前言
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_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.lwlx.mydragtestapp.MyViewDragConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/icon1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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>
限制拖拽方向的例子
下面的代码,我们假设需要限制拖拽的方向只能向下,其他方向都不行。
效果图
代码
class MyViewDragConstraintLayout(context: Context, attrs: AttributeSet?) : ConstraintLayout(context, attrs) {
private lateinit var mViewDragHelper: ViewDragHelper
private var mDefaultY = 0
init {
mViewDragHelper = ViewDragHelper.create(this, 1.0f, object : ViewDragHelper.Callback() {
override fun tryCaptureView(child: View, pointerId: Int): Boolean {
mDefaultY = child.top
return true
}
/**
* 控制垂直方向的拖动位移,如果不重写此方法默认是不允许垂直运动的,按照下面重写方法后可以允许垂直方向的拖动
*/
override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
Log.e("zh", "top = ${top}")
//不允许top小于mDefaultY,这样就限制了Y轴的值不能变小
if (mDefaultY > top){
return mDefaultY
}
return top
}
})
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
return mViewDragHelper.shouldInterceptTouchEvent(ev)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
mViewDragHelper.processTouchEvent(event)
return true
}
}
拖拽回弹效果
效果图
代码
class MyViewDragConstraintLayout(context: Context, attrs: AttributeSet?) :
ConstraintLayout(context, attrs) {
private lateinit var mViewDragHelper: ViewDragHelper
private var mDefaultY = 0
private var mDefaultX = 0
private lateinit var mIconView: ImageView
init {
mViewDragHelper = ViewDragHelper.create(this, 1.0f, object : ViewDragHelper.Callback() {
override fun tryCaptureView(child: View, pointerId: Int): Boolean {
return child == mIconView
}
override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
return top
}
override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {
return left
}
override fun onViewPositionChanged(changedView: View, left: Int, top: Int, dx: Int, dy: Int) {
super.onViewPositionChanged(changedView, left, top, dx, dy)
}
/**
* 当子视图不再被主动拖动时调用。
* releasedChild – 捕获的子视图现在被释放
* xvel – 指针离开屏幕时的X速度,单位为像素每秒。
* yvel – 指针离开屏幕时的Y速度,单位为像素/秒。
*/
override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
if (mIconView == releasedChild) {
//回弹默认位置
val result = mViewDragHelper.settleCapturedViewAt(mDefaultX, mDefaultY)
invalidate()
} else {
super.onViewReleased(releasedChild, xvel, yvel)
}
}
})
}
/**
* 注意这个重写的computeScroll与设置的continueSettling是关键,如果不重写此方法,settleCapturedViewAt方法就没有效果
*/
override fun computeScroll() {
super.computeScroll()
if (mViewDragHelper.continueSettling(true)) {
invalidate()
}
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
return mViewDragHelper.shouldInterceptTouchEvent(ev)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
mViewDragHelper.processTouchEvent(event)
return true
}
override fun onFinishInflate() {
super.onFinishInflate()
mIconView = findViewById(R.id.icon1)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
mDefaultX = mIconView.left
mDefaultY = mIconView.top
}
}
边缘拖拽监听
代码
class MyViewDragConstraintLayout(context: Context, attrs: AttributeSet?) :
ConstraintLayout(context, attrs) {
private lateinit var mViewDragHelper: ViewDragHelper
private lateinit var mIconView: ImageView
init {
mViewDragHelper = ViewDragHelper.create(this, 1.0f, object : ViewDragHelper.Callback() {
override fun tryCaptureView(child: View, pointerId: Int): Boolean {
return child == mIconView
}
override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
return top
}
override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {
return left
}
override fun onEdgeDragStarted(edgeFlags: Int, pointerId: Int) {
super.onEdgeDragStarted(edgeFlags, pointerId)
Log.e("zh", "onEdgeDragStarted: ${edgeFlags}", )
when(edgeFlags){
ViewDragHelper.EDGE_LEFT->{
Toast.makeText(context, "已经移动到最左边了 指针id${pointerId}", Toast.LENGTH_SHORT).show()
}
ViewDragHelper.EDGE_RIGHT->{
Toast.makeText(context, "已经移动到最右边了 指针id${pointerId}", Toast.LENGTH_SHORT).show()
}
ViewDragHelper.EDGE_TOP->{
Toast.makeText(context, "已经移动到最上边了", Toast.LENGTH_SHORT).show()
}
ViewDragHelper.EDGE_BOTTOM->{
Toast.makeText(context, "已经移动到最下边了", Toast.LENGTH_SHORT).show()
}
}
mViewDragHelper.captureChildView(mIconView, pointerId)
}
})
//设置需要监听的四个方向的编译,只能设置一个方向,并且在上面的onEdgeDragStarted里回调触发
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT)
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
return mViewDragHelper.shouldInterceptTouchEvent(ev)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
mViewDragHelper.processTouchEvent(event)
return true
}
}
end
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/17463237.html
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。