ViewDragHelper是Android系统原生封装用于ViewGroup滑动的类库.(ViewDragHelper只能用在ViewGroup中.)
使用ViewDragHelper,可以非常方便的在ViewGroup中移动,滑动任意一个子View,并且控制相当方便.
1:基础代码模版
public class ViewDragTestLayout extends RelativeLayout {
ViewDragHelper mViewDragHelper;
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//中间参数表示灵敏度,比如滑动了多少像素才视为触发了滑动.值越大越灵敏.
mViewDragHelper = ViewDragHelper.create(this, 1f, new DragCallback());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//固定写法
int action = MotionEventCompat.getActionMasked(ev);
if (action == MotionEvent.ACTION_CANCEL
|| action == MotionEvent.ACTION_UP) {
mViewDragHelper.cancel();
return false;
}
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//固定写法
mViewDragHelper.processTouchEvent(event);
return true;
}
@Override
public void computeScroll() {
//固定写法
//此方法用于自动滚动,比如自动回滚到默认位置.
if (mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
以上代码,可以粘贴复制. 都是模版代码;
2:ViewDragHelper.Callback
//这个类的回调方法,才是ViewDragHelper的重点
private class ViewDragCallback extends ViewDragHelper.Callback{
@Override
public boolean tryCaptureView(View child, int pointerId) {
//child 表示想要滑动的view
//pointerId 表示触摸点的id, 比如多点按压的那个id
//返回值表示,是否可以capture,也就是是否可以滑动.可以根据不同的child决定是否可以滑动
return true;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//child 表示当前正在移动的view
//left 表示当前的view正要移动到左边距为left的地方
//dx 表示和上一次滑动的距离间隔
//返回值就是child要移动的目标位置.可以通过控制返回值,从而控制child只能在ViewGroup的范围中移动.
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
//child 表示当前正在移动的view
//top 表示当前的view正要移动到上边距为top的地方
//dx 表示和上一次滑动的距离间隔
return top;
}
}
重写以上3个方法, 你的ViewGroup就可以正常工作了.子View就可以被任意拖动了.
3:控制child的移动范围在父view中
//控制child只能在ViewGroup的横向中移动
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
final int leftBound = getPaddingLeft();
final int rightBound = getWidth() - mDragView.getWidth();
final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
return newLeft;
}
//控制child只能在ViewGroup的纵向中移动
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
final int topBound = getPaddingTop();
final int bottomBound = getHeight() - mDragView.getHeight();
final int newTop = Math.min(Math.max(top, topBound), bottomBound);
return newTop;
}
回调顺序
//一次滑动周期的回调顺序.(开始拖动到放手)
getOrderedChildIndex - 0
getOrderedChildIndex - 0
tryCaptureView - tryCaptureView -1 0
onViewCaptured - null
onViewDragStateChanged - null
clampViewPositionHorizontal - left:11 dx:11
clampViewPositionVertical - top:5 dy:5
onViewPositionChanged - null
...
clampViewPositionHorizontal - left:100 dx:23
clampViewPositionVertical - top:44 dy:11
onViewPositionChanged - null
onViewReleased - null
onViewDragStateChanged - null
4:开启边界滑动
//开启4个边
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);
//各个边
public static final int EDGE_LEFT = 1 << 0;
public static final int EDGE_RIGHT = 1 << 1;
public static final int EDGE_TOP = 1 << 2;
public static final int EDGE_BOTTOM = 1 << 3;
//当开启边界滑动之后, 此方法就会回调
@Override
public void onEdgeTouched(int edgeFlags, int pointerId) {
//通常开启边界之后, 都需要手动capture view.之后就可以滑动view了.
mViewDragHelper.captureChildView(getChildAt(1), pointerId);
}
@Override
public boolean tryCaptureView(View child, int pointerId) {
//开启边界之后, 这个方法的返回值可能需要进一步处理.要不然开边界就没啥意思了.
return false;
}
回调顺序:
getOrderedChildIndex - 2
onEdgeTouched - edgeFlags:4 pointerId:0
getOrderedChildIndex - 2
tryCaptureView - tryCaptureView -1 0
...
5:释放后的回弹效果
有些时候, 当释放的时候, 需要将View回到原来的位置.
//释放的时候, 会回调下面的方法
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
//调用这个方法,就可以设置releasedChild回弹得位置.
mViewDragHelper.settleCapturedViewAt(0, 100);//参数就是x,y的坐标
postInvalidate();//注意一定要调用这个方法,否则没效果.
}
//以下2个方法最终调用的都是forceSettleCapturedViewAt().
mViewDragHelper.settleCapturedViewAt(0, 100);
mViewDragHelper.smoothSlideViewTo(getChildAt(1), 0, 100);
//所以...发挥你的想象力,看看有什么妙用!!!
//如果你还没有忘记的话...前文应该有说过,涉及到scroll,需要重写view的此方法.
//此方法一定要重写,否则没效果
@Override
public void computeScroll() {
//固定写法
if (mViewDragHelper.continueSettling(true)) {
postInvalidate();//注意此处.
}
}
通过上面2个方法的设置, 当手指释放的时候, View就会自动滑动到指定的位置...(不是一下子就到指定的位置哦,有一个滑动的过程.)
注意:如果需要滑动的View,会消耗touch事件,比如:Button,那么需要重写以下方法.
@Override
public int getViewHorizontalDragRange(View child) {
return child.getMeasuredWidth();//只要返回大于0的值就行
}
@Override
public int getViewVerticalDragRange(View child) {
return child.getMeasuredHeight();//只要返回大于0的值就行
}
到这里, 就结束啦...
相关阅读:
http://blog.csdn.net/lmj623565791/article/details/46858663
http://blog.csdn.net/pi9nc/article/details/39583377
至此: 文章就结束了,如有疑问: QQ群:274306954 欢迎您的加入.