1. 程式人生 > >淺談Android 事件分發機制(一)

淺談Android 事件分發機制(一)

get touch 需要 傳遞 cimage android ges 常見 滑動

在上一篇文章中,淺談Android 事件分發機制(一),簡要分析了一下事件分發機制的原理,總結一下就是事件層層傳遞,直到被消費,原理看似簡單,但是在實際使用過程中,場景各不相同,復雜程度也就因產品而異,這篇文章就通過給view加移動來模擬事件分發。

觸摸事件

這裏涉及到幾個與手指觸摸相關的常見事件:

技術分享圖片

坐標系對於單指觸控移動來說,一次簡單的交互流程是這樣的:
手指落下(ACTION_DOWN) -> 移動(ACTION_MOVE) -> 離開(ACTION_UP)

坐標系

Android坐標系以手機屏幕左上角的頂點為坐標原點,從該點向右為x軸正方向,從該點向下為y軸正方向。 上圖所示,一次觸摸涉及到多種距離的計算, 上圖所標註的方法可以分為兩類,一類是View提供的方法,一類是MotionEvent提供的方法。

View提供的:
getTop():獲取到view自身的頂邊到其父布局頂邊的距離
getLeft():獲取到view自身的左邊到其父布局左邊的距離
getRight():獲取到view自身的右邊到其父布局左邊的距離
getBottom():獲取到view自身底邊到其父布局頂邊的距離

MotionEvent提供的方法:
getX():獲取觸摸點距離控件左邊的距離,即視圖坐標
getY(): 獲取觸摸點距離控件頂邊的距離,即視圖坐標
getRawX():獲取觸摸點距離整個屏幕左邊的距離,即絕對坐標
getRawY():獲取觸摸點距離整個屏幕頂邊的距離,即絕對坐標
知道了以上的知識點後,基於文章一做view的移動,這裏還是三個視圖ViewC、ViewGroupB、ViewGroupA

技術分享圖片

C添加移動

技術分享圖片

給ViewC(藍色區域)添加移動
onTouchEvent返回true,自身消費事件。
手指按下MotionEvent.ACTION_DOWN,記錄當前距離控件左邊和頂邊的距離lastXlastY
手指移動時MotionEvent.ACTION_MOVE,獲取當前距離控件左邊和頂邊的距離xy,減去手指按下時記錄的距離lastXlastY,計算得到移動的距離,移動的距離加上view距離父布局的距離,得到相對於父布局的四個點坐標,layout重新確認位置。
手指離開MotionEvent.ACTION_UP,設置view距離父布局的margin,這邊的操作主要是固定view的位置,後續和視圖B一起移動時可固定位置。

private int lastX;
private int lastY;
@Override
public boolean onTouchEvent(MotionEvent event) {
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            lastX = x;
            lastY = y;
            break;
        case MotionEvent.ACTION_MOVE:
            //計算移動的距離
            int offsetX = x - lastX;
            int offsetY = y - lastY;
            int l = getLeft() + offsetX;
            int b = getBottom() + offsetY;
            int r = getRight() + offsetX;
            int t = getTop() + offsetY;
            //重新確認位置
            layout(l, t, r, b);
            break;
        case MotionEvent.ACTION_UP:
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams();
            params.setMargins(getLeft(), getTop(), 0, 0);
            break;
        default:
            break;
    }
    return true;
}

B添加移動

同樣給ViewGroupB添加以上的代碼用於B的移動。(藍色的視圖C,×××的視圖B)
技術分享圖片

情況一:如上圖 這裏視圖B、C的onTouchEvent都返回true,在C區域滑動,viewC消費了事件,不再傳遞給B;只有在B、C不重疊的區域滑動,C才會移動,這時沒有接觸到C,所以不會觸發C的事件。因為我們在C的MotionEvent.ACTION_UP手指離開時固定了C到父布局(B)的距離,所以C相對B的位置沒變。
技術分享圖片

情況二:如上圖,將C的onTouchEvent返回false,在C區域滑動,事件沒有消費,傳遞給到了B,B可以滑動,在不重疊區域一樣可以滑動B。
如果B把事件攔截了onInterceptTouchEvent返回true,那麽效果和情況二相同的,不管C的onTouchEvent返回啥,都響應不了。
這裏模擬了視圖B、C的滑動,A的話原理相同,這裏就不再描述。
淺談android事件分發的兩篇文章結束了,這裏只是簡單描述模擬了事件分發。日常項目中若是遇到情況怕是更為復雜,想要徹底玩轉事件分發機制還需要進一步的研究。

淺談Android 事件分發機制(一)