系统自带的activity切换效果不尽如人意,需要我们自己定义,我们用属性动画来实现。
首先抽象一个父类Activity :AnimatedDoorActivity
public abstract class AnimatedDoorActivity extendsActivity { private AnimatedDoorLayout mAnimated; protected int mDoorType; @Override protected void onCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(layoutResId()); //获取到根view FrameLayout activityRoot= (FrameLayout)findViewById(android.R.id.content); View parent = activityRoot.getChildAt(0); // 将子类中的layout加到根view mAnimated = new AnimatedDoorLayout(this); activityRoot.removeView(parent); activityRoot.addView(mAnimated,parent.getLayoutParams()); mAnimated.addView(parent); //动画类型 mDoorType = getIntent().getIntExtra("door_type",AnimatedDoorLayout.HORIZONTAL_DOOR); mAnimated.setDoorType(mDoorType); //将根layout的属性从get方法获取到的值(0)在600ms内变为1 ObjectAnimator animator= ObjectAnimator.ofFloat(mAnimated,ANIMATED_DOOR_LAYOUT_FLOAT_PROPERTY,1).setDuration(600); animator.start(); } protected abstract intlayoutResId(); @Override public void onBackPressed(){ ObjectAnimator animator= ObjectAnimator.ofFloat(mAnimated,ANIMATED_DOOR_LAYOUT_FLOAT_PROPERTY,0).setDuration(600); animator.addListener(newAnimatorListenerAdapter(){ @Override public void onAnimationEnd(Animatoranimation){ finish();} });
animator.start(); } private static final Property<AnimatedDoorLayout,Float>ANIMATED_DOOR_LAYOUT_FLOAT_PROPERTY = new Property<AnimatedDoorLayout,Float>(Float.class,"ANIMATED_DOOR_LAYOUT_FLOAT_PROPERTY"){ @Override public void set(AnimatedDoorLayoutlayout,Float value){ layout.setProgress(value); } @Override public Float get(AnimatedDoorLayoutlayout){ return layout.getProgress(); } };
@Override public void finish(){ super.finish(); overridePendingTransition(0,0); } } 接下来就是主要工作的类,实际上个是Viewgroup public class AnimatedDoorLayoutextends ViewGroup { private static final String TAG = "AnimatedDoorLayout"; static final booleanIS_JBMR2 = Build.VERSION.SDK_INT== Build.VERSION_CODES.JELLY_BEAN_MR2; public static final int HORIZONTAL_DOOR = 1; public static final int VERTICAL_DOOR = 2; private Rect mRect = new Rect(); private int mOriginalWidth; private int mOriginalHeight; private int mDoorType; private float mProgress; private Bitmap mFullBitmap; public AnimatedDoorLayout(Contextcontext){ super(context); } public AnimatedDoorLayout(Contextcontext,AttributeSet attrs){ super(context,attrs); } public AnimatedDoorLayout(Contextcontext,AttributeSet attrs,int defStyle) { super(context,attrs,defStyle); } public void setDoorType(intdoorType){ mDoorType = doorType; } public float getProgress(){ return mProgress; } public void setProgress(floatprogress){//属性动画更新该 Viewgroup的属性值 然后刷新界面 mProgress = progress; invalidate(); } @Override protected boolean addViewInLayout(Viewchild,int index, LayoutParams params,boolean preventRequestLayout) { throwCustomException(getChildCount()); boolean returnValue = super.addViewInLayout(child,index,params,preventRequestLayout); return returnValue; } @Override public void addView(Viewchild,int index, LayoutParams params){ throwCustomException(getChildCount()); super.addView(child,index,params); } @Override protected void onMeasure(intwidthMeasureSpec,int heightMeasureSpec) { View child = getChildAt(0); measureChild(child,widthMeasureSpec,heightMeasureSpec); setMeasuredDimension(widthMeasureSpec,heightMeasureSpec); } @Override protected void onLayout(booleanchanged,int l, int t,int r, int b){ View child = getChildAt(0); child.layout(0,0,child.getMeasuredWidth(),child.getMeasuredHeight()); updateDoor(); } private void throwCustomException(intnumOfChildViews){ if (numOfChildViews == 1){ throw new IllegalArgumentException("only one child please"); } } private void updateDoor(){ prepareDoor(); invalidate(); } private void prepareDoor(){ if(isInEditMode()){ return; } mOriginalWidth = getMeasuredWidth(); mOriginalHeight = getMeasuredHeight(); if (IS_JBMR2){//首次将整个 用户的layout绘制到屏幕上 mFullBitmap = Bitmap.createBitmap(mOriginalWidth,mOriginalHeight,Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(mFullBitmap); getChildAt(0).draw(canvas); } } @Override protected void dispatchDraw(Canvascanvas){//刷新,该动画效果类似开门,分为垂直和水平开门 if(isInEditMode()|| mProgress>= 1f){ super.dispatchDraw(canvas); return; } int delta; if(mDoorType== VERTICAL_DOOR){ delta =(int)((mOriginalHeight/2)*mProgress); } else { delta =(int)((mOriginalWidth/2)*mProgress); } //1st door第一个门 canvas.save(); if(mDoorType== VERTICAL_DOOR){ mRect.set(0,0,mOriginalWidth,delta); } else { mRect.set(0,0,delta,mOriginalHeight); } if (IS_JBMR2){ canvas.drawBitmap(mFullBitmap,mRect,mRect,null); } else { canvas.clipRect(mRect); super.dispatchDraw(canvas); } canvas.restore(); //2nd door第二个门 canvas.save(); if(mDoorType== VERTICAL_DOOR){//根据属性值计算要截取bitmap的区域 left、top、right、buttom mRect.set(0,mOriginalHeight - delta,mOriginalWidth,mOriginalHeight); } else { mRect.set(mOriginalWidth- delta,0,mOriginalWidth,mOriginalHeight); } if (IS_JBMR2){ canvas.drawBitmap(mFullBitmap,mRect,mRect,null); } else { canvas.clipRect(mRect); super.dispatchDraw(canvas); } canvas.restore(); } }
最后附上开源项目地址,内有demo apk
https://github.com/flavienlaurent/activityanimation