使用ViewDragHelper实现拖拽<二>的布局拖拽效果。
官方在v4的支持包中提供了ViewDragHelper
这样一个类来帮助我们方便的编写自定义ViewGroup。
ViewDragHelper.Callback是连接ViewDragHelper与view之间的桥梁;
ViewDragHelper的实例是通过静态工厂方法创建的;
ViewDragHelper可以检测到是否触及到边缘;
ViewDragHelper并不是直接作用于要被拖动的View,而是使其控制的视图容器中的子View可以被拖动,如果要指定某个子view的行为,需要在Callback中实现;
ViewDragHelper的本质其实是分析onInterceptTouchEvent和onTouchEvent的MotionEvent参数,然后根据分析的结果去改变一个容器中被拖动子View的位置。
ViewDragHelper 提供了两个工厂方法来创建实例:
static ViewDragHelper create(ViewGroup forParent, float sensitivity, ViewDragHelper.Callback cb)
static ViewDragHelper create(ViewGroup forParent, ViewDragHelper.Callback cb)
参数:
ViewGroup:与ViewDragHelper相关联ViewGroup
sensitivity:拖拽灵敏系数
cb:ViewDragHelper.Callback的回调类型之一。
ViewDragHelper提供的全部回调方法:
int clampViewPositionHorizontal(View child, int left, int dx)
int clampViewPositionVertical(View child, int top, int dy)
int getOrderedChildIndex(int index)
int getViewHorizontalDragRange(View child)
int getViewVerticalDragRange(View child)
void onEdgeDragStarted(int edgeFlags, int pointerId)
boolean onEdgeLock(int edgeFlags)
void onEdgeTouched(int edgeFlags, int pointerId)
void onViewCaptured(View capturedChild, int activePointerId)
void onViewDragStateChanged(int state)
void onViewPositionChanged(View changedView, int left, int top, int dx, int dy)
void onViewReleased(View releasedChild, float xvel, float yvel)
abstract boolean tryCaptureView(View child, int pointerId)
ViewDragHelper 回调中能构成最简单能运行实例的方法:
// 决定了是否需要捕获这个 child,只有捕获了才能进行下面的拖拽行为
abstract boolean tryCaptureView(View child, int pointerId)
// 修整 child 水平方向上的坐标,left 指 child 要移动到的坐标,dx 相对上次的偏移量
int clampViewPositionHorizontal(View child, int left, int dx)
// 修整 child 垂直方向上的坐标,top 指 child 要移动到的坐标,dy 相对上次的偏移量
int clampViewPositionVertical(View child, int top, int dy)
// 手指释放时的回调
void onViewReleased(View releasedChild, float xvel, float yvel)
要用 ViewDragHelper 来处理拖拽这个流程,自然要把触摸相关的动作要委托给它了
这就涉及到了 ViewDrageHelper 两个方法:
/** 是否应该拦截 children 的触摸事件,
*只有拦截了 ViewDragHelper 才能进行后续的动作
*将它放在 ViewGroup 中的 onInterceptTouchEvent() 方法中就好了
**/
boolean shouldInterceptTouchEvent(MotionEvent ev)
/** 处理 ViewGroup 中传递过来的触摸事件序列
*在 ViewGroup 中的 onTouchEvent() 方法中处理
*/
void processTouchEvent(MotionEvent ev)
简单实现:
package com.hjk.shiny.androidcontrols;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
/**
* Created by Maibenben on 2018/2/2.
*/
public class DragViewHelper extends FrameLayout{
private ViewDragHelper mHelper;
public DragViewHelper(Context context) {
this(context,null);
}
public DragViewHelper(Context context, @Nullable AttributeSet attrs) {
this(context,attrs,0);
}
public DragViewHelper(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mHelper=ViewDragHelper.create(this, new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return top;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mHelper.processTouchEvent(event);
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mHelper.shouldInterceptTouchEvent(ev);
}
}
初步实现很简单,但真正精通还需要仔细研究研究才是。