实现拖动控制神器 ViewDragHelper 的简单学习

上一篇学习了 android里可以进行scroll 的 4 个方法,还有一个重要的 ViewDragHelper ,在这里重点学习一下。

首先我们先把这个ViewDragHelper 的框架先搭建起来,让它里的View 可以随意拖动。


首先自定义一个View 继承 ViewGroup ,先来一个完成代码,后面学习细节

package mw.huawei.com.viewdraghelper.MyView;

import android.content.Context;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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.LinearLayout;

/**
 * Created by Administrator on 2018/5/6.
 */

public class ViewDragHelperView extends LinearLayout {


    private View mDragView;         //随意拖动View
    private View mAutoBackView ;    // 拖动释放后返回原位置
    private View mEdgeTrackerView ; // 从边缘触发拖动

    private ViewDragHelper mViewDragHelper;

    private int mAutoBackViewX;
    private int mAutoBackViewY;

    public ViewDragHelperView(@NonNull Context context) {
        this(context,null);
    }

    public ViewDragHelperView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ViewDragHelperView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }
    // STEP 1:初始 mViewDragHelper
    private void initView(){
        mViewDragHelper = ViewDragHelper.create(this,1.0f,callback);
        mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); // 左边缘拖动 调用 onEdgeDragStarted 里传入的View
    }

    // SETP 2:拿到回调参数callBack
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        @Override  //哪一个View可以被拖动
        public boolean tryCaptureView(View child, int pointerId) {
            // mEdgeTrackerView 从边缘触发,禁止拖动
            return mDragView == child || mAutoBackView == child;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            int rangeX = getWidth() - child.getWidth();
            if (left <= 0){
                return 0;
            }else if (left > rangeX){
                return rangeX;
            }else{
                return left;
            }
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            int rangeY = getHeight() - child.getHeight();
            if (top<=0){
                return 0;
            }else if (top > rangeY){
                return rangeY;
            }else{
                return top;
            }
        }

        //手指释放的时候回调
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            if(releasedChild == mAutoBackView){
                mViewDragHelper.settleCapturedViewAt(mAutoBackViewX,mAutoBackViewY);//传入原始的位置左边,让mAutoBackView返回原位置
            }
            invalidate();// 如果没有执行完毕, 就执行computeScroll,继续计算
        }

        //在边界拖动时回调
        @Override
        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
            mViewDragHelper.captureChildView(mEdgeTrackerView, pointerId);
        }
    };

    //STEP 3:将View 的触摸 和 事件拦截都扔给 mViewDragHelper
    @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);
        }
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mDragView=getChildAt(0);
        mAutoBackView=getChildAt(1);
        mEdgeTrackerView=getChildAt(2);
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        mAutoBackViewX =  mAutoBackView.getLeft();
        mAutoBackViewY =  mAutoBackView.getTop();
    }
}

现在分为三步实现这个ViewDragHelper

// STEP 1:初始 mViewDragHelper

// STEP 1:初始 mViewDragHelper
    private void initView(){
        mViewDragHelper = ViewDragHelper.create(this,1.0f,callback);
        mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); // 左边缘拖动 调用 onEdgeDragStarted 里传入的View
    }
 // SETP 2:拿到回调参数callBack
// SETP 2:拿到回调参数callBack
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        @Override  //哪一个View可以被拖动
        public boolean tryCaptureView(View child, int pointerId) {
            // mEdgeTrackerView 从边缘触发,禁止拖动
            return mDragView == child || mAutoBackView == child;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            int rangeX = getWidth() - child.getWidth();
            if (left <= 0){
                return 0;
            }else if (left > rangeX){
                return rangeX;
            }else{
                return left;
            }
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            int rangeY = getHeight() - child.getHeight();
            if (top<=0){
                return 0;
            }else if (top > rangeY){
                return rangeY;
            }else{
                return top;
            }
        }

        //手指释放的时候回调
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            if(releasedChild == mAutoBackView){
                mViewDragHelper.settleCapturedViewAt(mAutoBackViewX,mAutoBackViewY);//传入原始的位置左边,让mAutoBackView返回原位置
            }
            invalidate();// 如果没有执行完毕, 就执行computeScroll,继续计算
        }

        //在边界拖动时回调
        @Override
        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
            mViewDragHelper.captureChildView(mEdgeTrackerView, pointerId);
        }
    };
//STEP 3:将View 的触摸 和 事件拦截都扔给 mViewDragHelper
//STEP 3:将View 的触摸 和 事件拦截都扔给 mViewDragHelper
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
       return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

到这里就可以实现示例图中第一个方块的拖动效果啦。

下来在进阶一下下,实现第二个小方块的操作

拖动一个View  然后返回某一个坐标位置,需要重写如下方法,就只能简单的拖动了

@Override
public void computeScroll() {
   //固定写法
   //此方法用于自动滚动,比如自动回滚到默认位置.
   if (mViewDragHelper.continueSettling(true)) {
        ViewCompat.postInvalidateOnAnimation(this);
   }
}

这个方法主要用来处理View进行平滑滑动。

并且需要重写onViewReleased()实现当手指松开的时候回到原位置的操作    

//手指释放的时候回调
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
	if(releasedChild == mAutoBackView){
		mViewDragHelper.settleCapturedViewAt(mAutoBackViewX,mAutoBackViewY);//传入原始的位置左边,让mAutoBackView返回原位置
	}
	invalidate();// 如果没有执行完毕, 就执行computeScroll,继续计算
}

当然这里传入的两个参数是在 自定义View Layout时候进行坐标的获取。

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
	super.onLayout(changed, l, t, r, b);
	mAutoBackViewX =  mAutoBackView.getLeft();
	mAutoBackViewY =  mAutoBackView.getTop();
}

然后实现边缘控制:如图中的第三个小方块,只能在左侧拖动进行控制。

主要实现callback 中 onEdgeDragStarted() 的操作

//在边界拖动时回调
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
	mViewDragHelper.captureChildView(mEdgeTrackerView, pointerId);
}

传入的View就是我们实现的左侧边缘拖动控制的View

同时还需要在 mViewDragHelper 初始化的时候设置

mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);

以实现左侧边缘控制。


activity_main.xml 如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="mw.huawei.com.viewdraghelper.MainActivity">

    <mw.huawei.com.viewdraghelper.MyView.ViewDragHelperView
        android:orientation="vertical"
        android:layout_height="match_parent"
        android:layout_width="match_parent">

        <TextView
            android:layout_margin="10dp"
            android:gravity="center"
            android:layout_gravity="center"
            android:background="#88ff0000"
            android:text="I can be dragged !"
            android:layout_width="100dp"
            android:layout_height="100dp"/>

        <TextView
            android:layout_margin="10dp"
            android:layout_gravity="center"
            android:gravity="center"
            android:background="#8800ff00"
            android:text="I will bakc to original loc !"
            android:layout_width="100dp"
            android:layout_height="100dp"/>

        <TextView
            android:layout_margin="10dp"
            android:layout_gravity="center"
            android:gravity="center"
            android:background="#880000ff"
            android:text=" edage to ctrl me"
            android:layout_width="100dp"
            android:layout_height="100dp"/>
    </mw.huawei.com.viewdraghelper.MyView.ViewDragHelperView>
</RelativeLayout>

最后奉上我们的成果:



本文参考代码



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值