美文网首页Android自定义View
实现View滑动的6种方式

实现View滑动的6种方式

作者: Doikki | 来源:发表于2018-05-04 20:31 被阅读32次
    • layout()方法
      View进行绘制的时候会调用onLayout()方法来设置现实的位置,因此我们同样也可以通过修改View的left、top、right、bottom这4个属性来控制View的坐标。首选我们需要自定义一个View,在onTouchEvent()方法中获取触摸点的坐标,接下来我们在ACTION_MOVE事件中计算偏移量,再调用layout()方法重新放置控件的位置即可,代码如下所示:
    public boolean onTouchEvent(MotionEvent event) {
        //获取手指触摸点的横坐标和纵坐标
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //计算移动的距离
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                //调用layout()方法来重新放置控件的位置
                layout(getLeft() + offsetX, getTop() + offsetY,
                        getRight() + offsetX, getBottom() + offsetY);
                break;
        }
        return true;
    }
    
    • offsetLeftAndRight()与offsetTopAndBottom()
      这种方法和上面的layout()方法差不多。我们将ACTION_MOVE中的代码替换成如下代码即可得到我们想要的效果。
    case MotionEvent.ACTION_MOVE:
        //计算移动的距离
        int offsetX = x - lastX;
        int offsetY = y - lastY;
        offsetLeftAndRight(offsetX);
        offsetTopAndBottom(offsetY);
        break;
    
    • LayoutParams(改变布局参数)
      LayoutParams主要保存了一个View的布局参数,因此我们可以通过LayoutParams来改变View的布局参数从而达到改变View位置的效果。同样,将ACTION_MOVE中的代码替换成如下代码:
    case MotionEvent.ACTION_MOVE:
        //计算移动的距离
        int offsetX = x - lastX;
        int offsetY = y - lastY;
        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
        layoutParams.leftMargin = getLeft() + offsetX;
        layoutParams.topMargin = getTop() + offsetY;
        setLayoutParams(layoutParams);
        break;
    

    因为父控件是LinearLayout,所以我们使用了LinearLayout.LayoutParams。如果父控件是RelativeLayout,则要使用RelativeLayout.LayoutParams。除了使用布局的LayoutParams外,我们还可以使用ViewGroup.MarginLayoutParams来实现:

    case MotionEvent.ACTION_MOVE:
        //计算移动的距离
        int offsetX = x - lastX;
        int offsetY = y - lastY;
        ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
        layoutParams.leftMargin = getLeft() + offsetX;
        layoutParams.topMargin = getTop() + offsetY;
        setLayoutParams(layoutParams);
        break;
    
    • 动画
      可以采用动画来移动,在res目录新建anim文件夹并创建anim_translate.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:fillAfter="true">
        <translate
            android:fromXDelta="0"
            android:toXDelta="300" />
    </set>
    

    接下来在Java代码中调用:

    mCustomView.setAnimation(AnimationUtils.loadAnimation(this, R.anim.anim_translate));
    

    运行程序,控件会向右平移300个像素,并停留在当前位置。
    需要注意的是View动画并不能改变View的位置参数。如果对控件设置一个点击事件,此时对控件执行如上操作,点击控件停留的位置并不会触发点击事件,但我们点击控件初始位置却触发了点击事件。对于系统来说这个控件并没有改变原有的位置,所以就出现上述问题。在Android3.0的时候推出的属性动画可以解决上述问题,它不仅执行了动画,还改变了控件的位置参数。代码如下:

    ObjectAnimator.ofFloat(mCustomView, "translationX", 0, 300).setDuration(1000).start();
    
    • scrollTo与scrollBy
      scrollTo(x,y)表示移动到一个具体的坐标点,而scrollBy(dx,dy)则表示移动的增量为dx,dy。其中,scrollBy最终也是要调用scrollTo的。scrollTo与scrollBy移动的是View的内容,如果在ViewGroup中使用,则是移动其所有的子View。我们将ACTION_MOVE中的代码替换成如下代码:
    case MotionEvent.ACTION_MOVE:
        //计算移动的距离
        int offsetX = x - lastX;
        int offsetY = y - lastY;
        ((View)getParent()).scrollBy(-offsetX, -offsetY);
        break;
    
    • Scroller
      我们在用scrollTo/scrollBy方法进行滑动时,这个过程是瞬间完成的,所以用户体验不太好,这里我们可以使用Scroller来实现过渡效果。Scroller本身是不能滑动的,它需要与View的computeScroll()方法配合才能实现弹性滑动效果。这里我们演示一下把控件向右移动400个像素,代码如下:
    public class CustomView extends View {
        public CustomView(Context context) {
            super(context);
        }
    
        public CustomView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            mScroller = new Scroller(context);
        }
    
        public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        private Scroller mScroller;
    
        @Override
        public void computeScroll() {
            super.computeScroll();
            if (mScroller.computeScrollOffset()) {
                ((View)getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
                invalidate();
            }
        }
    
        public void smoothScrollTo(int destX, int destY) {
            int scrollX = getScrollX();
            int delta = destX - scrollX;
            mScroller.startScroll(scrollX, 0, delta, 0, 2000);
            invalidate();
        }
    }
    

    最后我们在activity中调用smoothScrollTo()方法:

    mCustomView.smoothScrollTo(-400, 0);
    

    相关文章

      网友评论

        本文标题:实现View滑动的6种方式

        本文链接:https://www.haomeiwen.com/subject/jiqrrftx.html