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
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/17463237.html
Android拖拽助手ViewDragHelper
在项目中,我们经常自定义ViewGroup,有时候需要拖拽它的子View,让其运动,一般情况下如果我们手动处理各种滑动事件,非常麻烦,谷歌给我们提供了一个辅助类ViewDragHelper
,ViewDragHelper
给我们提供了很多拖拽相关的方法以及状态跟踪。
创建实例
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)
- tryCaptureView返回一个boolean,用户判断是否捕获当前view的触摸事件
- getViewHorizontalDragRange获取child水平方向的拖拽范围
- clampViewPositionHorizontal控制child在水平方向的移动,我们可以通过dx修正left的值,返回值表示我们真正想让child的left变成的值
- clampViewPositionVertical和水平方向类似
- onViewPositionChanged 当child位置改变时候的回调
- onViewReleased当拖拽的view释放的时候回调
使用
自定义一个简单的侧拉菜单,该菜单有两个子View,一个主界面,一个侧边菜单界面
首先自定义一个ViewGroup并初始化ViewDragHelper
public class SlideMenu extends FrameLayout
private void init()
viewDragHelper = ViewDragHelper.create(this, callback);
然后重写onInterceptTouchEvent
和onTouchEvent
,将这两个方法的处理逻辑交给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
方法,所以close
和open
方法就很简单
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使用讲解的主要内容,如果未能解决你的问题,请参考以下文章
滑动 ViewDragHelper DrawerLayout