Android 实现View滑动几种方式
关于View的滑动,Android中提供了许多方法,具体可以分为一下几类:
layout
在ACTION_MOVE中通过获取x、y的偏移量动态布局view,并禁止向父控件传递事件:
@Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                layout(
                        getLeft() + offsetX,
                        getTop() + offsetY,
                        getRight() + offsetX,
                        getBottom() + offsetY
                );
                break;
        }
        return true;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
offsetLeftAndRight和offsetTopAndBottom
将上述layout方法改为该两个方法的组合,偏移量计算同上:
 case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
                break;
    1
    2
    3
    4
    5
    6
    7
LayoutParams
实现方法和layout相似,动态设置布局参数,缺点是如果view参数加了rules,会导致无法滑动:
    case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                ViewGroup.MarginLayoutParams params
                        = (ViewGroup.MarginLayoutParams) getLayoutParams();
                params.leftMargin = getLeft() + offsetX;
                params.topMargin = getTop() + offsetY;
                setLayoutParams(params);
                break;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
ScrollBy
scrollBy移动的是view中的内容或者ViewGroup中的所有子view,故需先获得父控件的实例;同时scrollBy参数的正负是和android坐标轴的正负方向相反的,故需队offset值取反:
 case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                ((View) getParent()).scrollBy(-offsetX, -offsetY);
                break;
    1
    2
    3
    4
    5
    6
ViewDragHelper
该类非常强大,基本可以各种不同的滑动、拖放需求。support库中DragLayout也是基于此类实现侧滑效果。使用该类一般需要如下几个步骤:
    继承自ViewGroup,在构造中初始化ViewDragHelper对象,传入的两个参数分别为当前容器对象和ViewDragHelper中的回调接口,该回调中封装了子view的滑动操作相关api
    public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mViewDragHelper = ViewDragHelper.create(this, mCallBack);
    }
    1
    2
    3
    4
    触摸事件拦截与处理,需要将事件传递给ViewDragHelper处理
 @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    处理ViewDragHelper中回调Callback
private ViewDragHelper.Callback mCallBack = new ViewDragHelper.Callback() {
        /**
         * 指定可以滑动的子View,比如当前只有mMainView可以滑动
         * @param child
         * @param pointerId
         * @return true 指定的子view可以滑动
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == mMainView;
        }
        /**
         * 控制子view水平滑动的距离,默认是0 不可以滑动
         * @param child
         * @param left
         * @param dx
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }
        /**
         * 功能同上,垂直方向滑动的距离
         * @param child
         * @param top
         * @param dy
         * @return
         */
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return top;
        }
        /**
         * 当拖拽子view之后手指离开屏幕时触发;
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
        }
    };
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
以上代码即可实现view滑动的功能。但如果想要实现手指离开屏幕view自动滑动到指定位置的功能时,需要在Callback中重写onViewReleased()方法。ViewDragHelper提供了smoothSlideViewTo() 方法,可以实现view的自动滑动效果,当然其内部也是通过Scroller类实现的,故需要重写computeScroll() 方法。
如下是一个模拟google DragLayout的一个Demo,当然只实现了其中侧滑的一个小功能,其他事件分发处理逻辑都没有具体实现。
package com.ts.test.widget;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
/**
 * Created by tiansen on 17-11-18.
 */
public class MyDragLayout extends FrameLayout {
    private static final String TAG = "MyDragLayout";
    private ViewDragHelper mViewDragHelper;
    /**
     * 侧边栏View
     */
    private View mMenuView;
    /**
     * 主View
     */
    private View mMainView;
    /**
     * 侧边栏View宽度
     */
    private int mMenuWidth;
    /**
     * 主View宽度
     */
    private int mMainWidth;
    private ViewDragHelper.Callback mCallBack = new ViewDragHelper.Callback() {
        /**
         * 指定可以滑动的子View
         * @param child
         * @param pointerId
         * @return true 指定的子view可以滑动
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == mMainView;
        }
        /**
         * 控制子view水平滑动的距离,默认是0 不可以滑动
         * @param child
         * @param left
         * @param dx
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            // 控制滑动边界
            return (left < 0 ? 0 : left) < mMenuWidth ? left : mMenuWidth;
        }
        /**
         * 功能同上,垂直方向滑动的距离
         * @param child
         * @param top
         * @param dy
         * @return
         */
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return 0;
        }
        /**
         * 当拖拽子view之后手指离开屏幕时触发;
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            if (mMainView.getLeft() < mMenuWidth / 2) {
                mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                ViewCompat.postInvalidateOnAnimation(MyDragLayout.this);
            } else {
                mViewDragHelper.smoothSlideViewTo(mMainView, mMenuWidth, 0);
                ViewCompat.postInvalidateOnAnimation(MyDragLayout.this);
            }
        }
    };
    public MyDragLayout(Context context) {
        this(context, null);
    }
    public MyDragLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public MyDragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mViewDragHelper = ViewDragHelper.create(this, mCallBack);
    }
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mMenuView = getChildAt(0);
        mMainView = getChildAt(1);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mMainWidth = mMainView.getMeasuredWidth();
        mMenuWidth = mMenuView.getMeasuredWidth();
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true;
    }
    @Override
    public void computeScroll() {
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
}
--------------------- 
作者:TianSen-dev 
来源:CSDN 
原文:https://blog.csdn.net/qq_35705558/article/details/78509763 
版权声明:本文为博主原创文章,转载请附上博文链接!
                    
                
                
            
        
浙公网安备 33010602011771号