先上个效果图看看(太卡,没法搞动态的啊,我去) :
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了,好了大伙儿下载源码试试吧~ 传送门:戳这里