Android 7.0 Gallery圖庫源碼分析4 - SlotView手勢監聽及頁面跳轉
上篇文章講了初始化View時會實例化一個SlotView並監聽其事件,至於它是怎麽實現的,用的是Android自帶的GestureDetector。
GestureDetector是Android自帶的用來監聽各種用戶手勢的的一個類,比如監聽單擊、雙擊和長按等操作。關於GestureDetector的詳解可以參考此文章用戶手勢檢測-GestureDetector使用詳解
SlotView中定義了一個GestureDetector。
1 private final GestureDetector mGestureDetector; 2 3 public SlotView(AbstractGalleryActivity activity, Spec spec) {4 //給GestureDetector傳入我們自定義的Listener接口 5 mGestureDetector = new GestureDetector(activity, new MyGestureListener()); 6 ...... 7 }
然後在onTouch中攔截SlotView的觸摸事件並交給GestureDetector處理
1 @Override 2 protected boolean onTouch(MotionEvent event) { 3 ...... 4 mGestureDetector.onTouchEvent(event);5 ...... 6 //必須返回true,不然監聽不到完整事件 7 return true; 8 }
至於GestureDetector的監聽事件怎麽和SlotView的Listener綁定到一起的?我們看一下自定義的MyGestureListener接口,它就是實現了GestureDetector的OnGestureListener接口。
1 private class MyGestureListener implements GestureDetector.OnGestureListener { 2 ......3 //點擊一次 4 @Override 5 public boolean onSingleTapUp(MotionEvent e) { 6 ...... 7 //獲取點擊的相冊索引 8 int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); 9 //處理點擊事件 10 if (index != INDEX_NONE) mListener.onSingleTapUp(index); 11 return true; 12 } 13 }
從上述代碼可以看出當GestureDetector監測到點擊事件時會回調onSingleTapUp方法,在這個方法裏我們對點擊事件進行處理。上面的mListener就是SlotView中的Listener接口,這樣就將GestureDetector的監聽事件和SlotView的Listener綁定到一起了。所以每次接收到觸摸事件時最終都會傳給SlotView的Listener處理,至於SlotView的Listener具體怎麽實現每個ActivityState頁面都不一樣,比如AlbumSetPage中就是如下實現的,最後會調用AlbumSetPage對應的方法來處理觸摸事件
1 private void initializeViews() { 2 mSlotView.setListener(new SlotView.SimpleListener() { 3 @Override 4 public void onDown(int index) { 5 AlbumSetPage.this.onDown(index); 6 } 7 8 @Override 9 public void onUp(boolean followedByLongPress) { 10 AlbumSetPage.this.onUp(followedByLongPress); 11 } 12 13 @Override 14 public void onSingleTapUp(int slotIndex) { 15 AlbumSetPage.this.onSingleTapUp(slotIndex); 16 } 17 18 @Override 19 public void onLongTap(int slotIndex) { 20 AlbumSetPage.this.onLongTap(slotIndex); 21 } 22 }); 23 }
現在手勢監聽流程已經講解完了,下面講一下界面的跳轉,我們找到AlbumSetPage的onSingleTapUp方法
1 public void onSingleTapUp(int slotIndex) { 2 if (mSelectionManager.inSelectionMode()) { 3 ...... 4 } else { 5 //顯示動畫 6 mAlbumSetView.setPressedIndex(slotIndex); 7 mAlbumSetView.setPressedUp(); 8 //通過Handler發送消息,msg.arg1是slotIndex,也就是點擊的相冊索引 9 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0), 10 FadeTexture.DURATION); 11 } 12 }
Handler的handleMessage方法在AlbumSetPage的onCreate方法中
1 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { 2 @Override 3 public void handleMessage(Message message) { 4 switch (message.what) { 5 case MSG_PICK_ALBUM: { 6 //跳轉到相冊 7 pickAlbum(message.arg1); 8 break; 9 } 10 default: throw new AssertionError(message.what); 11 } 12 } 13 };
我們看一下pickAlbum的代碼,
1 private void pickAlbum(int slotIndex) { 2 ...... 3 if (mGetAlbum && targetSet.isLeafAlbum()) { 4 ...... 5 } else if (targetSet.getSubMediaSetCount() > 0) { 6 ...... 7 } else { 8 ...... 9 data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath); 10 11 // We only show cluster menu in the first AlbumPage in stack 12 boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class); 13 data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum); 14 //通過StateManager跳轉到AlbumPage類中,跟應用的啟動流程差不多 15 mActivity.getStateManager().startStateForResult( 16 AlbumPage.class, REQUEST_DO_ANIMATION, data); 17 } 18 }
通過上述代碼可以看出頁面Gallery的頁面跳轉都是通過StateManager來管理的。如果從相冊點擊進入某一張圖片,跳轉邏輯也跟著一樣,看下AlbumPage的handleMessage方法就知道了。
Android 7.0 Gallery圖庫源碼分析4 - SlotView手勢監聽及頁面跳轉