天天看點

Android 7.0 Gallery圖庫源碼分析4 - SlotView手勢監聽及頁面跳轉

轉載請注明出處: http://blog.csdn.net/lb377463323/article/details/70208825

上篇文章講了初始化View時會執行個體化一個SlotView并監聽其事件,至于它是怎麼實作的,用的是Android自帶的GestureDetector。

GestureDetector是Android自帶的用來監聽各種使用者手勢的的一個類,比如監聽單擊、輕按兩下和長按等操作。關于GestureDetector的詳解可以參考此文章使用者手勢檢測-GestureDetector使用詳解

SlotView中定義了一個GestureDetector。

private final GestureDetector mGestureDetector;

public SlotView(AbstractGalleryActivity activity, Spec spec) {
        //給GestureDetector傳入我們自定義的Listener接口
        mGestureDetector = new GestureDetector(activity, new MyGestureListener());
        ......
    }
           

然後在onTouch中攔截SlotView的觸摸事件并交給GestureDetector處理

@Override
    protected boolean onTouch(MotionEvent event) {
        ......
        mGestureDetector.onTouchEvent(event);
        ......
        //必須傳回true,不然監聽不到完整事件
        return true;
    }
           

至于GestureDetector的監聽事件怎麼和SlotView的Listener綁定到一起的?我們看一下自定義的MyGestureListener接口,它就是實作了GestureDetector的OnGestureListener接口。

private class MyGestureListener implements GestureDetector.OnGestureListener {
        ......
        //點選一次
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            ......
            //擷取點選的相冊索引
            int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY());
            //處理點選事件
            if (index != INDEX_NONE) mListener.onSingleTapUp(index);
            return true;
        }
}
           

從上述代碼可以看出當GestureDetector監測到點選事件時會回調onSingleTapUp方法,在這個方法裡我們對點選事件進行處理。上面的mListener就是SlotView中的Listener接口,這樣就将GestureDetector的監聽事件和SlotView的Listener綁定到一起了。是以每次接收到觸摸事件時最終都會傳給SlotView的Listener處理,至于SlotView的Listener具體怎麼實作每個ActivityState頁面都不一樣,比如AlbumSetPage中就是如下實作的,最後會調用AlbumSetPage對應的方法來處理觸摸事件:

private void initializeViews() {
    mSlotView.setListener(new SlotView.SimpleListener() {
            @Override
            public void onDown(int index) {
                AlbumSetPage.this.onDown(index);
            }

            @Override
            public void onUp(boolean followedByLongPress) {
                AlbumSetPage.this.onUp(followedByLongPress);
            }

            @Override
            public void onSingleTapUp(int slotIndex) {
                AlbumSetPage.this.onSingleTapUp(slotIndex);
            }

            @Override
            public void onLongTap(int slotIndex) {
                AlbumSetPage.this.onLongTap(slotIndex);
            }
        });
}
           

現在手勢監聽流程已經講解完了,下面講一下界面的跳轉,我們找到AlbumSetPage的onSingleTapUp方法

public void onSingleTapUp(int slotIndex) {
        if (mSelectionManager.inSelectionMode()) {
            ......
        } else {
            //顯示動畫
            mAlbumSetView.setPressedIndex(slotIndex);
            mAlbumSetView.setPressedUp();
            //通過Handler發送消息,msg.arg1是slotIndex,也就是點選的相冊索引
            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, ),
                    FadeTexture.DURATION);
        }
    }
           

Handler的handleMessage方法在AlbumSetPage的onCreate方法中

mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
            @Override
            public void handleMessage(Message message) {
                switch (message.what) {
                    case MSG_PICK_ALBUM: {
                        //跳轉到相冊
                        pickAlbum(message.arg1);
                        break;
                    }
                    default: throw new AssertionError(message.what);
                }
            }
        };
           

我們看一下pickAlbum的代碼,

private void pickAlbum(int slotIndex) {
    ......
    if (mGetAlbum && targetSet.isLeafAlbum()) {
            ......
        } else if (targetSet.getSubMediaSetCount() > ) {
            ......
        } else {
            ......
            data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath);

            // We only show cluster menu in the first AlbumPage in stack
            boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class);
            data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum);
            //通過StateManager跳轉到AlbumPage類中,跟應用的啟動流程差不多
            mActivity.getStateManager().startStateForResult(
                    AlbumPage.class, REQUEST_DO_ANIMATION, data);
        }
}
           

通過上述代碼可以看出頁面Gallery的頁面跳轉都是通過StateManager來管理的。如果從相冊點選進入某一張圖檔,跳轉邏輯也跟着一樣,看下AlbumPage的handleMessage方法就知道了。