继续讲解前,我们先回顾一下前面5节的分析。
首先在开机或者加载外部存储器时,在mediaprivder里面receiver会得到广播消息,receiver开启服务进行扫描,生成数据库,并在T卡上生成缩略图临时文件,
然后在第一个Activity里面有两个关于opengl的成员,RenderView和作为Root Layer 的GridLayer成员,并且关联了RenderView和Root Layer,并且在Activity里面通过调用RenderView的同名成员函数的办法,将按键响应以及渲染的暂停和继续同Activity同步关联。
而RenderView在刷新时,通过调用generate接口,生成Root层的,Root层调用generate接口生成背景层和Hud层,同样的办法Hud层生成其他的层,并将RendView保存到自己的成员变量中。
而这些层又分成了几个类,放在几个层的列表中,决定哪些层响应点击事件,哪些层透明。
现在我们要分析的问题是,界面和层是如何关联的,又是如何切换的?
这个问题比较多,会花几个部分解决。
我们先探讨一个小的问提,我们先使用下Gallery3d ,你会发现长按键后可以标记相册或者单一图片或者视频。
说明Gallery3d里面又两种模式,普通模式和选择模式对应的代码是在HudLayer中:
public final class HudLayer extends Layer { public static final int MODE_NORMAL = 0; public static final int MODE_SELECT = 1;
那么在关键的HudLayer中又用了两个方法来读取和设置模式
int getMode() { return mMode; } void setMode(int mode) { if (mMode != mode) { mMode = mode; updateViews(); } }
在哪里调用的呢
public void enterSelectionMode() { // Do not enter selection mode if the feed is about to change. if (mGridLayer.feedAboutToChange()) return; // Disable sharing if it is the pick intent. if (mGridLayer.getPickIntent()) { mSingleViewIntentBottomMenu = mSingleViewIntentBottomMenuNoShare; mNormalBottomMenu = mNormalBottomMenuNoShare; } setAlpha(1.0f); setMode(HudLayer.MODE_SELECT); // if we are in single view mode, show the bottom menu without the // delete button. if (mGridLayer.noDeleteMode()) { mSelectionMenuBottom.setMenus(mSingleViewIntentBottomMenu); } else { mSelectionMenuBottom.setMenus(mNormalBottomMenu); } }
public void cancelSelection() { mSelectionMenuBottom.close(); closeSelectionMenu(); setMode(MODE_NORMAL); }
就是通过HudLayer中的进入选择模式和退出选择模式来切换模式的和菜单的显示。那么从用户长按又是如何到enterSelectMode函数的呢?
首先触摸是各个层里面处理的,而按键都是Root Layer处理的,谁是Root Layer,当然是GridLayer,我们看下GridLayer是如何处理的
@Override public boolean onTouchEvent(MotionEvent event) { return mInputProcessor.onTouchEvent(event); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mInputProcessor != null) return mInputProcessor.onKeyDown(keyCode, event, mState); return false; }
说明所有GridLayer的按键和触摸都交给了一个叫做mInputProcessor的成员去处理了。对应的是
GridInputProcessor类
这个类又是如何处理的呢?
public void onLongPress(MotionEvent e) { if (mZoomGesture) return; if (mLayer.getFeed() != null && mLayer.getFeed().isSingleImageMode()) { HudLayer hud = mLayer.getHud(); hud.getPathBar().setHidden(true); hud.getMenuBar().setHidden(true); if (hud.getMode() != HudLayer.MODE_NORMAL) hud.setMode(HudLayer.MODE_NORMAL); } if (mCurrentFocusSlot != Shared.INVALID) { vibrateLong(); GridLayer layer = mLayer; if (layer.getState() == GridLayer.STATE_FULL_SCREEN) { layer.deselectAll(); } HudLayer hud = layer.getHud(); hud.enterSelectionMode(); layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true); } }
那么,我们重新整理下思路:
用户长按 Activity --> 因为Acitvity中的触摸是层里面处理的,所以给了根层GridLayer去处理,而GridLayer嫌麻烦,另外写了一个类GridInputProcessor的成员处理,而再这个类中,调用通过传进来的GridLayer上下文和方法 getHud获得了Hud层的对象,然后调用他的enterSelectionMode方法,将状态设置成了选择模式。
长按和处理我们看完了,其他的拖动和点击请自己再分析下,作为今天的作业吧,呵呵。
那么我们再来看GridLayer界面的显示,再构造函数我们可以看到下面的代码。
mCameraManager = new GridCameraManager(mCamera); mDrawManager = new GridDrawManager(context, mCamera, mDrawables, mDisplayList, mDisplayItems, mDisplaySlots); mInputProcessor = new GridInputProcessor(context, mCamera, this, mView, mTempVec, mDisplayItems);
mDrawManager就是负责界面的显示的。我们仔细看下。
大家还记得RenderView里面对三组层的列表进行的统一刷新么?
其中对opaque层是怎么刷新的,使用的是一个循环,加上调用层的renderOpaque方法,那么我们来看这个里面是否有?我们看GridLayer层的刷新函数
// Renders the node in a given pass. public void renderOpaque(RenderView view, GL11 gl) { GridCamera camera = mCamera; int selectedSlotIndex = mInputProcessor.getCurrentSelectedSlot(); computeVisibleItems(); gl.glMatrixMode(GL11.GL_MODELVIEW); gl.glLoadIdentity(); GLU.gluLookAt(gl, -camera.mEyeX, -camera.mEyeY, -camera.mEyeZ, -camera.mLookAtX, -camera.mLookAtY, -camera.mLookAtZ, camera.mUpX, camera.mUpY, camera.mUpZ); view.setAlpha(1.0f); if (mSelectedAlpha != 1.0f) { gl.glEnable(GL11.GL_BLEND); gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); view.setAlpha(mSelectedAlpha); } if (selectedSlotIndex != Shared.INVALID) { mTargetAlpha = 0.0f; } else { mTargetAlpha = 1.0f; } mDrawManager.prepareDraw(mBufferedVisibleRange, mVisibleRange, selectedSlotIndex, mInputProcessor.getCurrentFocusSlot(), mInputProcessor.getCurrentScaledSlot(), mInputProcessor.isFocusItemPressed(), mInputProcessor.getScale(), mInputProcessor.getScaleGestureDetector(), mFeedAboutToChange); if (mSelectedAlpha != 0.0f) { mDrawManager.drawThumbnails(view, gl, mState); } if (mSelectedAlpha != 1.0f) { gl.glDisable(GL11.GL_BLEND); } // We draw the selected slotIndex. if (selectedSlotIndex != Shared.INVALID) { mDrawManager.drawFocusItems(view, gl, mZoomValue, mSlideshowMode, mTimeElapsedSinceView); mCurrentFocusItemWidth = mDrawManager.getFocusQuadWidth(); mCurrentFocusItemHeight = mDrawManager.getFocusQuadHeight(); } view.setAlpha(mSelectedAlpha); }
在这里面,我们找到了实质性刷界面的函数
ComputerVisibleItem();计算可见项目
mDrawManager.prepareDraw准备工作
mDrawManager.drawThumnails画缩略图
在这里我们看到了缩略图显示刷新,但是还有一些疑问,数据从哪里来的,而且这里只有一个界面的显示,其他的界面如何显示的?下次探讨吧。