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进行管理的