package moe.codeest.enviews; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.CornerPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.RectF; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.animation.AnticipateInterpolator; import com.shuyu.gsyvideoplayer.R; /** * Created by codeest on 16/11/7. * */ public class ENPlayView extends View { public static int STATE_PLAY = 0; public static int STATE_PAUSE = 1; public static int DEFAULT_LINE_COLOR = Color.WHITE; public static int DEFAULT_BG_LINE_COLOR = 0xfffafafa; public static int DEFAULT_LINE_WIDTH = 4; public static int DEFAULT_BG_LINE_WIDTH = 4; public static int DEFAULT_DURATION = 1200; private int mCurrentState = STATE_PAUSE; private Paint mPaint, mBgPaint; private int mWidth, mHeight; private int mCenterX, mCenterY; private int mCircleRadius; private RectF mRectF, mBgRectF; private float mFraction = 1; private Path mPath, mDstPath; private PathMeasure mPathMeasure; private float mPathLength; private int mDuration; public ENPlayView(Context context) { super(context); } public ENPlayView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.play); int lineColor = ta.getColor(R.styleable.play_play_line_color, DEFAULT_LINE_COLOR); int bgLineColor = ta.getColor(R.styleable.play_play_bg_line_color, DEFAULT_BG_LINE_COLOR); int lineWidth = ta.getInteger(R.styleable.play_play_line_width, dp2px(DEFAULT_LINE_WIDTH)); int bgLineWidth = ta.getInteger(R.styleable.play_play_bg_line_width, dp2px(DEFAULT_BG_LINE_WIDTH)); ta.recycle(); setLayerType(View.LAYER_TYPE_SOFTWARE, null); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setColor(lineColor); mPaint.setStrokeWidth(lineWidth); mPaint.setPathEffect(new CornerPathEffect(1)); mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBgPaint.setStyle(Paint.Style.STROKE); mBgPaint.setStrokeCap(Paint.Cap.ROUND); mBgPaint.setColor(bgLineColor); mBgPaint.setStrokeWidth(bgLineWidth); mPath = new Path(); mDstPath = new Path(); mPathMeasure = new PathMeasure(); mDuration = DEFAULT_DURATION; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w * 9 / 10; mHeight = h * 9 / 10; mCircleRadius = mWidth / dp2px(4); mCenterX = w / 2; mCenterY = h / 2; mRectF = new RectF(mCenterX - mCircleRadius, mCenterY + 0.6f * mCircleRadius, mCenterX + mCircleRadius, mCenterY + 2.6f * mCircleRadius); mBgRectF = new RectF(mCenterX - mWidth / 2 ,mCenterY - mHeight / 2 ,mCenterX + mWidth / 2, mCenterY + mHeight / 2); mPath.moveTo(mCenterX - mCircleRadius, mCenterY + 1.8f * mCircleRadius); mPath.lineTo(mCenterX - mCircleRadius, mCenterY - 1.8f * mCircleRadius); mPath.lineTo(mCenterX + mCircleRadius, mCenterY); mPath.close(); mPathMeasure.setPath(mPath, false); mPathLength = mPathMeasure.getLength(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(mCenterX, mCenterY, mWidth / 2, mBgPaint); if (mFraction < 0) { //嗷~~ 弹性部分 canvas.drawLine(mCenterX + mCircleRadius, mCenterY - 1.6f * mCircleRadius + 10 * mCircleRadius * mFraction, mCenterX + mCircleRadius, mCenterY + 1.6f * mCircleRadius + 10 * mCircleRadius * mFraction, mPaint); canvas.drawLine(mCenterX - mCircleRadius, mCenterY - 1.6f * mCircleRadius, mCenterX - mCircleRadius, mCenterY + 1.6f * mCircleRadius, mPaint); canvas.drawArc(mBgRectF, -105 , 360 , false, mPaint); } else if (mFraction <= 0.3) { //嗷~~ 右侧直线和下方曲线 canvas.drawLine(mCenterX + mCircleRadius, mCenterY - 1.6f * mCircleRadius + mCircleRadius * 3.2f / 0.3f * mFraction, mCenterX + mCircleRadius, mCenterY + 1.6f * mCircleRadius, mPaint); canvas.drawLine(mCenterX - mCircleRadius, mCenterY - 1.6f * mCircleRadius, mCenterX - mCircleRadius, mCenterY + 1.6f * mCircleRadius, mPaint); if (mFraction != 0) canvas.drawArc(mRectF, 0f, 180f / 0.3f * mFraction, false, mPaint); canvas.drawArc(mBgRectF, -105 + 360 * mFraction, 360 * (1 - mFraction), false, mPaint); } else if (mFraction <= 0.6) { //嗷~~ 下方曲线和三角形 canvas.drawArc(mRectF, 180f / 0.3f * (mFraction - 0.3f), 180 - 180f / 0.3f * (mFraction - 0.3f), false , mPaint); mDstPath.reset(); //mDstPath.lineTo(0 ,0); mPathMeasure.getSegment(0.02f * mPathLength, 0.38f * mPathLength + 0.42f * mPathLength / 0.3f * (mFraction - 0.3f) , mDstPath, true); canvas.drawPath(mDstPath, mPaint); canvas.drawArc(mBgRectF, -105 + 360 * mFraction, 360 * (1 - mFraction), false, mPaint); } else if (mFraction <= 0.8) { //嗷~~ 三角形 mDstPath.reset(); //mDstPath.lineTo(0 ,0); mPathMeasure.getSegment(0.02f * mPathLength + 0.2f * mPathLength / 0.2f * (mFraction - 0.6f) , 0.8f * mPathLength + 0.2f * mPathLength / 0.2f * (mFraction - 0.6f) , mDstPath, true); canvas.drawPath(mDstPath, mPaint); canvas.drawArc(mBgRectF, -105 + 360 * mFraction, 360 * (1 - mFraction), false, mPaint); } else { //嗷~~ 弹性部分 mDstPath.reset(); //mDstPath.lineTo(0 ,0); mPathMeasure.getSegment(10 * mCircleRadius * (mFraction - 1) , mPathLength , mDstPath, true); canvas.drawPath(mDstPath, mPaint); } } public void play() { if (mCurrentState == STATE_PLAY) { return; } mCurrentState = STATE_PLAY; ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.f, 100.f); valueAnimator.setDuration(mDuration); valueAnimator.setInterpolator(new AnticipateInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mFraction = 1 - valueAnimator.getAnimatedFraction(); invalidate(); } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } } public void pause() { if (mCurrentState == STATE_PAUSE) { return; } mCurrentState = STATE_PAUSE; ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.f, 100.f); valueAnimator.setDuration(mDuration); valueAnimator.setInterpolator(new AnticipateInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mFraction = valueAnimator.getAnimatedFraction(); invalidate(); } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } } public int getCurrentState() { return mCurrentState; } public void setDuration(int duration) { mDuration = duration; } private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics()); } }