package com.liuguilin.lovewallpaper.view; /* * 项目名: LoveWallpaper * 包名: com.liuguilin.lovewallpaper.view * 文件名: PaperShredderView * 创建者: LGL * 创建时间: 2017/1/16 19:11 * 描述: 碎纸机 */ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import android.view.animation.LinearInterpolator; import com.liuguilin.lovewallpaper.R; import java.util.ArrayList; import java.util.List; public class PaperShredderView extends View { private Paint mPaint; private RectF rectFPaper; private RectF rectFHost; private Path pathHostHead; private ArgbEvaluator evaluator; private float mPaddingLR; private int paperSlipCount = 12; private int paperPieceCount = 35; private List<Float> randomHighs = new ArrayList<>(); private List<Float> randomQuadWidths = new ArrayList<>(); private List<Float> randomQuadHighs = new ArrayList<>(); private List<Float> randomQuadDirection = new ArrayList<>(); private List<Float> PaperPiecerandX = new ArrayList<>(); private List<Float> PaperPiecerandY = new ArrayList<>(); private List<Float> PaperPiecerandAngle = new ArrayList<>(); private List<Float> PaperPiecerandRadius = new ArrayList<>(); private int bgColor = Color.rgb(213, 57, 59); private int paperColor = Color.WHITE; private int paperEnterColor = Color.rgb(148, 146, 148); private String title = "Deleting"; boolean sherderTextShadow = true; private int titleColor = Color.WHITE; private SHREDEDTYPE mShrededType = SHREDEDTYPE.Slip; boolean sherderProgress = true; public void setTitle(String title) { this.title = title; } public void setShrededType(SHREDEDTYPE m) { this.mShrededType = m; } public void setSherderProgress(boolean show) { this.sherderProgress = show; } public void setTextColor(int color) { this.titleColor = color; invalidate(); } public void setBgColor(int color) { this.bgColor = color; invalidate(); } public void setPaperColor(int color) { this.paperColor = color; invalidate(); } public void setTextShadow(boolean show) { this.sherderTextShadow = show; invalidate(); } public void setPaperEnterColor(int color) { this.paperEnterColor = color; } public PaperShredderView(Context context) { this(context, null); } public PaperShredderView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PaperShredderView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } private void init(AttributeSet attrs) { TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.PaperShredderView); if (typedArray != null) { bgColor = typedArray.getColor(R.styleable.PaperShredderView_sherderBgColor, bgColor); titleColor = typedArray.getColor(R.styleable.PaperShredderView_sherderTextColor, titleColor); paperColor = typedArray.getColor(R.styleable.PaperShredderView_sherderPaperColor, paperColor); paperEnterColor = typedArray.getColor(R.styleable.PaperShredderView_sherderPaperEnterColor, paperEnterColor); title = typedArray.getString(R.styleable.PaperShredderView_sherderText); int type = typedArray.getInteger(R.styleable.PaperShredderView_sherderType, 0); if (type == 0) { mShrededType = SHREDEDTYPE.Slip; } else if (type == 1) { mShrededType = SHREDEDTYPE.Piece; } else { mShrededType = SHREDEDTYPE.Slip; } if (title == null) { title = "Deleting"; } sherderProgress = typedArray.getBoolean(R.styleable.PaperShredderView_sherderProgress, true); sherderTextShadow = typedArray.getBoolean(R.styleable.PaperShredderView_sherderTextShadow, sherderTextShadow); typedArray.recycle(); } initPaint(); } private void initPaint() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL); rectFPaper = new RectF(); rectFHost = new RectF(); pathHostHead = new Path(); evaluator = new ArgbEvaluator(); } private void drawPaper(Canvas canvas) { mPaint.setColor(paperColor); rectFPaper.top = 0 + mAnimatedValue * getMeasuredHeight() / 3f * 0.8f; rectFPaper.bottom = getMeasuredHeight() / 3f + mAnimatedValue * getMeasuredHeight() / 3f * 0.8f; rectFPaper.left = mPaddingLR; rectFPaper.right = getMeasuredWidth() - mPaddingLR; canvas.drawRect(rectFPaper, mPaint); } private void drawHost(Canvas canvas) { rectFHost.top = getMeasuredHeight() / 2f - getMeasuredHeight() / 3f / 2f - 10; rectFHost.bottom = getMeasuredHeight() / 2f + getMeasuredHeight() / 3f / 2f; rectFHost.left = 0; rectFHost.right = getMeasuredWidth(); mPaint.setColor(bgColor); canvas.drawRoundRect(rectFHost, mPaddingLR / 2, mPaddingLR / 2, mPaint); mPaint.setColor(Color.argb(80, 50, 50, 50));//shadow canvas.drawRoundRect(rectFHost, mPaddingLR / 2, mPaddingLR / 2, mPaint); rectFHost.bottom = rectFHost.bottom - mPaddingLR / 3; mPaint.setColor(bgColor); canvas.drawRoundRect(rectFHost, mPaddingLR / 3, mPaddingLR / 3, mPaint); pathHostHead.reset(); pathHostHead.moveTo(rectFHost.left, rectFHost.top); pathHostHead.lineTo(rectFHost.right, rectFHost.top); pathHostHead.lineTo(rectFHost.right, rectFHost.top + mPaddingLR / 3 / 2); pathHostHead.quadTo( rectFHost.right, rectFHost.top + mPaddingLR / 3, rectFHost.right - mPaddingLR / 3, rectFHost.top + mPaddingLR / 3 ); pathHostHead.lineTo( rectFHost.left + mPaddingLR / 3, rectFHost.top + mPaddingLR / 3); pathHostHead.quadTo(rectFHost.left, rectFHost.top + mPaddingLR / 3, rectFHost.left, rectFHost.top + mPaddingLR / 3 / 2 ); pathHostHead.close(); mPaint.setColor(paperEnterColor); canvas.drawPath(pathHostHead, mPaint); mPaint.setColor(titleColor); mPaint.setTextSize(mPaddingLR); if (sherderTextShadow) mPaint.setShadowLayer(2, 4, 4, Color.rgb(50, 50, 50)); canvas.drawText(title, rectFHost.centerX() - getFontlength(mPaint, title) / 2, rectFHost.centerY() + getFontHeight(mPaint, title) / 3, mPaint); if (sherderProgress) { mPaint.setColor(Color.argb(100, 255, 255, 255)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(dip2px(1)); float marginText = getFontlength(mPaint, title) / 2 + getFontHeight(mPaint, title) * 0.75f; canvas.drawCircle(rectFHost.centerX() - marginText, rectFHost.centerY(), getFontHeight(mPaint, title) / 2, mPaint); mPaint.setColor(titleColor); RectF rectF = new RectF(rectFHost.centerX() - getFontHeight(mPaint, title) / 2 - marginText , rectFHost.centerY() - getFontHeight(mPaint, title) / 2, rectFHost.centerX() + getFontHeight(mPaint, title) / 2 - marginText, rectFHost.centerY() + getFontHeight(mPaint, title) / 2); canvas.drawArc(rectF, 360 * mAnimatedValue, 100 , false, mPaint);//第四个参数是否显示半径 } mPaint.setStrokeWidth(0); mPaint.setStyle(Paint.Style.FILL); mPaint.setShadowLayer(0, 0, 0, Color.WHITE); } private void drawPaperSlip(Canvas canvas) { Path PaperSlip = new Path(); float paperSlipwidth = rectFPaper.width() / paperSlipCount; float paperSlipspace = paperSlipwidth / 7f; float animatedValue = mAnimatedValue; mPaint.setColor(paperColor); for (int i = 0; i < randomQuadHighs.size(); i++) { PaperSlip.reset(); PaperSlip.moveTo(rectFPaper.left + i * paperSlipwidth + paperSlipspace, rectFPaper.bottom ); PaperSlip.lineTo(rectFPaper.left + (i + 1) * paperSlipwidth - paperSlipspace, rectFPaper.bottom ); float paperSlipHigh = rectFPaper.height() * 2 / 3f + rectFPaper.height() / 3f * randomHighs.get(i); float randomQuadWidth = this.randomQuadWidths.get(i) * paperSlipspace * 2.5f * animatedValue; if (randomQuadDirection.get(i) > 0.5f) { randomQuadWidth = randomQuadWidth * -1; } float randomQuadHigh = this.randomQuadHighs.get(i) * paperSlipHigh * animatedValue; PaperSlip.quadTo( rectFPaper.left + (i + 1) * paperSlipwidth - paperSlipspace - randomQuadWidth, rectFPaper.bottom + randomQuadHigh, rectFPaper.left + (i + 1) * paperSlipwidth - paperSlipspace, rectFPaper.bottom + paperSlipHigh ); PaperSlip.lineTo(rectFPaper.left + (i) * paperSlipwidth + paperSlipspace, rectFPaper.bottom + paperSlipHigh ); PaperSlip.quadTo( rectFPaper.left + i * paperSlipwidth + paperSlipspace - randomQuadWidth, rectFPaper.bottom + randomQuadHigh, rectFPaper.left + i * paperSlipwidth + paperSlipspace, rectFPaper.bottom ); PaperSlip.close(); canvas.drawPath(PaperSlip, mPaint); } } private void drawPaperPiece(Canvas canvas) { if (mAnimatedValue == 0) return; float paperPiecewidth = rectFPaper.width() / paperSlipCount; Path paperPiece = new Path(); for (int i = 0; i < PaperPiecerandAngle.size(); i++) { int angle = (int) (PaperPiecerandAngle.get(i) * 360); angle = (int) (angle + 180 * mAnimatedValue); float radius = paperPiecewidth * 0.8f; if (PaperPiecerandRadius.get(i) < 0.3f) { PaperPiecerandRadius.set(i, 0.3f); } radius = radius * PaperPiecerandRadius.get(i); float centerX = mPaddingLR * 3 + (getMeasuredWidth() - 6 * mPaddingLR) * PaperPiecerandX.get(i); float centerY = getMeasuredHeight() / 3 * PaperPiecerandY.get(i) + getMeasuredHeight() / 3 + mAnimatedValue * getMeasuredHeight() / 3; if (PaperPiecerandRadius.get(i) >= 0.3f && PaperPiecerandRadius.get(i) <= 0.4f) { centerY = getMeasuredHeight() / 3 * PaperPiecerandY.get(i) + getMeasuredHeight() / 3 + mAnimatedValue * getMeasuredHeight() / 3 * 2.8f; } else if (PaperPiecerandRadius.get(i) > 0.4f && PaperPiecerandRadius.get(i) <= 0.5f) { centerY = getMeasuredHeight() / 3 * PaperPiecerandY.get(i) + getMeasuredHeight() / 3 + mAnimatedValue * getMeasuredHeight() / 3 * 2.6f; } else if (PaperPiecerandRadius.get(i) > 0.5f && PaperPiecerandRadius.get(i) <= 0.6f) { centerY = getMeasuredHeight() / 3 * PaperPiecerandY.get(i) + getMeasuredHeight() / 3 + mAnimatedValue * getMeasuredHeight() / 3 * 2.4f; } else if (PaperPiecerandRadius.get(i) > 0.6f && PaperPiecerandRadius.get(i) <= 0.7f) { centerY = getMeasuredHeight() / 3 * PaperPiecerandY.get(i) + getMeasuredHeight() / 3 + mAnimatedValue * getMeasuredHeight() / 3 * 2.2f; } else if (PaperPiecerandRadius.get(i) > 0.7f && PaperPiecerandRadius.get(i) <= 0.8f) { centerY = getMeasuredHeight() / 3 * PaperPiecerandY.get(i) + getMeasuredHeight() / 3 + mAnimatedValue * getMeasuredHeight() / 3 * 2.4f; } else if (PaperPiecerandRadius.get(i) > 0.8f && PaperPiecerandRadius.get(i) <= 0.9f) { centerY = getMeasuredHeight() / 3 * PaperPiecerandY.get(i) + getMeasuredHeight() / 3 + mAnimatedValue * getMeasuredHeight() / 3 * 2.6f; } else if (PaperPiecerandRadius.get(i) > 0.9f) { centerY = getMeasuredHeight() / 3 * PaperPiecerandY.get(i) + getMeasuredHeight() / 3 + mAnimatedValue * getMeasuredHeight() / 3 * 2.8f; } float x = (float) ((radius) * Math.cos(angle * Math.PI / 180f)); float y = (float) ((radius) * Math.sin(angle * Math.PI / 180f)); paperPiece.reset(); paperPiece.moveTo(centerX - x, centerY - y ); int angleBig = 0; if (PaperPiecerandX.get(i) > 0.7f) { angleBig = (int) (180 * 0.7f); } else if (PaperPiecerandX.get(i) < 0.3f) { angleBig = (int) (180 * 0.3f); } else { angleBig = (int) (180 * PaperPiecerandX.get(i)); } int angleSmall = 180 - angleBig; angle = angle + angleBig; x = (float) ((radius) * Math.cos(angle * Math.PI / 180f)); y = (float) ((radius) * Math.sin(angle * Math.PI / 180f)); paperPiece.lineTo(centerX - x, centerY - y ); angle = angle + angleSmall; x = (float) ((radius) * Math.cos(angle * Math.PI / 180f)); y = (float) ((radius) * Math.sin(angle * Math.PI / 180f)); paperPiece.lineTo(centerX - x, centerY - y ); angle = angle + angleBig; x = (float) ((radius) * Math.cos(angle * Math.PI / 180f)); y = (float) ((radius) * Math.sin(angle * Math.PI / 180f)); paperPiece.lineTo(centerX - x, centerY - y ); angle = angle + angleSmall; x = (float) ((radius) * Math.cos(angle * Math.PI / 180f)); y = (float) ((radius) * Math.sin(angle * Math.PI / 180f)); paperPiece.lineTo(centerX - x, centerY - y ); paperPiece.close(); int color = (Integer) evaluator.evaluate(PaperPiecerandRadius.get(i), Color.rgb(180, 180, 180), paperColor ); mPaint.setColor(color); canvas.drawPath(paperPiece, mPaint); } mPaint.setColor(paperColor); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); mPaddingLR = dip2px(getMeasuredWidth() / 30); mPaint.setColor(Color.WHITE); drawPaper(canvas); if (mShrededType == SHREDEDTYPE.Slip) drawPaperSlip(canvas); else if (mShrededType == SHREDEDTYPE.Piece) drawPaperPiece(canvas); drawHost(canvas); canvas.restore(); } public enum SHREDEDTYPE { Slip, Piece } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(dip2px(150), dip2px(150)); } else if (widthSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(dip2px(150), heightSpecSize); } else if (heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(widthSpecSize, dip2px(150)); } } private float getFontlength(Paint paint, String str) { Rect rect = new Rect(); paint.getTextBounds(str, 0, str.length(), rect); return rect.width(); } private float getFontHeight(Paint paint, String str) { Rect rect = new Rect(); paint.getTextBounds(str, 0, str.length(), rect); return rect.height(); } private int dip2px(float dpValue) { final float scale = getContext().getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } public void startAnim(int duration) { stopAnim(); startViewAnim(0f, 1f, duration); } private ValueAnimator valueAnimator; private float mAnimatedValue = 0f; public void stopAnim() { if (valueAnimator != null) { clearAnimation(); valueAnimator.setRepeatCount(0); valueAnimator.cancel(); valueAnimator.end(); mAnimatedValue = 0f; postInvalidate(); } } private ValueAnimator startViewAnim(float startF, final float endF, long time) { valueAnimator = ValueAnimator.ofFloat(startF, endF); valueAnimator.setDuration(time); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.setRepeatCount(ValueAnimator.INFINITE);//无限循环 valueAnimator.setRepeatMode(ValueAnimator.RESTART); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mAnimatedValue = (float) valueAnimator.getAnimatedValue(); invalidate(); } }); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); setRandom(); } @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); setRandom(); } @Override public void onAnimationRepeat(Animator animation) { super.onAnimationRepeat(animation); setRandom(); } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } return valueAnimator; } private void setRandom() { randomHighs.clear(); randomQuadWidths.clear(); randomQuadHighs.clear(); randomQuadDirection.clear(); for (int i = 0; i < paperSlipCount; i++) { randomHighs.add((float) Math.random()); randomQuadWidths.add((float) Math.random()); randomQuadHighs.add((float) Math.random()); randomQuadDirection.add((float) Math.random()); } PaperPiecerandX.clear(); PaperPiecerandY.clear(); PaperPiecerandAngle.clear(); PaperPiecerandRadius.clear(); for (int i = 0; i < paperPieceCount; i++) { PaperPiecerandX.add((float) Math.random()); PaperPiecerandY.add((float) Math.random()); PaperPiecerandAngle.add((float) Math.random()); PaperPiecerandRadius.add((float) Math.random()); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); stopAnim(); } }