天天看點

04 Gallery 源碼-SlotView相冊清單中點選單個相冊的手勢事件

0. 原文拜讀

https://blog.csdn.net/lb377463323/article/details/70208825

1. AlbumSetPage 中的 SlotView

package com.android.gallery3d.app;

import com.android.gallery3d.ui.SlotView;


// 顯示所有相冊縮略圖的頁面
public class AlbumSetPage extends ActivityState implements OnClickListener,...{

    // SlotView 就是一個相冊
    private SlotView mSlotView;

    private void initializeViews() {
        // mActivity -> mFragment
        if (null != mFragment && mFragment.isAdded()) {
            ...
        } else {
            mSelectionManager = new SelectionManager(mActivity, true);
            mSelectionManager.setSelectionListener(this);

            //mConfig是用來設定SlotView的參數,而
            mConfig = Config.AlbumSetPage.get(mActivity);
            mSlotView = new SlotView(mActivity, mConfig.slotViewSpec);

            //mAlbumSetView是mSlotView的渲染器,控制mSlotView的顯示
            mAlbumSetView = new AlbumSetSlotRenderer(
                    mActivity, mSelectionManager, mSlotView, mConfig.labelSpec,
                    mConfig.slotViewSpec,
                    mConfig.placeholderColor);

            //将mAlbumSetView設定給mSlotView        
            mSlotView.setSlotRenderer(mAlbumSetView);
            
            //監聽SlotView事件,根據手勢操作做出相應的響應,這個監聽事件原理
            mSlotView.setListener(new SlotView.SimpleListener() {
                ...
            });

            ...
            
            //把這個SlotView作為一個子控件傳給GLView,mRootPane是GLView類
            mRootPane.addComponent(mSlotView);
        }
    }
    
}

           

2. SlotView 的手勢事件

2.1 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);
            }
        });
           

2.2 手勢監聽接口

package com.android.gallery3d.ui;

public class SlotView extends GLView {

    public static class SimpleListener implements Listener {
        @Override public void onDown(int index) {}
        @Override public void onUp(boolean followedByLongPress) {}
        @Override public void onSingleTapUp(int index) {}
        @Override public void onLongTap(int index) {}
        @Override public void onScrollPositionChanged(int position, int total) {}
    }

    public interface Listener {
        public void onDown(int index);
        public void onUp(boolean followedByLongPress);
        public void onSingleTapUp(int index);
        public void onLongTap(int index);
        public void onScrollPositionChanged(int position, int total);
    }
}
           

2.3 手勢注冊器執行個體化

package com.android.gallery3d.ui;

public class SlotView extends GLView {
    
    // Android 系統自帶的手勢檢測器
    private final GestureDetector mGestureDetector;

    public SlotView(AbstractGalleryActivity activity, Spec spec) {
        mGestureDetector = new GestureDetector(activity, new MyGestureListener());
        ...
    }
}
           

2.4 手勢事件來源

package com.android.gallery3d.ui;

public class SlotView extends GLView {

    @Override
    protected boolean onTouch(MotionEvent event) {
        if (mUIListener != null) mUIListener.onUserInteraction();
        mGestureDetector.onTouchEvent(event);
        ....
    }
}
           

2.5 MyGestureListener()

private class MyGestureListener implements GestureDetector.OnGestureListener {
        private boolean isDown;

        // We call the listener's onDown() when our onShowPress() is called and
        // call the listener's onUp() when we receive any further event.
        @Override
        public void onShowPress(MotionEvent e) {
            GLRoot root = getGLRoot();
            root.lockRenderThread();
            try {
                if (isDown) return;
                int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY());
                if (index != INDEX_NONE) {
                    isDown = true;
                    mListener.onDown(index);
                }
            } finally {
                root.unlockRenderThread();
            }
        }

        private void cancelDown(boolean byLongPress) {
            if (!isDown) return;
            isDown = false;
            mListener.onUp(byLongPress);
        }

        @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }

        @Override
        public boolean onFling(MotionEvent e1,
                MotionEvent e2, float velocityX, float velocityY) {
            cancelDown(false);
            int scrollLimit = mLayout.getScrollLimit();
            if (scrollLimit == 0) return false;
            float velocity = WIDE ? velocityX : velocityY;
            mScroller.fling((int) -velocity, 0, scrollLimit);
            if (mUIListener != null) mUIListener.onUserInteractionBegin();
            invalidate();
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1,
                MotionEvent e2, float distanceX, float distanceY) {
            cancelDown(false);
            float distance = WIDE ? distanceX : distanceY;
            int overDistance = mScroller.startScroll(
                    Math.round(distance), 0, mLayout.getScrollLimit());
            if (mOverscrollEffect == OVERSCROLL_3D && overDistance != 0) {
                mPaper.overScroll(overDistance);
            }
            invalidate();
            return true;
        }

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

        @Override
        public void onLongPress(MotionEvent e) {
            cancelDown(true);
            if (mDownInScrolling) return;
            lockRendering();
            try {
                int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY());
                if (index != INDEX_NONE) mListener.onLongTap(index);
            } finally {
                unlockRendering();
            }
        }
    }
           

3. SlotView 手勢回調的處理

  • AlbumSetPage.this.onSingleTapUp(slotIndex)為例
public void onSingleTapUp(int slotIndex) {
        if (!mIsActive) return;

        if (mSelectionManager.inSelectionMode()) {
            MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex);
            if (targetSet == null) return; // Content is dirty, we shall reload soon
            mSelectionManager.toggle(targetSet.getPath());
            mSlotView.invalidate();
        } else {
            // Show pressed-up animation for the single-tap.
            // 顯示動畫
            mAlbumSetView.setPressedIndex(slotIndex);
            mAlbumSetView.setPressedUp();
            // 跳轉到相冊
            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0),
                    FadeTexture.DURATION);
        }
    }
           

3.1 mHandler 傳遞

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);
            }
        }
    };
           

3.2 跳轉相冊

package com.android.gallery3d.ui;

public class SlotView extends GLView {

    private void pickAlbum(int slotIndex) {
        ...

        if (mGetAlbum && targetSet.isLeafAlbum()) {
            ....
        } else if (targetSet.getSubMediaSetCount() > 0) {
            ...
        } else {
            ....
            data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath);

            //通過StateManager跳轉到AlbumPage類中,跟應用的啟動流程差不多
            getStateManager().startStateForResult(
                    AlbumPage.class, REQUEST_DO_ANIMATION, data);
        }
    }
}
           

上述中的頁面跳轉,即所有相冊縮略圖到相冊的界面切換都是通過StateManager進行管理的

繼續閱讀