@weidong
2017-07-19T03:37:54.000000Z
字数 4679
阅读 365
Android课程
https://juejin.im/entry/57c3e8ac165abd00666ae71e
https://github.com/LittleFriendsGroup/AndroidSdkSourceAnalysis/blob/master/article/ViewDragHelper%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90.md
ViewDragHelper作为官方推出的手势滑动辅助工具,极大的简化了我们对手势滑动的处理逻辑
public class DragLayout extends LinearLayout {
private ViewDragHelper mDragHelper;
public DragLayout(Context context, AttributeSet attrs) {
super(context, attrs);
//参数一:指的当前的ViewGroup,
//参数二:滑动检测的敏感度,越大越敏感
//参数三:用户的触摸过程中会回调相关方法
mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
// 对触摸view判断,如果需要当前触摸的子View进行拖拽移动就返回true,否则返回false
// 返回值为true就代表可以滑动 为false 则不能滑动
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
// 拖拽的子View在所属方向上移动的位置,child为拖拽的子View,
// left为child即将移动到的水平位置(x坐标)的值
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
//top为子view应该到达的y坐标
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return top;
}
});
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mDragHelper.shouldInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mDragHelper.processTouchEvent(event);
return true;
}
}
布局代码
<?xml version="1.0" encoding="utf-8"?>
<com.jf.weidong.DragLayout 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">
<LinearLayout
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorAccent" />
</com.jf.weidong.DragLayout>
关键代码
在ViewDragHelper.Callback 回调的tryCaptureView方法里面进行判断,如果只有类型为RelativeLayout的View才可以拖动
// 对触摸view判断,如果需要当前触摸的子View进行拖拽移动就返回true,否则返回false
// 返回值为true就代表可以滑动 为false 则不能滑动
@Override
public boolean tryCaptureView(View child, int pointerId) {
if(child instanceof RelativeLayout) {
return true;
}
return false;
}
XML 代码
<?xml version="1.0" encoding="utf-8"?>
<com.jf.weidong.DragLayout 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">
<LinearLayout
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorAccent" />
<RelativeLayout
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorPrimaryDark" />
</com.jf.weidong.DragLayout>
关键代码
在ViewDragHelper.Callback 回调的clampViewPositionHorizontal()、clampViewPositionVertical()方法里面进行判断,最大拖动范围为屏幕边界(View边界)
// 拖拽的子View在所属方向上移动的位置,child为拖拽的子View,
// left为child即将移动到的水平位置(x坐标)的值
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
final int leftBound = getPaddingLeft();
final int rightBound = getWidth() - child.getWidth() - leftBound;
//在leftBound和rightBound之间 那么就返回left
//如果left的值 比 leftbound还要小 那么就说明超过了左边界 那么返回左边界的值
//如果left的值 比rightbound还要大 那么就说明超过了右边界,那么返回右边界的值
final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
return newLeft;
}
//同上只是这里是垂直方向(y坐标)
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
final int topBound = getPaddingTop();
final int bottomBound = getHeight() - child.getHeight() - topBound;
return Math.min(Math.max(top, topBound), bottomBound);
}
需要重写ViewDragHelper.Callback的onViewReleased方法,该方法在View拖动结束后会回调
在该方法里面对View复位(移动回0,0位置)
关键代码
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
//手指释放时可以自动复位
if (releasedChild instanceof LinearLayout) {
//设置View返回到0,0的位置
mDragHelper.settleCapturedViewAt(0, 0);
invalidate();//重新绘制
}
}
重写View的方法
//view.invalidate(),会触发onDraw和computeScroll()
@Override
public void computeScroll() {
////如果滚动还没有结束
if (mDragHelper.continueSettling(true)) {
invalidate();
}
}
需要重写ViewDragHelper.Callback的onEdgeDragStarted方法,在View的边界上拖动会回调该方法,但是必须设置属性:
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
边界拖动需要获取指定的View,可以重写View里面的onFinishInflate进行获取
//在边界拖动时回调
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId)
{
mDragHelper.captureChildView(rl3, pointerId);
}
获取View的方法
@Override
protected void onFinishInflate() {
super.onFinishInflate();
rl3 = findViewById(R.id.rl3);
}
如果将拖动的View换成Buttom,那么拖动效果就失效了
主要是因为Buttom消耗了拖动事件
重写两个方法
//获取被拖拽View child 的水平拖拽范围,返回0表示无法被水平拖拽
@Override
public int getViewHorizontalDragRange(View child)
{
return getMeasuredWidth()-child.getMeasuredWidth();
}
//获取被拖拽View child 的垂直拖拽范围,返回0表示无法被水平拖拽
@Override
public int getViewVerticalDragRange(View child)
{
return getMeasuredHeight()-child.getMeasuredHeight();
}