Gallery浏览图片除开编辑界面,主要有三个界面:即起始页,相册簿集合页面(AlbumSetPage);点击某个相册进入该相册的所有图片页面(AlbumPage)和再点击某张具体图片之后的图片浏览页面(PhotoPage)。
我们从起始页面开始,点击某个相册:
一个相册是一个SlotView对象,在onCreate()中初始化了SlotView。并且对SlotView进行了监听:
- 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);
- }
- });
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);
}
});
接下来看onSingleTapUp()中是如何实现的:
- public void onSingleTapUp(int slotIndex) {
- if (!mIsActive) return;
- ...
- mHandler.sendMessage(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0));
- }
- }
public void onSingleTapUp(int slotIndex) {
if (!mIsActive) return;
...
mHandler.sendMessage(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0));
}
}
意即这一动作发送了一条消息,消息的处理在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);
- }
- }
- };
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);
}
}
};
- private void pickAlbum(int slotIndex) {
- if (!mIsActive) return;
- ...
- mActivity.getStateManager().startStateForResult(
- AlbumPage.class, REQUEST_DO_ANIMATION, data);
- }
- }
private void pickAlbum(int slotIndex) {
if (!mIsActive) return;
...
mActivity.getStateManager().startStateForResult(
AlbumPage.class, REQUEST_DO_ANIMATION, data);
}
}
接收到动作消息,启动相册页面AlbumPage对象。另外一个界面的跳转与此相同。我关注的点不在这里,这里我的疑问是SlotView.SimpleListener是我们自定义的监听器,这个监听器是如何实现手势监听的?原来Android系统提供了一套手势监听的接口GestureDetector.OnGestureListener,它们由底层驱动实现,是标准的手势接口,我们调用它实现自己的手势监听。
- 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);
- }
- 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);
}
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) {}
}
- private class MyGestureListener implements GestureDetector.OnGestureListener {
- ...
- @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;
- }
private class MyGestureListener implements GestureDetector.OnGestureListener {
...
@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;
}
mListener是Listener的对象。我们梳理一下这个过程,手指在屏幕上做点击抬起操作,屏幕感应器检测到这一点,交给相应驱动处理,驱动调用本地函数处理,本地函数调用GestureDetector.OnGestureListener的onSingleTapUp()函数,该函数调用了我们自定义的Listener的onSingleTapUp()函数,这个函数的实现则在我们创建的Listener对象中具体实现。这就是回调函数的机制。屏幕能检测到任何我们手指在屏幕上的操作,但是自上倒下没有任何的处理,这些函数里的内容都是空的,当我们在使用的时候把这些空的地方进行相应的填充就有了同一手势的不同实现。