by: andy.xie 转载请注明出处 http://blog.youkuaiyun.com/xiexh0921/article/details/7929847
1,概述:
Launcher桌面由Workspace.java包含Celllayout.java构成,一个celllayout就是一个桌面,默认5个。 Workspace和celllayout都继承于viewgroup。
2,获得Touch坐标:
Launcher.java为activity,workspace是viewgroup。所以在activity中会注册一个scroller来记录滑动状态,scroller start后workspace中的computeScroll() 会接收到scroller的状态。这里获取到 mTouchX = mScrollX = mScroller.getCurrX();。Launcher会对滑动事件进行管理使得每次都能切屏或返回,而不会出现滑动到一半的状态。
3,重绘view:
scroller start的时候会不断重绘view直到scroller结束(mScroller.computeScrollOffset()返回false),所以要实现效果只需直接修改dispathDraw函数。dispathDraw和onDraw的区别是一个是画自己一个是画子view,dispathDraw在onDraw之后执行。
这里我们要实现伪3D效果,所以不用opengl,根据上面得到的mTouchX直接用camera和matrix配合就可以实现了。根据上面得到的mTouchX计算出子view需要旋转的角度,隐藏childview后,1)用drawchild画子view;2)直接抓取子view的bitmap(getChildAt(0).buildDrawingCache();Bitmap bitmap = getChildAt(0).getDrawingCache();)然后画到workspace的canvas。
4,实现代码:
上面大概的讲了下原理,下面给出实现代码,其实很简单,只需要修改Launcher2中的workspace.java就可以实现了。
@Override
protected void dispatchDraw(Canvas canvas) {
boolean restore = false;
int restoreCount = 0;
// ViewGroup.dispatchDraw() supports many features we don't need:
// clip to padding, layout animation, animation listener, disappearing
// children, etc. The following implementation attempts to fast-track
// the drawing dispatch by drawing only what we know needs to be drawn.
boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN;
// If we are not scrolling or flinging, draw only the current screen
if (fastDraw) {
//add by andy.xie 20120831
getChildAt(mCurrentScreen).setBackgroundResource(android.R.color.transparent);
drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());
} else {
final long drawingTime = getDrawingTime();
final float scrollPos = (float) mScrollX / getWidth();
final int leftScreen = (int) scrollPos;
final int rightScreen = leftScreen + 1;
//edit by andy.xie 20120831
// if (leftScreen >= 0) {
// drawChild(canvas, getChildAt(leftScreen), drawingTime);
// }
// if (scrollPos != leftScreen && rightScreen < getChildCount()) {
// drawChild(canvas, getChildAt(rightScreen), drawingTime);
// }
//add by andy.xie 20120831
Camera camera = new Camera();
Matrix matrix = new Matrix();
int width = getWidth();
int height = getHeight();
float rotateY = ((float)(mTouchX % width) / width) * 90;
if(rotateY < 0) rotateY = 0;
if(rotateY > 90) rotateY = 90;
if(rotateY > 90) rotateY = 90;
//
Log.d("xxh", "x=" + mTouchX + " rotateY=" + rotateY + " scrollPos=" + scrollPos);
if (leftScreen >= 0) {
//
canvas.save();
camera.save();
//camera.translate(0, 0, mWidth/2);
camera.rotateY(-rotateY);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-width * ((int)scrollPos + 1), -height/2);
matrix.postTranslate(width * ((int)scrollPos + 1), height/2);
//
canvas.concat(matrix);
getChildAt(leftScreen).setBackgroundResource(android.R.drawable.screen_background_dark_transparent);
drawChild(canvas, getChildAt(leftScreen), drawingTime);
getChildAt(leftScreen).setBackgroundResource(android.R.drawable.screen_background_dark_transparent);
drawChild(canvas, getChildAt(leftScreen), drawingTime);
canvas.restore();
}
if (scrollPos != leftScreen && rightScreen < getChildCount()) {
Matrix matrix2 = new Matrix();
canvas.save();
camera.save();
//camera.translate(0, 0, mWidth/2);
camera.rotateY(90-rotateY);
camera.getMatrix(matrix2);
camera.restore();
matrix2.preTranslate(-width * ((int)scrollPos + 1), -height/2);
matrix2.postTranslate(width * ((int)scrollPos + 1), height/2);
//
canvas.concat(matrix2);
getChildAt(rightScreen).setBackgroundResource(android.R.drawable.screen_background_dark_transparent);
canvas.concat(matrix2);
getChildAt(rightScreen).setBackgroundResource(android.R.drawable.screen_background_dark_transparent);
drawChild(canvas, getChildAt(rightScreen), drawingTime);
canvas.restore();
}
}
if (restore) {
canvas.restoreToCount(restoreCount);
}
}