首先GalleryActivity.java里面设置setContentView(R.layout.main); 该布局里面有一个GLRootView, 该类继承自GLSurfaceView。所以整个界面的内容的显示是在GLSurfaceView上的。该类的用法框架如下:
mSurfaceView = new GLSurfaceView(this);
setContentView(mSurfaceView );
mSurfaceView.setRenderer(new Renderer() {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.e(TAG, "onSurfaceCreated");
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.e(TAG, "onSurfaceChanged");
}
@Override
public void onDrawFrame(GL10 gl) {
Log.e(TAG, "onDrawFrame");
}
});
只要在GLSurfaceView里设置一个GLSurfaceView.Renderer接口的类即可通过监听来在GLSurfaceView界面上通过onDrawFrame画出图像来。
还需要设置渲染模式setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);此时通过GLSurfaceView的requestRender()方法即可回调onDrawFrame画出每一帧。
在图库中根界面是GLRootView,它实现接口GLRoot。所有它上面的视图都继承自GLView。
下面以AlbumPage页面为例说明显示过程。
AlbumPage相当于一个Activity,它的父类中有真正Activity(GalleryActivity)的实例,并且它能通过该Activity获得在GalleryActivity中的布局GLRootView。
在AlbumPage类中,首先实例化了一个类GLView mRootPane =new GLView();该类重写了父类的onLayout和render。
在AlbumPage的onCreate的initializeViews方法中又实例化了一个view(SlotView),并将它加入mRootView中:mRootPane.addComponent(mSlotView);
进入GLView中的addComponent方法可以看到它做了几件事。
public void addComponent(GLView component) {
// Make sure the component doesn't have a parent currently.
if (component.mParent != null) throw new IllegalStateException();
// Build parent-child links
if (mComponents == null) {
mComponents = new ArrayList<GLView>();
}
mComponents.add(component);
component.mParent = this;
// If this is added after we have a root, tell the component.
if (mRoot != null) {
component.onAttachToRoot(mRoot);
}
}
第一建了个ArrayList,并把加入的子view放入该arraylist中,然后设置该子view的父亲为this。最后通过component.onAttachToRoot(mRoot);将mRoot设到子view中。
接着在onResume中setContentPane(mRootPane);
protected void setContentPane(GLView content) {
mContentPane = content;
if (mIntroAnimation != null) {
mContentPane.setIntroAnimation(mIntroAnimation);
mIntroAnimation = null;
}
mContentPane.setBackgroundColor(getBackgroundColor());
mActivity.getGLRoot().setContentPane(mContentPane);
}
进入到ActivityState中可以看到,这个时候设置mContentPane的背景颜色,并调用mActivity.getGLRoot().setContentPane(mContentPane);将mContentPane设到GLRootView中。
进入到GLRootView的setContentPane方法中
public void setContentPane(GLView content) {
if (mContentView == content) return;
if (mContentView != null) {
if (mInDownState) {
long now = SystemClock.uptimeMillis();
MotionEvent cancelEvent = MotionEvent.obtain(
now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
mContentView.dispatchTouchEvent(cancelEvent);
cancelEvent.recycle();
mInDownState = false;
}
mContentView.detachFromRoot();
BasicTexture.yieldAllTextures();
}
mContentView = content;
if (content != null) {
content.attachToRoot(this);
requestLayoutContentPane();
}
}
这里,如果新设置的跟视图与原来的相同直接返回。如果不同,但原来的不为空,先要把原来的跟视图detachFromRoot。让它的mRoot为空,遍历所有子视图,将子视图的mRoot都设为空。这时将新的跟视图设到GLRootView中。并attachToRoot,将该根视图的mRoot置为GLRootView。接下来requestLayoutContentPane()。顾名思义调用布局根视图的方法。后面的调用流程如下图所示:
GLRootView requestLayoutContentPane
|
V
GLRootView requestRender
|
V
GLSurfaceView requestRender
|
V
GLRootView onDrawFrame
|
V
GLRootView onDrawFrameLocked
| |
V V
GLRootView layoutContentPane mContentView.render()
| |
V V
GLRootView mContentView.layout(); 调用mContentView子view的render
后面需要再次要求layout和render的主要途径有两个:
对每个view进行invalidate或者requestLayout。
Invalidate会调用GLRootView的requestRender。
requestLayout会调用GLRootView的requestLayoutContentPane。