Android 7.0 Gallery相簿原始碼分析4
上篇文章講了初始化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, 0),
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() > 0) {
......
} 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方法就知道了。