天天看點

ViewDragHelper類的使用方法和事件分發機制ViewDragHelper類的使用方法和事件分發機制的配合

ViewDragHelper類的使用方法和事件分發機制的配合

  1. 寫一個SlideMenu類,繼承自FrameLayout,因為如果繼承自ViewGroup的話,需要我們自己來實作onMeasure方法,而該方法的實作一般比較麻煩且沒有必要,是以選擇繼承系統的已有的控件FrameLayout,不用其他控件是因為FrameLayout最輕量級
  2. 在布局檔案中給SlideMenu添加2個子布局,分别是菜單的布局和主界面的布局(代碼略);
  3. 移動View的方法總結:
    通過改變View的scroll的坐标來移動:
    scrollTo(x,y);//滾動到指定位置
    scrollBy(xOffset,yOffset);//滾動多少距離
               
  4. 通過改變View在父View中的布局的位置:
    offsetLeftAndRight(offset);//同時更改view的left和right
    offsetTopAndBottom(offset);//同時更改view的top和bottom
    layout(l,t,r,b);
               
    但是谷歌發現很多View移動的情景有相識點, 是以封裝了ViewDragHelper類來幫助我們在ViewGroup中進行子View的移動:

ViewDragHelper類的介紹

谷歌在2013年I/O開發者大會上提出;
  • 專門用于在ViewGroup中對子View進行拖拽處理;
  • 在19(Android4.4)以及以上的v4包中;
  • 本質是封裝了對觸摸事件的解析,包括觸摸位置,觸摸速度以及Scroller的封裝,隻需要我們在回調方法中指定是否移動,移動多少等等,但是需要注意的是:它隻是一個觸摸事件的解析類(如GestureDecetor),是以需要我們傳遞給它觸摸事件,它才能工作;

ViewDragHelper類的使用方法

如何建立ViewDragHelper對象

ViewDragHelper viewDragHelper = ViewDragHelper.create(this, callback);
           

由于ViewDragHelper隻是觸摸事件解析類,要想讓ViewDragHelper工作,需要将觸摸事件傳遞給它

public boolean onInterceptTouchEvent(MotionEvent ev) {
    //讓ViewDragHelper幫助我們判斷是否應該攔截
    boolean result = viewDragHelper.shouldInterceptTouchEvent(ev);
    return result;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
    //将觸摸事件傳遞給ViewDragHelper來解析
    viewDragHelper.processTouchEvent(event);
    return true;
}
           

重寫幾個方法

  • 判斷是否需要捕獲View的觸摸事件

    public boolean tryCaptureView(View child, int pointerId)

  • 當一個View被捕獲觸摸事件時候調用

    public void onViewCaptured(View capturedChild, int activePointerId)

  • 方法名為擷取水準方向拖拽的範圍,然而目前并沒有用,該方法的傳回值用來作為判斷滑動方向的條件之一

    public int getViewHorizontalDragRange(View child)

  • 用來修正或者指定子View在水準方向上的移動

    public int clampViewPositionHorizontal(View child, int left, int dx)

  • 用來修正或者指定子View在垂直方向上的移動

    public int clampViewPositionVertical(View child, int top, int dy)

  • 當View移動的時候調用

    public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy)

  • 當手指從View上擡起的時候回調

    public void onViewReleased(View releasedChild, float xvel, float yvel)

其他的方法

調用方法 :參數需要移動的控件,左上角的原點的坐标
smoothSlideViewTo(View child, int finalLeft, int finalTop)
方法可以使自動移動到某個位置
           
重新整理頁面:參數為需要重新整理控件的父控件
ViewCompat.postInvalidateOnAnimation(Slidemenu.this);
           

需要重寫view裡面的computeScroll()方法才能實作重新整理

/**
 * 頁面重新整理都得走這個方法
 * 重新整理方法->draw()->computeScroll
 */
@Override
public void computeScroll() {
    super.computeScroll();
    if (viewDragHelper.continueSettling(true)) {
        ViewCompat.postInvalidateOnAnimation(SlideMenu.this);
    }
}
           

水準移動的案例

private ViewDragHelper.Callback callback= new MyCallback();
    private class MyCallback extends ViewDragHelper.Callback{
        /**
     * 判斷是否需要捕獲View的觸摸事件,捕獲事件後才可執行下面的方法
     * @param child   目前觸摸的View
     * @param pointerId  觸摸點索引
     * @return  true:捕獲,  false:不捕獲.
     */
    @Override
    public boolean tryCaptureView(View child, int pointerId) {
        Log.d(TAG, "tryCaptureView");
        return true;
    }
    /**
     * 當一個View被捕獲觸摸事件時候調用
     * @param capturedChild 被捕獲觸摸事件的子View
     * @param activePointerId
     */
    @Override
    public void onViewCaptured(View capturedChild, int activePointerId) {
        Log.d(TAG, "tryConViewCapturedaptureView");
        super.onViewCaptured(capturedChild, activePointerId);
    }
    /**
     * 方法名為擷取水準方向拖拽的範圍,然而目前并沒有用,該方法的傳回值用來作為判斷滑動方向的條件之一,
     * 如果你想水準移動,那麼該方法的傳回值最好大于0
     * @param child
     * @return
     */
    @Override
    public int getViewHorizontalDragRange(View child) {
        //Log.d(TAG, "getViewHorizontalDragRange");
        return 1;
    }
    /**
     * 用來修正或者指定子View在水準方向上的移動
     * @param child
     * @param left  是ViewDragHelper幫你計算好的View最新的left的值,left=view.getLeft()+dx
     * @param dx   本次水準移動的距離
     * @return  傳回的值表示我們真正想讓View的left變成的值
     */
    @Override
    public int clampViewPositionHorizontal(View child, int left, int dx) {
        //Log.v(TAG, "clampViewPositionHorizontal");
        return left;
    }
    /**
     * 用來修正或者指定子View在垂直方向上的移動
     * @param
     * @param top  是ViewDragHelper幫你計算好的View最新的top的值,top=view.getTop()+dy
     * @param dy   本次垂直移動的距離
     * @return  傳回的值表示我們真正想讓View的top變成的值
     */
    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
       // Log.e(TAG, "clampViewPositionVertical");
        return super.clampViewPositionVertical(child, top, dy);
    }


    /**
     * 當View移動的時候調用
     * @param changedView   目前移動的VIew
     * @param left  目前View移動之後最新的left
     * @param top   目前View移動之後最新的top
     * @param dx    水準移動的距離
     * @param dy    垂直移動的距離
     */
    @Override
    public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
        Log.d(TAG, "onViewPositionChanged");
        if (changedView==mMainView){

        }
    }
    /**
     * 當手指從View上擡起的時候回調
     * @param releasedChild
     * @param xvel  x方向滑動的速度
     * @param yvel  y方向滑動的速度
     */
    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
        Log.v(TAG, "onViewReleased");
        super.onViewReleased(releasedChild, xvel, yvel);
    }
};
           

事件分發機制

幾個重要方法
  • 分發事件

    public boolean dispatchTrackballEvent(MotionEvent event)

  • 攔截事件

    public boolean onInterceptTouchEvent(MotionEvent ev)

  • 處理事件

    public boolean onTouchEvent(MotionEvent event)

ViewGroup中的事件處理的發放

/**
     *分發事件
     * @param event 事件
     */
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {

    return super.dispatchTrackballEvent(event);
}

/**
     *攔截事件
     * @param event 事件
     * @return  傳回true 不攔截 ;false攔截
     */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    Log.d(TAG, "是否攔截");
    //讓viewDragHelper幫主我們判斷是否應該攔截
    return viewDragHelper.shouldInterceptTouchEvent(ev);
}

/**
     *處理事件
     * @param event 事件
     * @return  傳回true 自己處理 ;false傳遞給下一個處理
     */
@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG, "onTouchEvent");
    //讓ViewDragHelper幫主我們處理觸摸事件
    viewDragHelper.processTouchEvent(event);
    return true;
}
           
ViewDragHelper類的使用方法和事件分發機制ViewDragHelper類的使用方法和事件分發機制的配合

繼續閱讀