Android:ViewDragHelper学习

android v4包中的视图拖拽的帮助类。

参考博客:
2、http://blog.csdn.net/pi9nc/article/details/39583377

1、创建方法:
ViewDragHelper.create(ViewGroup forParent, float sensitivity, Callback cb)

第一个参数是当前要拖拽的ViewGroup对象,
第二个参数是拖拽的灵敏度,
第三个参数是拖拽的监听回调。

代码如下:
private ViewDragHelper mDragger;
mDragger = ViewDragHelper.create(this, 1.0f, callBack);
2、事件分发
ViewGroup的事件分发都是从dispatchTouchEvent开始的,当dispatch返回true时,则事件下发到ViewGroup的onInterceptTouchEvent,该方法进行判断是否对事件进行拦截,当返回true时,表示拦截事件,则事件传递到ViewGroup中的onTouchEvent处理;返回false时,表示不拦截事件,则事件分发到子View。

原理懂了之后,再处理ViewGroup的拖拽事件,我们在onInterceptTouchEvent进行拦截,然后再onTouchEvent中进行处理,代码如下:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
final int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_CANCEL
|| action == MotionEvent.ACTION_UP) {
return false;
}
return mDragger.shouldInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mDragger.processTouchEvent(event);
return true;
}
3、事件回调
在创建ViewDragHelper对象实例的时候,传入了一个callback回调,作为view与手势动作的一个桥梁。下面是回调覆写的一些相关的方法。
(1)clampViewPositionHorizontal(View child,int left ,int dx),这个方法用来处理横向的拖动,返回一个int值就可以实现横向的拖动效果,其中left是当前View拖动到达的x座标,理论上这个方法返回第二个参数left的值,当然,还可以对返回的left值做处理。比如,设置拖动过程遇到左右边界就不让其拖动。代码如下:
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
Log.d("DragLayout", "clampViewPositionHorizontal " + left + ","
+ dx);
final int leftBound = getPaddingLeft();
final int rightBound = getWidth() - mView1.getWidth();
final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
return newLeft;
}
(2)clampViewPositionVertical(View child,int top , int dy),该回调方法跟第一个clampViewPositionHorizontal类似,主要是处理垂直拖动。这里就不多做介绍。这两个方法默认返回值是0,设置拖动过程遇到上下边界就不让其拖动,代码如下:
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
final int topBound = getPaddingTop();
final int BottomBound = getHeight() - mView1.getHeight();
final int newTop = Math.min(Math.max(top, topBound), BottomBound);
return newTop;
}
(3)tryCaptureView(View child, int pointerId)这个方法主要是决定改ViewGroup中有哪几个子View可以进行移动,先看下面的代码:
private View mView1;
private View mView2;
private View mView3;
 
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mView1= getChildAt(0);
mView2= getChildAt(1);
mView3= getChildAt(2);
}
 
@Override
public boolean tryCaptureView(View child, int pointerId) {
// mView3禁止直接移动
return child == mView1|| child == mView2;
}
从代码中可以发现,在当前的ViewGroup中,取得了3个子View:mView1,mView2,mView3,而我们在tryCaptureView中,传入了参数child,当child为mView1或者mView2时,返回true,否则返回false。所以,只有mView1和mView2可以拖动,mView3不能拖动。而当返回直接写 return true 时,则表示所有的child都可以拖动。

(4)onViewRelease(View releasedChild, float xvel,float yvel),这个方法是拖动结束后手指放开的回调,这里有一个用法是,让view拖动完回到原来的位置,代码如下:
//用来存放要拖动view的起始位置
private Point mAutoBackOriginPos = new Point();
//获取起始座标
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mAutoBackOriginPos.x = mView2.getLeft();
mAutoBackOriginPos.y = mView2.getTop();
}
//一定要覆写
@Override
public void computeScroll() {
if (mDragger.continueSettling(true)) {
    invalidate();
}
}
// 手指释放的时候回调
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
    // mView2手指释放时可以自动回去
    if (releasedChild == mView2) {
    mDragger.settleCapturedViewAt(mAutoBackOriginPos.x,
    mAutoBackOriginPos.y);
    //一定要invalidate
    invalidate();
}
}
(5)onEdgeDragStarted(int edgeFlags , int pointerId) ,ViewDragHelper有边缘检测的功能,其回调方法就是这个方法,当我们在边界拖动的时候,可以指定view进行移动。代码如下:
mDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
 
// 在边界拖动时回调
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
mDragger.captureChildView(mView3, pointerId);
}
第一行代码表示,检测的是左边缘,当我们的手指在屏幕左边缘滑动时,指定的mView3会根据滑动的方向及距离做出相应的移动。我们在onEdgeDragStarted回调方法中,主动通过captureChildView对其捕获,该方法可以绕过tryCaptureView,所以,即使我们在tryCaptureView中没有让mView3返回true,但不影响。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章