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类型的控件来实现它里面控件的动画效果。

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