View滑動動畫的選擇及其left, marginLeft, translationX參數的總結

最近由於項目需要,做一個比較複雜的3D動畫,核心就是根據手指的滑動來翻轉3D效果。因此,又回顧了一下view滑動效果,而且根據不同的方式實現了一下,發現其中很多參數容易搞混,比如改變view的left,marginLeft,translationX中的任意一個值,對另外2個值及其getX是否有影響,因此,做了一下實驗,發現挺有意思,結果如下:


這裏寫圖片描述

注:第三行,是設置了android:layout_centerInParent=”true”的結果,因此圖片也滑動不了了。如果去掉此設置,getLeft是隨着leftMargin而改變的!

從上面的數據來看,這幾個view的參數之間的值相互之間不影響。同理right, marginRight, translationX和top, marginTop, translationY以及bottom, marginBottom, translationY都能得到相同的答案。

另外一點很重要,就是無論如何變化,始終有如下關係:
view.getX() = view.getLeft() + view.getTranslationX();
這個其實根據View.getX()的代碼也能證明:

/**
     * The visual x position of this view, in pixels. This is equivalent to the
     * {@link #setTranslationX(float) translationX} property plus the current
     * {@link #getLeft() left} property.
     *
     * @return The visual x position of this view, in pixels.
     */
    @ViewDebug.ExportedProperty(category = "drawing")
    public float getX() {
        return mLeft + getTranslationX();
    }

其次,在處理滑動的過程中,很容易弄混亂的一點就是view和MotionEvent event都有getX(), getY()方法, 它們的區別是:

  1. event的getX(), getY()是觸摸點相對於監聽此觸摸事件的view的左邊,頂部x, y方向距離,而view的getX(),getY()是view的左邊,頂部相對於其父控件的距離。
  2. 一般來講,利用event的getX(),getY()來作爲主動變化的因素,判斷滑動的方向,距離。然後根據方向,距離來動態改變view的各種參數(如left, marginLeft, translationX)來使得view產生動畫效果。

還有一點需要總結的是:

  1. view的getTop(), getLeft(), getRight(), getBottom(), getX(), getY()都是相對於其父佈局的值。
  2. MotionEvent的getX(),getY()是當前觸摸點相對於設置此監聽觸摸事件的view的左邊和頂部的距離。
  3. 只有MotionEvent的getRawX(),getRawY()是絕對座標。

另外,對於view的動畫視覺效果,大體上分爲以下幾種:

  1. 改變left, right, top, bottom參數,然後layout(l, t, r, b)
  2. 改變layoutParams參數,然後requestLayout()或者setLayoutParams(params)
  3. 利用View的scrollTo(x, y), scrollBy(x, y)
  4. 利用Scroller類,重寫computeScroll()方法
  5. View動畫
  6. 屬性動畫
  7. ViewDragHelper類

其中1的例子如下:

@Override
    public boolean onTouch(View view, MotionEvent event) {

        float  dx, dy;

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startTouchX = event.getX();
                startTouchY = event.getY();

                circleImageLeft = circleImage.getLeft();
                circleImageRight = circleImage.getRight();
                break;

            case MotionEvent.ACTION_MOVE:
                dx = event.getX() - startTouchX;
                dy = event.getY() - startTouchY;
/* 
  注意:
  1. 這裏不要用 (circleImage.getLeft() + dx),因爲每次layout之後已經改變了left的值,因此getLeft是已經更新後的值,這樣將會導致dx全部累計,滑動使得view滑動的更快。 
  2. 一定要記得right也要跟着變,否則right不變的話,view將會被壓縮或者拉伸。
*/
                circleImage.layout((int) (circleImageLeft + dx),
                        circleImage.getTop(),
                        (int) (circleImageRight + dx),
                        circleImage.getBottom());
                break;
            case MotionEvent.ACTION_UP:
                AppLog.e("ACTION_UP");
                break;
            case MotionEvent.ACTION_CANCEL:
                AppLog.e("ACTION_CANCEL");
                break;
        }

        return true;
    }

第2種方法:
1. 如果設置了view的屬性 android:layout_centerInParent=”true”的話,圖片就滑動不了了
2. 如果滑動view到達邊界處,會出現縮小view而滑不出邊界的現象。

而第1種方法則不會出現這2個問題,所以個人比較推薦第1種方法來滑動。

第3種方法,它只能滑動view的內容,view本身不動,並且是瞬間移動。

第4種方法與第3種類似,只是它能夠設置時間緩慢進行。

第5,6種方法,動畫都是需要start,如果需要根據手指滑動來跟着變化就不適合動畫方法。

第7種,適合自定義viewGroup類型的控件來實現它裏面控件的動畫效果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章