iphone-ibooks的书橱界面和商城界面是两个背靠背的视图,可以通过左右伪3D旋转切换前后界面,我现在写了一个安卓版本的rollbackview,效果如下:
源代码如下:
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.Scroller;
public class rollbackview extends RelativeLayout{
Context mContext;int mwidth,mheight,zdistance;float radius;Scroller ms;
Camera mc;Matrix mm;float lastx,lasty;Boolean intercepyed,handled,hadcharged;
View child1,child2;
View aboveview,startView;
public rollbackview(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO 自动生成的构造函数存根
mContext=context;intercepyed=false;handled=false;hadcharged=false;
ms=new Scroller(context);
mc=new Camera();mm=new Matrix();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO 自动生成的方法存根
if(ev.getAction()==0){lastx=ev.getX();lasty=ev.getY();intercepyed=false;hadcharged=false;handled=false;startView=aboveview;}
if(ev.getAction()==2){float movex=ev.getX();float movey=ev.getY();
float offdx=movex-lastx;float dy=movey-lasty;
if(!hadcharged){
if(Math.abs(offdx)<10&&Math.abs(dy)<10){
return true;
}else{hadcharged=true;}
}
if(!handled){
handled=true;
if(Math.abs(offdx)>Math.abs(dy)){intercepyed=true;}else{
intercepyed=false;
}}}
if(intercepyed){
float offdx=ev.getX()-lastx;
if(ev.getAction()==1){
//currentView=aboveview;
MotionEvent cancel=MotionEvent.obtain(ev);
cancel.setAction(3);
startView.dispatchTouchEvent(cancel);
cancel.recycle();
int time=(int) (mwidth/2-Math.abs((mwidth/2-Math.abs(offdx))));
if(Math.abs(offdx)>mwidth/2){
if(offdx<0){ms.startScroll((int)offdx, 0, -mwidth-(int)(offdx), 0, time);}else{
ms.startScroll((int)offdx, 0, mwidth-(int)(offdx), 0, time);
}}
else{
ms.startScroll((int)offdx, 0, -(int)(offdx), 0, time);}
invalidate();return true;
}setpercent(offdx/mwidth,(int)offdx);
}else{
startView.dispatchTouchEvent(ev);
}
return true;//super.dispatchTouchEvent(ev);
}
private void setpercent(float percent,int offx) {
// TODO 自动生成的方法存根
//mm.reset();
radius=percent*180;
mc.save();
mc.translate(0, 0, (float) (zdistance*(0.5f-Math.abs(0.5-Math.abs(percent)))));
if(Math.abs(radius)>90){
aboveview=startView==child1?child2:child1;
mc.rotateY(radius-180);
}else{
aboveview=startView;
mc.rotateY(radius);}
mc.getMatrix(mm);
mm.preTranslate(-mwidth/2,-mheight/2);
mm.postTranslate(mwidth/2,mheight/2);
mc.restore();
invalidate();
}
@Override
public void computeScroll() {
// TODO 自动生成的方法存根
super.computeScroll();
if(ms.computeScrollOffset()){
int x=ms.getCurrX();
setpercent((float)x/mwidth,x);
}
}
@Override
protected void onFinishInflate() {
// TODO 自动生成的方法存根
super.onFinishInflate();
child1=getChildAt(0);child2=getChildAt(1);
aboveview=startView=child2;
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
// TODO 自动生成的方法存根
if(child!=aboveview){return false;}else{
canvas.save();
canvas.concat(mm);
boolean draw=super.drawChild(canvas, aboveview,getDrawingTime());
canvas.restore();
return draw;
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO 自动生成的方法存根
super.onLayout(changed, l, t, r, b);
mwidth=r-l;mheight=b-t;zdistance=mwidth/2;
}
}
主要思路就是:重写了drawchild函数,在绘图前反转canvas,矩阵由滑动距离决定,