触摸转动布局 类似酷狗音乐的那种

时间:2021-03-05 05:01:56

 先上个效果图看看(太卡,没法搞动态的啊,我去)  :

触摸转动布局 类似酷狗音乐的那种


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了,好了大伙儿下载源码试试吧~  传送门:戳这里