先上个效果图看看(太卡,没法搞动态的啊,我去) :
package com.eversky.mfkg; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.Animator.AnimatorListener; import com.nineoldandroids.animation.ValueAnimator; import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener; public class TouchSlideLayout extends FrameLayout { /**最大旋转角度*/ private final static float DRAG_MAX_DEGREE = 25.0f; /** 旋转的角度 */ private float mCanvasRotateDegree = 0f; private int mWidth = 0; private int mLastX; /** 是否开始拖动事件 */ private boolean mDragStart; private VelocityTracker mVelocityTracker; private int mTouchSlop; private int mMinFlingVelocity; public TouchSlideLayout(Context context) { super(context); init(context); } public TouchSlideLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public TouchSlideLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { setBackgroundColor(getResources().getColor(android.R.color.transparent)); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mMinFlingVelocity = ViewConfiguration.get(context) .getScaledMinimumFlingVelocity(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = getMeasuredWidth(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { float x = ev.getX(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = (int) ev.getX(); break; case MotionEvent.ACTION_MOVE: float movedX = x - mLastX; if (Math.abs(movedX) > mTouchSlop) { mDragStart = true; return true; } break; case MotionEvent.ACTION_UP: break; default: break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: float x = event.getX(); float movedX = x - mLastX; if (!mDragStart && Math.abs(movedX) > mTouchSlop) { mDragStart = true; } if (mDragStart) { mCanvasRotateDegree += (movedX / mWidth) * DRAG_MAX_DEGREE; invalidate(); mLastX = (int) x; } break; case MotionEvent.ACTION_UP: mDragStart = false; mVelocityTracker.computeCurrentVelocity(1000); float vx = mVelocityTracker.getXVelocity(); if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } float toDegree = vx > 0 ? 90 : -90; if (Math.abs(vx) > mMinFlingVelocity) { if (mCanvasRotateDegree > -DRAG_MAX_DEGREE && mCanvasRotateDegree < 0) { if (vx > 0) { backToNormal(); } else { dismiss(toDegree); } } else if (mCanvasRotateDegree > 0 && mCanvasRotateDegree < DRAG_MAX_DEGREE) { if (vx < 0) { backToNormal(); } else { dismiss(toDegree); } } } else { backToNormal(); } break; default: break; } return true; } private void dismiss(float toDegree) { ValueAnimator animator = ValueAnimator.ofFloat(mCanvasRotateDegree, toDegree); animator.setDuration(300); animator.setInterpolator(new AccelerateInterpolator()); animator.start(); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator arg0) { mCanvasRotateDegree = (Float) arg0.getAnimatedValue(); invalidate(); } }); animator.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator arg0) { } @Override public void onAnimationRepeat(Animator arg0) { } @Override public void onAnimationEnd(Animator arg0) { setVisibility(View.GONE); if (mDismissListener != null) { mDismissListener.OnDismiss(); } } @Override public void onAnimationCancel(Animator arg0) { } }); } private void backToNormal() { ValueAnimator animator = ValueAnimator.ofFloat(mCanvasRotateDegree, 0); animator.setDuration(500l); animator.setInterpolator(new DecelerateInterpolator()); animator.start(); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator arg0) { mCanvasRotateDegree = (Float) arg0.getAnimatedValue(); invalidate(); } }); } @Override protected void dispatchDraw(Canvas canvas) { canvas.save(); int px = getWidth() / 2; int py = getHeight(); canvas.rotate(mCanvasRotateDegree, px, py * 2f); super.dispatchDraw(canvas); canvas.restore(); } interface IDismissListener { public void OnDismiss(); } private IDismissListener mDismissListener; public void setOnDismissListener(IDismissListener dismissListener) { mDismissListener = dismissListener; } }
原理:很简单,就是旋转画布,在dispatchDraw当中控制旋转,这样childview被一起旋转了,然后控制下触摸事件,差不多就是这样了,肯定还有完善的地方。
用法:就是在你的布局最外层套一个这个layout,如果用在Activity的布局中,把Activity设置成透明主题。这样就可以看到前一个Activity了,好了大伙儿下载源码试试吧~ 传送门:戳这里