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,但不影響。

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