Android开发 ViewDragHelper使用讲解

Posted 观心静

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android开发 ViewDragHelper使用讲解相关的知识,希望对你有一定的参考价值。

 

前言

  ViewDragHelper需要自定义ViewGroup实现,并且只是针对ViewGroup里的子View进行拖放,在拖放的过程中不能携带数据。也不能跨进程,甚至不能跨activity。所以ViewDragHelper本质上更像是一个ViewGroup里简单实现拖放效果的帮助类。

 

一个简单拖动的例子

  快速了解一下,有个概念

效果图

代码

自定义ViewGroup布局


class MyViewDragConstraintLayout(context: Context, attrs: AttributeSet?) : ConstraintLayout(context, attrs) 
    private lateinit var mViewDragHelper: ViewDragHelper

    init 
        /**
         * 第一个参数是实现拖动的ViewGroup父类布局,第二个参数是拖动时的灵敏度,拖动开始的敏感程度的乘数。值越大越敏感。1.0f是正常的。
         */
        mViewDragHelper = ViewDragHelper.create(this, 1.0f, object : ViewDragHelper.Callback() 
            /**
             * 是否允许view的拖动功能,返回true是允许拖动,返回false是不允许拖动
             */
            override fun tryCaptureView(child: View, pointerId: Int): Boolean 
                return true
            

            /**
             * 控制垂直方向的拖动位移,如果不重写此方法默认是不允许垂直运动的,按照下面重写方法后可以允许垂直方向的拖动
             */
            override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int 
                return top
            

            /**
             * 控制横向方向的拖动位移,如果不重写此方法默认是不允许横向运动的,按照下面重写方法后可以允许横向方向的拖动
             */
            override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int 
                return left
            
        )
    

    /**
     * 注意,你需要重写onInterceptTouchEvent方法并且将触摸拦截交予ViewDragHelper的shouldInterceptTouchEvent,使其可以重新分配触控事件
     */
    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean 
        return mViewDragHelper.shouldInterceptTouchEvent(ev)
    

    /**
     * 注意,你需要重写onTouchEvent,并且将mViewDragHelper的processTouchEvent实现,使其可以实现拖动子view的效果
     */
    override fun onTouchEvent(event: MotionEvent): Boolean 
        mViewDragHelper.processTouchEvent(event)
        return true
    

xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    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_
    android:layout_
    tools:context=".MainActivity">

    <com.lwlx.mydragtestapp.MyViewDragConstraintLayout
        android:layout_
        android:layout_
        android:orientation="vertical">

        <ImageView
            android:id="@+id/icon1"
            android:layout_
            android:layout_
            android:src="@mipmap/ic_launcher"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>

    </com.lwlx.mydragtestapp.MyViewDragConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

end

Android拖拽助手ViewDragHelper

在项目中,我们经常自定义ViewGroup,有时候需要拖拽它的子View,让其运动,一般情况下如果我们手动处理各种滑动事件,非常麻烦,谷歌给我们提供了一个辅助类ViewDragHelperViewDragHelper给我们提供了很多拖拽相关的方法以及状态跟踪。

创建实例

ViewDragHelper.create(vp, callback);

ViewDragHelper的创建比较简单,它的构造函数是私有的,只能通过create()方法创建,第一个参数是一个ViewGroup,也就是需要使用ViewDragHelper的自定义View,第二个参数callback,提供了很多拖拽相关的回调。

ViewDragHelper.Callback

下面是几个常用的方法

private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() 
   public boolean tryCaptureView(View child, int pointerId)
   public int getViewHorizontalDragRange(View child)
   public int clampViewPositionHorizontal(View child, int left, int dx)
   public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) 
   public void onViewReleased(View releasedChild, float xvel, float yvel) 

  1. tryCaptureView返回一个boolean,用户判断是否捕获当前view的触摸事件
  2. getViewHorizontalDragRange获取child水平方向的拖拽范围
  3. clampViewPositionHorizontal控制child在水平方向的移动,我们可以通过dx修正left的值,返回值表示我们真正想让child的left变成的值
  4. clampViewPositionVertical和水平方向类似
  5. onViewPositionChanged 当child位置改变时候的回调
  6. onViewReleased当拖拽的view释放的时候回调

使用

自定义一个简单的侧拉菜单,该菜单有两个子View,一个主界面,一个侧边菜单界面

首先自定义一个ViewGroup并初始化ViewDragHelper

public class SlideMenu extends FrameLayout
    private void init()
       viewDragHelper = ViewDragHelper.create(this, callback);
    


然后重写onInterceptTouchEventonTouchEvent,将这两个方法的处理逻辑交给ViewDragHelper

public boolean onInterceptTouchEvent(MotionEvent ev) 
   return viewDragHelper.shouldInterceptTouchEvent(ev);

public boolean onTouchEvent(MotionEvent event) 
   viewDragHelper.processTouchEvent(event);
   return true;


实现ViewDragHelper.Callback,重写tryCaptureView,在当前Layout中两个子VIew都需要滑动,所以直接返回true.

public boolean tryCaptureView(View child, int pointerId) 
   return true;


先限制一下横向滑动范围,给一个最大值

public int getViewHorizontalDragRange(View child) 
   return (int) dragRange;


主界面在滑动过程中,我们需要控制下它在水平方向的移动距离

public int clampViewPositionHorizontal(View child, int left, int dx) 
   if(child==mainView)
      if(left<0)left=0;//限制mainView的左边
      if(left>dragRange)left=(int) dragRange;//限制mainView的右边
   
   return left;


在滑动过程中,根据拖拽回调重新对侧拉菜单和主界面布局,不断刷新他们的位置信息,这里简单起见,让侧拉菜单固定,只是主界面滑动。

public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) 
   if(changedView==menuView)
      menuView.layout(0, 0, menuView.getMeasuredWidth(),menuView.getMeasuredHeight());
      int newLeft = mainView.getLeft()+dx;
      if(newLeft<0)newLeft=0;
      if(newLeft>dragRange)newLeft=(int) dragRange;mainView.layout(newLeft,mainView.getTop()+dy,newLeft+mainView.getMeasuredWidth(),mainView.getBottom()+dy);
   


当手指抬起释放view的时候,可能我们只是拖拽了一点,这时候我们需要根据当前拖拽的信息决定是打开菜单还是关闭菜单。

public void onViewReleased(View releasedChild, float xvel, float yvel) 
   if(mainView.getLeft()<dragRange/2)
      //在左半边
      close();
   else 
      //在右半边
      open();
   


对于view的滑动ViewDragHelper也提供了smoothSlideViewTo方法,所以closeopen方法就很简单

public void close() 
   viewDragHelper.smoothSlideViewTo(mainView,0,mainView.getTop());
   ViewCompat.postInvalidateOnAnimation(SlideMenu.this);

public void computeScroll() 
   if(viewDragHelper.continueSettling(true))
      ViewCompat.postInvalidateOnAnimation(SlideMenu.this);
   


然后还可以提供一些拖拽状态回调,比如拖拽完成,拖拽中等状态,这些比较简单,直接在onViewPositionChanged中处理就可以了。

最后看一下效果

以上是关于Android开发 ViewDragHelper使用讲解的主要内容,如果未能解决你的问题,请参考以下文章

Android拖拽助手ViewDragHelper

Android使用ViewDragHelper实现侧滑菜单

Android拖拽助手ViewDragHelper

滑动 ViewDragHelper DrawerLayout

Android 中 View移动总结:ViewDragHelper学习及用法详解

Android 中 View移动总结:ViewDragHelper学习及用法详解