android----ViewDragHelper的使用

使用ViewDragHelper 来处理移动的操作

1.ViewDragHelper 在高版本中v4 包才有

2.ViewDragHelper 主要用于ViewGroup中对子控件的拖拽处理

3.ViewDragHelper 主要封装了  View 的触摸位置,触摸速度和移动距离等的监控和scroller,

    通过接口回调的方式,告诉我们,只需要指定是否需要移动 ,移动多少 回调接口 

ViewDragHelper.Callback 
package com.yifei.myapplication;

import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;

public class MyDrawViewGroup extends FrameLayout {
    View redView;
    View blueView;
    private ViewDragHelper viewDragHelper;

    public MyDrawViewGroup(Context context) {
        super(context);
    }

    public MyDrawViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyDrawViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyDrawViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    private void initView() {
        viewDragHelper = ViewDragHelper.create(this, callback);//Param1 viewParent  Param2 回调函数
    }

    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        //用于判断,是否捕获当前child的触摸事件
        // child:当前的子View
        // return : true; 就获得并解析  false不处理
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == redView;
        }

        //当View 被开始获得和解析的回调Captured
        //capturedChild 当前获得的子View
        @Override
        public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
        }

        //获取View 水平方向的拖拽范围 不能限制边界
        //
        @Override
        public int getViewHorizontalDragRange(@NonNull View child) {
            return super.getViewHorizontalDragRange(child);
        }

        //获取View竖值方向的拖拽范围
        @Override
        public int getViewVerticalDragRange(@NonNull View child) {
            return super.getViewVerticalDragRange(child);
        }

        //控制child 在水平方向的滚动
        //left 表示ViewDragHelper 认为你想让当前child的left改变的值 left = child.getLeft+dx
        //dx 本次child在水平方向的距离
        //return 表示你真正想让child的left 变成的值
        @Override
        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
            return super.clampViewPositionHorizontal(child, left, dx);
        }

        //控制child在竖直方向的滚动
        //top 表示ViewDragHelper 认为你想让当前child的top改变的值 top = child.getTop+dy
        //return 表示你真正想让child的Top 变成的值
        @Override
        public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
            return super.clampViewPositionVertical(child, top, dy);
        }

        //当child的位置改变的时候执行 一般用于做其他子View的伴随移动
        //Params changedView ://位置改变的child
        //left  child 当前最新的left
        //top  child 当前最新的top
        //dx  本次水平移动的距离
        //dy  本次垂直移动的距离
        @Override
        public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
        }

        //手指抬起的方法 相当与 Motion.Action_Up
        //Params releasedChild 当前抬起的view
        //xvel x 方向移动的速度    正 为向右移动 负 为向左移动
        // yvel y 方向 移动的速度  正 为向下移动 负 为向 上移动
        @Override
        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
        }
    };

    //初始化子View的引用 当ViewGroup 的xml结束标签被读取完成,会执行该方法
    //此时会知道自己有几个子控件
    //onFinishInflate() 方法一般用来初始化子控件
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        redView = getChildAt(0);
        blueView = getChildAt(1);
    }

}

对滑动的范围进行限制

package com.yifei.myapplication;

import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
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;

public class MyDrawViewGroup extends FrameLayout {
    View redView;
    View blueView;
    private ViewDragHelper viewDragHelper;

    public MyDrawViewGroup(Context context) {
        super(context);
        initView();
    }

    public MyDrawViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public MyDrawViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyDrawViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();
    }

    private void initView() {
        viewDragHelper = ViewDragHelper.create(this, callback);//Param1 viewParent  Param2 回调函数
    }

    //
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (viewDragHelper.continueSettling(true)) { //判断子View 是否在移动
            ViewCompat.postInvalidateOnAnimation(this);//传递当前的位置
        }
    }

    //事件的分发
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    //事件的拦截
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return viewDragHelper.shouldInterceptTouchEvent(ev);//判断是否应该拦截 让ViewDragHelper 来处理
    }

    //事件的处理
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        viewDragHelper.processTouchEvent(event);//将事件交给ViewDragHelper 来处理
        return true;
    }

    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        //用于判断,是否捕获当前child的触摸事件
        // child:当前的子View
        // return : true; 就获得并解析  false不处理
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == redView;
        }

        //当View 被开始获得和解析的回调Captured
        //capturedChild 当前获得的子View
        @Override
        public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
        }

        //获取View 水平方向的拖拽范围 不能限制边界
        // 返回的值 目前用在手指抬起的时候的View缓慢移动的动画时间的计算
        //不要返回0
        @Override
        public int getViewHorizontalDragRange(@NonNull View child) {
            return getMeasuredWidth() - child.getMeasuredWidth(); //限制范围
        }

        //获取View竖值方向的拖拽范围
        // 返回的值 目前用在手指抬起的时候的View缓慢移动的动画时间的计算
        //不要返回0
        @Override
        public int getViewVerticalDragRange(@NonNull View child) {
            return getMeasuredHeight() - child.getMeasuredHeight();
        }

        //控制child 在水平方向的滚动
        //left 表示ViewDragHelper 认为你想让当前child的left改变的值 left = child.getLeft+dx
        //dx 本次child在水平方向的距离
        //return 表示你真正想让child的left 变成的值
        @Override
        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
            if(left<0){
                left =0;
            }else  if(left>(getMeasuredWidth() - child.getMeasuredWidth())){
                left = getMeasuredWidth() - child.getMeasuredWidth();
            }
            return left;
        }

        //控制child在竖直方向的滚动
        //top 表示ViewDragHelper 认为你想让当前child的top改变的值 top = child.getTop+dy
        //return 表示你真正想让child的Top 变成的值
        @Override
        public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
            if(top<0){
                top = 0;

            }else if(top>(getMeasuredHeight() - child.getMeasuredHeight())){
                top=getMeasuredHeight() - child.getMeasuredHeight();
            }
            return top;
        }

        //当child的位置改变的时候执行 一般用于做其他子View的伴随移动
        //Params changedView ://位置改变的child
        //left  child 当前最新的left
        //top  child 当前最新的top
        //dx  本次水平移动的距离
        //dy  本次垂直移动的距离
        @Override
        public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
        }

        //手指抬起的方法 相当与 Motion.Action_Up
        //Params releasedChild 当前抬起的view
        //xvel x 方向移动的速度    正 为向右移动 负 为向左移动
        // yvel y 方向 移动的速度  正 为向下移动 负 为向 上移动
        @Override
        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
        }
    };

    //初始化子View的引用 当ViewGroup 的xml结束标签被读取完成,会执行该方法
    //此时会知道自己有几个子控件
    //onFinishInflate() 方法一般用来初始化子控件
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        redView = getChildAt(0);
        blueView = getChildAt(1);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//没有特殊要求 可以这样做
        measureChild(redView,widthMeasureSpec,heightMeasureSpec);
        measureChild(blueView,widthMeasureSpec,heightMeasureSpec); //另外一种测量方式
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int left =getPaddingLeft()+getWidth()/2-redView.getMeasuredWidth()/2;
        int top =0+redView.getPaddingTop();
        redView.layout(left, top, left+redView.getMeasuredWidth(),top+ redView.getMeasuredHeight());//把红色的View摆放上去
        blueView.layout(left, redView.getBottom(), left+redView.getMeasuredWidth(), redView.getBottom() +redView.getHeight());
    }

}

让蓝色的控件也可以移动

 @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == redView||child ==blueView;
        }

通过layout方法让红色view移动时,蓝色View 也一起移动

 //当child的位置改变的时候执行 一般用于做其他子View的伴随移动
        //Params changedView ://位置改变的child
        //left  child 当前最新的left
        //top  child 当前最新的top
        //dx  本次水平移动的距离
        //dy  本次垂直移动的距离
        @Override
        public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            if (changedView == redView) {//单红色view移动时,让蓝色View 也移动
                blueView.layout(left, top + blueView.getMeasuredHeight(), left + blueView.getMeasuredWidth(), top + blueView.getMeasuredHeight() * 2);

            }
        }

当蓝色View移动时,让红色View 一起移动


        //当child的位置改变的时候执行 一般用于做其他子View的伴随移动
        //Params changedView ://位置改变的child
        //left  child 当前最新的left
        //top  child 当前最新的top
        //dx  本次水平移动的距离
        //dy  本次垂直移动的距离
        @Override
        public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            if (changedView == redView) {//单红色view移动时,让蓝色View 也移动
                blueView.layout(left, top + blueView.getMeasuredHeight(), left + blueView.getMeasuredWidth(), top + blueView.getMeasuredHeight() * 2);

            }else if(changedView==blueView){
                redView.layout(left,top-redView.getHeight(),left+blueView.getMeasuredWidth(),top);
            }
        }

当手指抬起时候,view如果靠近左边,  就向左边滑动

//手指抬起的方法 相当与 Motion.Action_Up
        //Params releasedChild 当前抬起的view
        //xvel x 方向移动的速度    正 为向右移动 负 为向左移动
        // yvel y 方向 移动的速度  正 为向下移动 负 为向 上移动
        @Override
        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            int centerleft = getMeasuredWidth()/2 -redView.getWidth()/2;//得到中间线的距离
            if(centerleft>releasedChild.getLeft()){
                //在左边滑动,应该向左缓慢滑动
                viewDragHelper.smoothSlideViewTo(releasedChild,0,0);//缓慢滑到左边
                ViewCompat.postInvalidateOnAnimation(MyDrawViewGroup.this); //调用方法,滑到左边
            }else if(centerleft

引入jar包

implementation 'com.nineoldandroids:library:2.4.0'

一个缩放动画

 private void executeAnim(float fraction) {
            //执行一个伴随动画 动画效果 
            ViewHelper.setScaleX(redView,(float) (1+0.5*fraction));//一个缩放动画
            ViewHelper.setScaleY(redView,(float) (1+0.5*fraction));
        }

 

你可能感兴趣的:(android)