ValueAnimator实现酷炫的动画
bnxrrta85
8年前
<p>这篇文章主要实现用ValueAnimator实现自定义控件的一个动画效果</p> <p>先大概说一下ValueAnimator的使用ValueAnimator valueAnimator=ValueAnimator.ofFloat(0, 100f);这样就生成了一个ValueAnimator类,ValueAnimator.ofFloat()也可以是ValueAnimator.ofInt();然后就是setDuration()设置动画持续时间;setInterpolator(new AccelerateDecelerateInterpolator())设置拦截器(api给出了几种效果,使用很方便的);再添加一个更新的监听就可以开始搞事了addUpdateListener();接下来给大家看看我之前在项目中用过的一个比较复杂的动画,代码太长,就直接粘代码吧,很简单的,希望有大神能对代码做一下改进!</p> <pre> <code class="language-java">public class RatingViw extends View { //旋转动画,百分比动画,评估中的动画,评分动画,结果动画 private ValueAnimator rotateAnimation, perAnimation, detailAnimation, ratingAnimation, resultAnimation; private float rotateAngle; private List<RatingBar> RatingBars; private int x, y; //圆心的坐标 private static final int STROKE_OFFSET = 5; //扇形的间隙 private int currStarNum = -1; //当前星的数量 private int lastStatNum = -1; //上一颗星的数量 private int currPer; //当前的百分数 private int radius; //半径 private int ditalAlpha, resultAlpha; // private int maxRate = 18; private boolean isShow; //显示RatingView private boolean isShowDetail = true; //显示诊断过程 //股票名称,百分比,百分号,结果,评估中 private Paint paint, perPaint, mPaint, resulPaint, sPaint; private Rect rect, rect1, textRect, ditalRect, resultRect; private String name = "", result = "80分"; private float eventX; private float eventY; private boolean isEmpty = false; private String assess="评估中"; //评估中 private boolean drawResult; private boolean isAnimationYEnd=false; public RatingViw(Context context) { this(context, null); } public RatingViw(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RatingViw(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); RatingBars = new ArrayList<>(); RatingBars.add(0, new RatingBar(0)); RatingBars.add(0, new RatingBar(0)); RatingBars.add(0, new RatingBar(0)); initAnimation(); initTextAnimation(); } public void setName(String name) { this.name = name; } public String getName(){ return name; } public void setResult(String result){ this.result=result+"分"; } private void initTextAnimation() { detailAnimation = ValueAnimator.ofInt(0, 255); detailAnimation.setDuration(500); detailAnimation.setInterpolator(new LinearInterpolator()); detailAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { ditalAlpha = (int) valueAnimator.getAnimatedValue(); } }); resultAnimation = ValueAnimator.ofInt(0, 255); resultAnimation.setDuration(500); resultAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { resultAlpha = (int) valueAnimator.getAnimatedValue(); } }); } private void initAnimation() { rotateAnimation = ValueAnimator.ofFloat(0, 360 * 5); rotateAnimation.setDuration(3000); rotateAnimation.setInterpolator(new AccelerateDecelerateInterpolator()); rotateAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { rotateAngle = (float) valueAnimator.getAnimatedValue(); long currentPlayTime = valueAnimator.getCurrentPlayTime(); invalidate(); if (currentPlayTime > 2500) { if (isShow) { ratingAnimation.start(); } } } }); //中间的文字 perAnimation = ValueAnimator.ofInt(0, 180); perAnimation.setDuration(3000); perAnimation.setInterpolator(new LinearInterpolator()); perAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { currPer = (int) valueAnimator.getAnimatedValue(); if (currPer == 50) { detailAnimation.start(); } if (currPer == 100) { detailAnimation.start(); } } }); ratingAnimation = ValueAnimator.ofInt(0, maxRate); //18颗星 ratingAnimation.setDuration(1000); ratingAnimation.setInterpolator(new LinearInterpolator()); ratingAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { currStarNum = (int) valueAnimator.getAnimatedValue(); //关闭百分比和详情 isShowDetail = false; if (currStarNum == 1) { resultAnimation.start(); drawResult = true; } if (currStarNum != lastStatNum) { invalidate(); } lastStatNum = currStarNum; } }); ratingAnimation.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { if (!drawResult) { resultAnimation.start(); } if (translation!=null) translation.start(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); } private int translationX;//评分向左移动 private int textX,textY; private int width,height; private int reSetX; private ValueAnimator translation,textAnimationX,textAnimatorY,reSetAnimation; //评分左移,文字左移, @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(getMeasuredWidth(),getMeasuredWidth()*16/45); } @Override protected void onSizeChanged(final int w, final int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); x = w / 2; y = h / 2; radius = y*11/16; translation= ValueAnimator.ofInt(x,radius+h/4); translation.setDuration(500); translation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translationX= (int) animation.getAnimatedValue(); x=translationX; initRatingBar(); invalidate(); if (translationX<300){ textAnimationX.start(); textAnimatorY.start(); } } }); width = getMeasuredWidth(); height = getMeasuredHeight(); int d = width - 2 * radius - dip2px(getContext(), 15); textAnimationX= ValueAnimator.ofInt(0,w*7/90,w*7/90-30,w*7/90,w*7/90-20,w*7/90,w*7/90-10,w*7/90); textAnimationX.setDuration(500); textAnimationX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { textX= (int) animation.getAnimatedValue(); if (textX*5>225){ textRectPaint.setAlpha(255); textPaint.setAlpha(255); } else { textRectPaint.setAlpha(textX*5); textPaint.setAlpha(textX*5); } initPath(); invalidate(); } }); textAnimatorY= ValueAnimator.ofInt(0,h*3/16,h*3/16-30,h*3/16,h*3/16-20,h*3/16,h*3/16-10,h*3/16); textAnimatorY.setDuration(500); textAnimatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { textY= (int) animation.getAnimatedValue(); initPath(); invalidate(); } }); textAnimatorY.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { isAnimationYEnd=true; if (onAnimatorListener!=null){ onAnimatorListener.onEnd(); } } }); reSetAnimation= ValueAnimator.ofInt(radius+h/4,width/2); reSetAnimation.setDuration(500); reSetAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { x= (int) animation.getAnimatedValue(); int alpha = width / 2 - x; if (alpha>=255){ alpha=255; } textRectPaint.setAlpha(alpha); textPaint.setAlpha(alpha); initPath(); initRatingBar(); invalidate(); } }); reSetAnimation.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { Toast.makeText(getContext(), "完成", Toast.LENGTH_SHORT).show(); show(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); initText(); initRatingBar(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (isEmpty) { canvas.save(); canvas.rotate(rotateAngle, x, y); for (RatingBar RatingBar : RatingBars) { RatingBar.drawUnRate(canvas); } canvas.restore(); canvas.save(); canvas.rotate(-rotateAngle, x, y); for (RatingBar RatingBar : RatingBars) { RatingBar.drawLine(canvas); } canvas.restore(); paint.setTextSize(radius / 5); canvas.drawText(name, x - textRect.width() / 2, y - radius / 2, paint); } drawResult(canvas); drawTranslationX(canvas); drawText(canvas); } private String suggest=""; //增持 private String ranking=""; //打败96%的股票 private String totalAccuracy=""; //89% private String changeAccuracy=""; //较昨日提升2% public void setSuggest(int suggest) { String[] array = getContext().getResources().getStringArray(R.array.diagnoseRating); if (suggest>=array.length)return; this.suggest=array[suggest]; } public void setRanking(String ranking) { this.ranking = "打败"+DigitalUtil.getNumberToNumver_towInt(ranking)+"%的股票"; } public void setTotalAccuracy(String totalAccuracy) { this.totalAccuracy = DigitalUtil.getNumberToNumver_towInt(totalAccuracy)+"%"; } public void setChangeAccuracy(String changeAccuracy) { if (TextUtils.isEmpty(changeAccuracy))return; if (!changeAccuracy.contains("-")){ this.changeAccuracy = "较昨日提升"+DigitalUtil.getNumberToNumver_towInt(changeAccuracy)+"%"; }else { String replace = changeAccuracy.replace("-", ""); this.changeAccuracy = "较昨日降低"+DigitalUtil.getNumberToNumver_towInt(replace)+"%"; } } /** * 画最后的文字 */ private void drawText(Canvas canvas) { textPaint.setTextSize(textY*2/5); textPaint.getTextBounds("今日评级",0,"今日评级".length(),textRectF); canvas.drawText("今日评级",width*235/450-textRectF.width()/2,y-height/8,textPaint); textPaint.setTextSize(textY*2/3); textPaint.getTextBounds(suggest,0,suggest.length(),textRectF); canvas.drawText(suggest,width*235/450-textRectF.width()/2,y+textRectF.height()/2,textPaint); textPaint.setTextSize(textY*2/5); textPaint.getTextBounds(ranking,0,ranking.length(),textRectF); canvas.drawText(ranking,width*235/450-textRectF.width()/2,y+height*3/16,textPaint); textPaint.setTextSize(textY*2/5); textPaint.getTextBounds("诊股准确率",0,"诊股准确率".length(),textRectF); canvas.drawText("诊股准确率",width*365/450-textRectF.width()/2,y-height/8,textPaint); textPaint.setTextSize(textY*2/3); textPaint.getTextBounds(totalAccuracy,0,totalAccuracy.length(),textRectF); canvas.drawText(totalAccuracy,width*365/450-textRectF.width()/2,y+textRectF.height()/2,textPaint); textPaint.setTextSize(textY*2/5); textPaint.getTextBounds(changeAccuracy,0,changeAccuracy.length(),textRectF); canvas.drawText(changeAccuracy,width*365/450-textRectF.width()/2,y+height*3/16,textPaint); textPaint.getTextBounds("查看详情>",0,"查看详情>".length(),textRectF); canvas.drawText("查看详情>",width*440/450-textRectF.width(),height*15/16,textPaint); } private Rect textRectF; private Paint textRectPaint,textPaint; private Path pathA,pathB,pathC,pathD,pathAr,pathBr,pathCr,pathDr; private void initText(){ textRectPaint=new Paint(Paint.ANTI_ALIAS_FLAG); textRectPaint.setColor(Color.WHITE); textRectPaint.setAlpha(0); textRectPaint.setStyle(Paint.Style.STROKE); textRectPaint.setStrokeWidth(dip2px(getContext(),1)); textPaint=new Paint(Paint.ANTI_ALIAS_FLAG); textPaint.setColor(Color.WHITE); textPaint.setTextSize(30); textRectF=new Rect(); textPaint.getTextBounds("今日评级",0,"今日评级".length(),textRectF); pathA=new Path(); pathB=new Path(); pathC=new Path(); pathD=new Path(); pathAr=new Path(); pathBr=new Path(); pathCr=new Path(); pathDr=new Path(); initPath(); } private void initPath() { int line=width/45; pathA.reset(); pathA.moveTo(width*225/450-textX,y-textY); pathA.lineTo(width*225/450-textX,y-line-textY); pathA.lineTo(width*225/450-textX+line,y-line-textY); pathB.reset(); pathB.moveTo(width*225/450+textX+2*width/45,y-textY); pathB.lineTo(width*225/450+textX+2*line,y-line-textY); pathB.lineTo(width*225/450+textX+line,y-line-textY); pathC.reset(); pathC.moveTo(width*225/450+textX+2*line,y+textY); pathC.lineTo(width*225/450+textX+2*line,y+line+textY); pathC.lineTo(width*225/450+textX+line,y+line+textY); pathD.reset(); pathD.moveTo(width*225/450-textX,y+textY); pathD.lineTo(width*225/450-textX,y+line+textY); pathD.lineTo(width*225/450-textX+line,y+line+textY); pathAr.reset(); pathAr.moveTo(width*355/450-textX,y-textY); pathAr.lineTo(width*355/450-textX,y-line-textY); pathAr.lineTo(width*355/450+line-textX,y-line-textY); pathBr.reset(); pathBr.moveTo(width*355/450+2*line+textX,y-textY); pathBr.lineTo(width*355/450+2*line+textX,y-line-textY); pathBr.lineTo(width*355/450+line+textX,y-line-textY); pathCr.reset(); pathCr.moveTo(width*355/450+2*line+textX,y+textY); pathCr.lineTo(width*355/450+2*line+textX,y+line+textY); pathCr.lineTo(width*355/450+line+textX,y+line+textY); pathDr.reset(); pathDr.moveTo(width*355/450-textX,y+textY); pathDr.lineTo(width*355/450-textX,y+line+textY); pathDr.lineTo(width*355/450+line-textX,y+line+textY); } /** * 画平移动画 * @param canvas 画布 */ private void drawTranslationX(Canvas canvas) { if (translationX>0){ canvas.drawPath(pathA,textRectPaint); canvas.drawPath(pathB,textRectPaint); canvas.drawPath(pathC,textRectPaint); canvas.drawPath(pathD,textRectPaint); canvas.drawPath(pathAr,textRectPaint); canvas.drawPath(pathBr,textRectPaint); canvas.drawPath(pathCr,textRectPaint); canvas.drawPath(pathDr,textRectPaint); } } private static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } public static int getScreenWidth(Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(outMetrics); return outMetrics.widthPixels; } private void drawResult(Canvas canvas) { if (isShow) { //画没有评分的所有的item canvas.save(); canvas.rotate(rotateAngle, x, y); for (RatingBar RatingBar : RatingBars) { RatingBar.drawUnRate(canvas); } canvas.restore(); canvas.save(); canvas.rotate(-rotateAngle, x, y); for (RatingBar RatingBar : RatingBars) { RatingBar.drawLine(canvas); } canvas.restore(); canvas.drawText(name, x - textRect.width() / 2, y - radius / 5, paint); if (isShowDetail){ drawPer(canvas); } //画星 if (currStarNum != -1) { for (RatingBar RatingBar : RatingBars) { for (int i = 0; i < RatingBar.getCurrRate(); i++) { if (i <= currStarNum) { //每次都要讲之前的画出来,不然之前的就没有了 RatingBar.drawRating(canvas, i); } } } } //画结果 if (resultAlpha > 0) { resulPaint.setAlpha(resultAlpha); canvas.drawText(result, x - resultRect.width() / 2, y + radius / 5*2, resulPaint); } } } private void drawPer(Canvas canvas) { canvas.drawText("%", x + 2 * rect.width() / 3, y + radius / 3, mPaint); if (0<currPer&&currPer <= 30) { canvas.drawText("" + currPer, x - rect.width() / 2, y + radius / 3, perPaint); if (ditalAlpha > 0) { canvas.drawText(assess, x - ditalRect.width() / 2, y + radius / 3 + ditalRect.height()*3/2, sPaint); } } if (currPer > 30 && currPer < 50) { canvas.drawText("" + 30, x - rect.width() / 2, y + radius / 3, perPaint); if (ditalAlpha > 0) { canvas.drawText(assess, x - ditalRect.width() / 2, y + radius / 3 + ditalRect.height()*3/2, sPaint); } } if (currPer >= 50 && currPer <= 80) { canvas.drawText("" + (currPer - 20), x - rect.width() / 2, y + radius / 3, perPaint); if (ditalAlpha > 0) { canvas.drawText(assess, x - ditalRect.width() / 2, y + radius / 3 + ditalRect.height()*3/2, sPaint); } } if (currPer > 80 && currPer < 100) { canvas.drawText("" + 60, x - rect.width() / 2, y + radius / 3, perPaint); if (ditalAlpha > 0) { canvas.drawText(assess, x - ditalRect.width() / 2, y + radius / 3 + ditalRect.height()*3/2, sPaint); } } if (currPer >= 100 && currPer <= 130) { canvas.drawText("" + (currPer - 40), x - rect.width() / 2, y + radius / 3, perPaint); if (ditalAlpha > 0) { canvas.drawText(assess, x - ditalRect.width() / 2, y + radius / 3 + ditalRect.height()*3/2, sPaint); } } if (currPer > 130 && currPer < 150) { canvas.drawText("" + 90, x - rect.width() / 2, y + radius / 3, perPaint); if (ditalAlpha > 0) { canvas.drawText(assess, x - ditalRect.width() / 2, y + radius / 3 + ditalRect.height()*3/2, sPaint); } } if (currPer >= 150 && currPer < 160) { canvas.drawText("" + (currPer - 60), x - 2 * rect.width() / 3, y + radius / 3, perPaint); } if (currPer >= 160) { canvas.drawText("" + 100, x - 2 * rect1.width() / 3, y + radius / 3, perPaint); } } private void initRatingBar() { int dividePart = RatingBars.size(); if (dividePart == 0) { return; } int sweepAngle = dividePart == 1 ? 360 : (360 - dividePart * STROKE_OFFSET) / dividePart; int rotateOffset = dividePart == 1 ? 90 : 90 + sweepAngle / 2 - 3; for (int i = 0; i < dividePart; i++) { float startAngle = i * (sweepAngle + STROKE_OFFSET) - rotateOffset; RatingBar RatingBar = RatingBars.get(i); if (dividePart == 1) { RatingBar.setSingle(true); } RatingBar.setX(x); RatingBar.setY(y); RatingBar.setStartAngle(startAngle); RatingBar.setSweepAngle(sweepAngle); RatingBar.init(maxRate); radius = RatingBar.getRadius(); } initPaint(); } private void initPaint() { paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setTextSize(radius / 4); paint.setColor(Color.WHITE); paint.setAlpha((int) (255 * 0.6)); perPaint = new Paint(Paint.ANTI_ALIAS_FLAG); perPaint.setAlpha(255); perPaint.setTextSize(radius / 2); perPaint.setColor(Color.WHITE); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setTextSize(radius / 4); mPaint.setColor(Color.WHITE); mPaint.setAlpha(255); resulPaint = new Paint(Paint.ANTI_ALIAS_FLAG); resulPaint.setAlpha((int) (255 * 0.7)); resulPaint.setColor(Color.WHITE); resulPaint.setTextSize(radius / 2); sPaint = new Paint(Paint.ANTI_ALIAS_FLAG); sPaint.setAlpha((int) (255 * 0.6)); sPaint.setColor(Color.WHITE); sPaint.setTextSize(radius / 6); rect = new Rect(); perPaint.getTextBounds("10", 0, "10".length(), rect); rect1 = new Rect(); perPaint.getTextBounds("100", 0, "100".length(), rect1); textRect = new Rect(); paint.getTextBounds(name, 0, name.length(), textRect); ditalRect = new Rect(); sPaint.getTextBounds(assess,0,assess.length(),ditalRect); resultRect = new Rect(); resulPaint.getTextBounds(result, 0, result.length(), resultRect); } public void addRatingBar(RatingBar RatingBar) { RatingBar.add(RatingBar); } public void show() { if (RatingBar.size() == 0) { return; } isShow = true; isEmpty = false; if (rotateAnimation != null) { rotateAnimation.cancel(); } initRatingBar(); rotateAnimation.setRepeatCount(0); //旋转动画 rotateAnimation.start(); //百分比动画 perAnimation.start(); //评估中动画 detailAnimation.start(); if (onAnimatorListener!=null){ onAnimatorListener.onStart(); } } public void showEmpty() { isEmpty = true; initEmpty(); invalidate(); rotateAnimation.setRepeatMode(ValueAnimator.RESTART); rotateAnimation.setRepeatCount(ValueAnimator.INFINITE); rotateAnimation.start(); } private void initEmpty() { paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setTextSize(radius / 5); // paint.setColor(Color.WHITE); paint.setAlpha((int) (255 * 0.6)); textRect = new Rect(); paint.getTextBounds(name, 0, name.length(), textRect); } public void clear() { rotateAnimation.end(); rotateAnimation.cancel(); RatingBar.clear(); isShow = false; ditalAlpha=0; resultAlpha=0; currStarNum=-1; isShowDetail=true; invalidate(); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: eventX = event.getX(); eventY = event.getY(); break; case MotionEvent.ACTION_UP: float resX = Math.abs(event.getX() - eventX); float resY = Math.abs(event.getY() - eventY); if (resX<10&&resY<10){ if (isAnimationYEnd){ Log.e("HHH", "onTouchEvent: " + event.getX() +"---"+ event.getY() +"---"+ width*365/450 +"---"+ height*15/16 ); if (event.getX()>=width-textRectF.width()*3/2 && event.getX()<width && event.getY()>=height-2*textRectF.height() && event.getY()<height) { if (onClickRatingViewListener!=null){ onClickRatingViewListener.onClick(); } } } } break; } return true; } public void reSet(){ name=""; ditalAlpha=0; resultAlpha=0; currStarNum=-1; reSetAnimation.start(); } private OnClickRatingViewListener onClickRatingViewListener; public void setOnClickRatingViewListener(OnClickRatingViewListener onClickRatingViewListener) { this.onClickRatingViewListener = onClickRatingViewListener; } public interface OnClickRatingViewListener{ void onClick(); } private OnAnimatorListener onAnimatorListener; public void setOnAnimatorListener(OnAnimatorListener onAnimatorListener) { this.onAnimatorListener = onAnimatorListener; } public interface OnAnimatorListener{ void onStart(); void onEnd(); } }</code></pre> <h2>啊啊啊!!!一行一行的格式化代码好麻烦啊,有没有大神知道快速格式化代码的吗</h2> <p>下面是每个小格</p> <pre> <code class="language-java">public class RatingBar { private static final int ITEM_OFFSET = 1; //每个小item的间隙 private static final int UN_RATING_ALPHA = (int) (255 * 0.3); //没被选中的item的透明度 private static final int OUTLINE_ALPHA = (int) (255 * 0.4); //外面的线的透明度 private static final int RATING_ALPHA = (int) (255 * 0.8); //评分的透明度 private int ratingAlpha; private float startAngle; //每扇形开始的角度 private int sweepAngle; //每个扇形的角度 private int ratingBarWidth; //评分的宽度 private int outLineWidth; //外面的线的宽度 private int maxRate = 18; //总分数 private int currRate; //当前的评分数 private int radius; //半径 private int x, y; //位置 private List<Rate> rates; private Paint paint, outLinrPaint, ratingPaint; private RectF rectF, outLineRectF; private boolean isSingle = false; public RatingBar(int currRate) { this.currRate = currRate; ratingAlpha=RATING_ALPHA; paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.WHITE); outLinrPaint = new Paint(Paint.ANTI_ALIAS_FLAG); outLinrPaint.setColor(Color.WHITE); ratingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); ratingPaint.setColor(Color.WHITE); } void init(int maxRate) { this.maxRate=maxRate; initRaingBar(); initRectF(); initPaint(); } private void initPaint() { paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(ratingBarWidth); paint.setAlpha(UN_RATING_ALPHA); outLinrPaint.setStyle(Paint.Style.STROKE); outLinrPaint.setStrokeWidth(outLineWidth); outLinrPaint.setAlpha(OUTLINE_ALPHA); ratingPaint.setStyle(Paint.Style.STROKE); ratingPaint.setStrokeWidth(ratingBarWidth); ratingPaint.setAlpha(ratingAlpha); } private void initRectF() { radius = y / 4*3; ratingBarWidth = radius / 8; outLineWidth = ratingBarWidth / 4; int outLineRadius = radius -outLineWidth/2; int ratingBarRadius = radius - ratingBarWidth / 2-5*outLineWidth; rectF = new RectF(); rectF.left = x - ratingBarRadius; rectF.top = y - ratingBarRadius; rectF.right = x + ratingBarRadius; rectF.bottom = y + ratingBarRadius; outLineRectF = new RectF(); outLineRectF.left = x - outLineRadius; outLineRectF.top = y - outLineRadius; outLineRectF.right = x + outLineRadius; outLineRectF.bottom = y + outLineRadius; } private void initRaingBar() { rates = new ArrayList<>(); float itemSweepAngle; if (isSingle) { itemSweepAngle = (sweepAngle - (ITEM_OFFSET * maxRate)) / maxRate; } else { //计算每个item的弧度 itemSweepAngle = (sweepAngle - (ITEM_OFFSET * (maxRate - 1))) / maxRate; } for (int i = 0; i < maxRate; i++) { //计算每个item的开始角度 float itemstartAngle = startAngle + i * (itemSweepAngle + ITEM_OFFSET); rates.add(new Rate(itemstartAngle, itemSweepAngle)); } } void drawUnRate(Canvas canvas) { for (Rate rate : rates) { rate.drawArc(canvas, rectF, paint); } } void drawLine(Canvas canvas) { //周长 canvas.drawArc(outLineRectF, startAngle-3, sweepAngle, false, outLinrPaint); } void drawRating(Canvas canvas, int index) { if (index > currRate) { return; } Rate rate = rates.get(index); rate.drawRate(canvas, rectF, ratingPaint); } void setStartAngle(float startAngle) { this.startAngle = startAngle; } void setSweepAngle(int sweepAngle) { this.sweepAngle = sweepAngle; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; } void setSingle(boolean single) { isSingle = single; } int getRadius() { return radius; } int getCurrRate() { return currRate; } private class Rate { private float startAngle, sweepAngle; //每个小格的角度 Rate(float startAngle, float sweepAngle) { this.startAngle = startAngle; this.sweepAngle = sweepAngle; } void drawArc(Canvas canvas, RectF oval, Paint paint) { canvas.drawArc(oval, startAngle, sweepAngle, false, paint); } void drawRate(Canvas canvas, RectF rectF, Paint paint) { canvas.drawArc(rectF, startAngle, sweepAngle, false, paint); } } }</code></pre> <p>代码看着很多,但是原理很简单,逻辑有点乱,可以说ValueAnimator的作用就是用来计时的,但是在以前有个项目中用ValueAnimator来做循环倒计时,大概代码如下:</p> <pre> <code class="language-java">animator=ValueAnimator.ofInt(5,0); animator.setDuration(5000); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { time=(int)valueAnimator.getAnimatedValue(); text.setText(String.valueOf(time)); }}); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animator.start(); //当动画结束后又继续该动画,实现一个无限循环的效果 }});</code></pre> <p>就用动画实现一个无限循环的效果,想像的很美好,但是一运行这个动画只执行了两次,第二次结束后就没有继续了,苦思冥想,各种测试最后找到一个方法,就是在结束的时候用handler来发送一个消息,在接收消息那里再启动动画,这个动画就可以实现无线循环了,具体原因为什么呢?有没有大神知道的给我留个言吧。</p> <p>在运行这个评分动画的时候也发现了一个问题,在动画更新的监听中long currentPlayTime = valueAnimator.getCurrentPlayTime();这个方法在大部分手机没有问题,但就在华为荣耀8的7.0的手机上出现了动画不按套路出牌的效果,根据动画的效果来看发现问题出在这里,由于这里有个启动动画,这个动画就在这里乱套了,然而打印出currentPlayTime ,奇怪的是在第一次运行的时候没有任何异常,在第二次的时候currentPlayTime 的初始值不是0,而是当前动画从开始执行到现在的总共时间,用其他手机来测试,没有发现异常,再看源码里面也没有关于版本的代码,就暂时在currentPlayTime 这里判断了一下,如果大于总时间就等于0,然后再来荣耀上运行,欧拉,暂时没有问题了。</p> <p>最后附上截图-O(∩_∩)O哈哈~</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/42ccdce19d939dbd8625e02b71b2fa56.gif"></p> <p style="text-align:center">GIF.gif</p> <p> </p> <p>来自:http://www.jianshu.com/p/b8d3e833d3c9</p> <p> </p>