ViewDragerHelper(一)認識與簡單實現

前言

<p>
ViewDrager是什么呢?

看看官方的解釋其實就明白了

/**
 * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number
 * of useful operations and state tracking for allowing a user to drag and reposition
 * views within their parent ViewGroup.
 */

從這段解釋呢我們可以看到ViewDrager是簡化view拖拽操作的幫助類,ViewDragHelper解決了android中手勢處理過于復雜的問題。

ViewDragHelper是作用在一個ViewGroup上,也就是說他不能直接作用到被拖拽的view, 其實這也很好理解,因為view在布局中的位置是父ViewGroup決定的。

簡單實現

<p>
接下來就實現一個內部View隨意拖動的demo

分步來完成

1.自定義一個ViewGroup

public class VDHLayout extends LinearLayout{
    
     public VDHLayout(Context context) {
        this(context, null);
    }

    public VDHLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VDHLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    
}

2.創建ViewDragerHelper實例以及實現ViewDragHelper.CallCack相關方法

 private ViewDragHelper viewDragHelper;

 private void initViewDragHelper(){
        viewDragHelper = ViewDragHelper.create(this,myCallBack);
        viewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);
    }

ViewDragHelper.Callback myCallBack = new ViewDragHelper.Callback() {
    @Override
    public boolean tryCaptureView(View child, int pointerId)
    {
      return true;
    }
    @Override
    public int clampViewPositionHorizontal(View child, int left, int dx)
    {
      return left;
    }
    @Override
    public int clampViewPositionVertical(View child, int top, int dy)
    {
      return top;
    }
};

3.觸摸相關方法

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return viewDragHelper.shouldInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    viewDragHelper.processTouchEvent(event);
    return true;
}

布局內容就不貼上來了

最后實現的效果如下

圖1 ViewDragerHelper簡單demo

是不是很神奇,簡單的幾行代碼就實現了這樣的效果了,至于為什么會實現呢?

這個到下一篇再從源碼角度進行說明

接下來我們看看ViewDragHelper.CallCack里的方法,這里面的方法則是ViewDragHelper實現不同效果和功能的主要地方

ViewDragHelper.CallCack

<p>
ViewDragHelper.CallCack里面的方法很多,分別介紹

  • onViewDragStateChanged(int state)

    當View的拖拽狀態改變時的回調
    STATE_IDLE: 當前未被拖拽
    STATE_DRAGGING:正在被拖拽
    STATE_SETTLING: 被拖拽后需要被安放到一個位置中的狀態

  • onViewPositionChanged(View changedView, int left, int top, int dx, int dy)

    當View拖拽位置發生變化時的回調
    changedView :被拖拽的View
    left : 被拖拽后View的left邊緣坐標
    top : 被拖拽后View的top邊緣坐標
    dx : 拖動的x偏移量
    dy : 拖動的y偏移量

  • onViewCaptured(View capturedChild, int activePointerId)

當一個View捕獲到準備拖拽時的回調
capturedChild : 捕獲的View
activePointerId: 對應的PointerId

  • onViewReleased(View releasedChild, float xvel, float yvel)

    當被捕獲拖拽View釋放的回調
    releasedChild:被釋放的View
    xvel: 釋放View的x方向上的加速度
    yvel: 釋放View的y方向上的加速度

  • onEdgeTouched(int edgeFlags, int pointerId)

    邊緣觸摸的回調
    edgeFlags : 當前觸摸的flag 有: EDGE_LEFT,EDGE_TOP,EDGE_RIGHT,EDGE_BOTTOM
    pointerId : 用來描述邊緣觸摸操作的id

  • onEdgeLock(int edgeFlags)

    是否鎖定該邊緣的觸摸,默認返回false,返回true表示鎖定

  • onEdgeDragStarted(int edgeFlags, int pointerId)

    邊緣觸摸開始時的回調
    edgeFlags : 當前觸摸的flag 有: EDGE_LEFT,EDGE_TOP,EDGE_RIGHT,EDGE_BOTTOM
    pointerId : 用來描述邊緣觸摸操作的id

  • getOrderedChildIndex(int index)

    如果需要改變子View的遍歷查詢順序可改寫此方法,例如讓下層的View優先于上層的View被選中。

  • tryCaptureView(View child, int pointerId)

    嘗試捕獲被拖拽的View
    child : 嘗試捕獲的View
    pointerId: 對應的PointerId

  • getViewHorizontalDragRange(View child)

    獲取被拖拽View child 的水平拖拽范圍,返回0表示無法被水平拖拽

  • getViewVerticalDragRange(View child)

    獲取被拖拽View child 的垂直拖拽范圍,返回0表示無法被垂直拖拽

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

    決定拖拽View在水平方向上應該移動到的位置
    child : 被拖拽的View
    left : 期望移動到位置的View的left值
    dx : 移動的水平距離
    返回值 : 直接決定View在水平方向的位置

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

    決定拖拽View在垂直方向上應該移動到的位置
    child : 被拖拽的View
    top : 期望移動到位置的View的top值
    dy : 移動的垂直距離
    返回值 : 直接決定View在垂直方向的位置

寫在后面的話

<p>
到這里基本上簡單使用已經介紹完畢了,對ViewDragHelper.CallCack的方法也都介紹了一遍,對于更深的源碼解析和更深層次的使用就放在后面的文章進行分析了。。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容