package com.example.jack.webchart; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Camera; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.CornerPathEffect; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.SweepGradient; import android.graphics.Typeface; import android.util.AttributeSet; import android.view.View; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2016/10/9. */ public class ExerciseWebChart extends View { //屏幕的宽度 private int mScreemWidth; //屏幕的高度 private int mScreemHight; //圆的线 private Paint mCirclePaint; //圆区域的颜色 private Paint mCirclePaintColor; //虚线 private Paint mLineCircle; //圆点 private Paint mCircleHoldPaint; //画字体 private Paint mCenterCircle; //最外的圆的透明度 private int mCircleAlpha1=0; //中间的圆的透明度 private int mCircleAlpha2=0; //最内的圆的透明度 private int mCircleAlpha3=0; //好友排名 private int mFriendDranking=0; //达标天数 private int mStandardDay=0; //平均步数 private int mAverageCount=0; //好友排名的X轴坐标 private float mFriendDrankingX=0; //好友排名的Y轴坐标 private float mFriendDrankingY=0; //平均步数的X轴坐标 private float mStandardDayX=0; //平均步数的Y轴坐标 private float mStandardDayY=0; //达标天数的X轴坐标 private float mAverageCountX=0; //达标天数的Y轴坐标 private float mAverageCountY=0; //临时的View的半径 private int tempCircleRadius=0; //View的半径 private int circleRadius=0; //每个圆圈的间隔 private float marginCircleSize=0; //圆的颜色 private int circleColor=0; //朋友区域的颜色 private int friendColor; //平均步数区域的颜色 private int averageColor; //达标天数区域的颜色 private int standardColor; //总步数 private String allStep; //好友排名 private String firendDrank; //达标天数 private String standarDay; //平均步数 private String averageCount; //波浪动画的数值 private int waveData=-30; //中间文字翻转动画的数值 private float centerData=0; //画波浪的看门狗 private boolean waveWatchDag=false; //画虚线的看门狗 private boolean lineWatchDag=false; //各点解释的看门狗 private boolean expainWatchDag=false; //中心圆的内容的看门狗 private boolean centerWatchDag=false; //解释的字符串 private String averageCountTxt="平均步数"; private String friendDrankTxt="好友排名"; private String standarDayTxt="达标天数"; private String theyCount="本周总步数"; private String tip="步"; public ExerciseWebChart(Context context) { this(context,null); } public ExerciseWebChart(Context context, AttributeSet attrs) { this(context,attrs,0); } public ExerciseWebChart(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray=context.getTheme().obtainStyledAttributes(attrs,R.styleable.ExerciseWebChart,defStyleAttr,0); int numCount=typedArray.getIndexCount(); for(int i=0;i<numCount;i++){ int attr=typedArray.getIndex(i); switch(attr){ case R.styleable.ExerciseWebChart_frienDranking: mFriendDranking=typedArray.getInt(attr,0); break; case R.styleable.ExerciseWebChart_standardDay: mStandardDay=typedArray.getInt(attr,0); break; case R.styleable.ExerciseWebChart_averageCount: mAverageCount=typedArray.getInt(attr,0); break; case R.styleable.ExerciseWebChart_circleSize: tempCircleRadius=typedArray.getInt(attr,0); break; case R.styleable.ExerciseWebChart_circleColor: circleColor=typedArray.getColor(attr,Color.parseColor("#BCBCBC")); break; case R.styleable.ExerciseWebChart_friendColor: friendColor=typedArray.getColor(attr,Color.parseColor("#32B7EB")); break; case R.styleable.ExerciseWebChart_averageColor: averageColor=typedArray.getColor(attr,Color.parseColor("#FBD700")); break; case R.styleable.ExerciseWebChart_standardColor: standardColor=typedArray.getColor(attr,Color.parseColor("#39E100")); break; case R.styleable.ExerciseWebChart_allStep: allStep=typedArray.getString(attr); break; case R.styleable.ExerciseWebChart_friendDrankData: firendDrank=typedArray.getString(attr); break; case R.styleable.ExerciseWebChart_standarDayData: standarDay=typedArray.getString(attr); break; case R.styleable.ExerciseWebChart_averageCountData: averageCount=typedArray.getString(attr); break; } } typedArray.recycle(); initValue(); } public void initValue(){ mCirclePaint=new Paint(); mCirclePaint.setColor(circleColor); mCirclePaint.setStrokeWidth(2); mCirclePaint.setAntiAlias(true); mCirclePaint.setStyle(Paint.Style.STROKE); mCirclePaintColor=new Paint(); mCirclePaintColor.setAntiAlias(true); mCirclePaintColor.setStyle(Paint.Style.FILL_AND_STROKE); mLineCircle=new Paint(); mLineCircle.setAntiAlias(true); mLineCircle.setStyle(Paint.Style.STROKE); mCircleHoldPaint=new Paint(); mCircleHoldPaint.setAntiAlias(true); mCircleHoldPaint.setStyle(Paint.Style.FILL_AND_STROKE); mCenterCircle=new Paint(Paint.ANTI_ALIAS_FLAG); mCenterCircle.setAntiAlias(true); mCenterCircle.setStyle(Paint.Style.STROKE); mCenterCircle.setTextAlign(Paint.Align.CENTER); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthModel=MeasureSpec.getMode(widthMeasureSpec); int heightModel=MeasureSpec.getMode(heightMeasureSpec); int measureWidth=MeasureSpec.getSize(widthMeasureSpec); int measureHeight=MeasureSpec.getSize(heightMeasureSpec); int width; int height; if(widthModel==MeasureSpec.EXACTLY){ width=measureWidth; }else{ width=getPaddingLeft()+getPaddingRight()+measureWidth; } if(heightModel==MeasureSpec.EXACTLY){ height=measureHeight; }else{ height=(getPaddingLeft()+getPaddingRight()+measureHeight)/2; } setMeasuredDimension(width,height); loadAnimator(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mScreemWidth=w; mScreemHight=h; //得出最大的圆的半径 if(mScreemWidth>mScreemHight){ circleRadius=Float.valueOf((w/3.4)+"").intValue(); }else{ circleRadius=Float.valueOf((h/3.4)+"").intValue(); } if(tempCircleRadius!=0&&tempCircleRadius<=circleRadius){ circleRadius=tempCircleRadius; } //得出每个圆的间隔 marginCircleSize=circleRadius/6; } @Override protected void onDraw(Canvas canvas) { canvas.translate(getWidth()/2,getHeight()/2-(circleRadius/6)); canvas.save(); //画出三条圆圈 drawCircle(canvas); //画出波浪图形 drawWaves(canvas); //画虚线 drawDottedLine(canvas); //画点 drawCircleHold(canvas); //画解释的内容 drawExpain(canvas); //画中心圆的内容 centerCircleContent(canvas); } //画解释的内容 public void drawExpain(Canvas canvas){ if(!expainWatchDag){ return ; } // int margin=circleRadius/5; //画平均步数和对应的数值 Rect txtRect=new Rect(); mCenterCircle.setColor(Color.BLACK); mCenterCircle.setTextSize(circleRadius/6); mCenterCircle.setTypeface(Typeface.SANS_SERIF); canvas.drawText(averageCount,0,circleRadius+margin,mCenterCircle); mCenterCircle.setColor(friendColor); mCenterCircle.setTextSize(circleRadius/10); mCenterCircle.getTextBounds(averageCountTxt,0,averageCountTxt.length(),txtRect); canvas.drawText(averageCountTxt,0,circleRadius+margin+(txtRect.bottom-txtRect.top),mCenterCircle); //画好友排名和对应的数值 mCenterCircle.setColor(Color.BLACK); mCenterCircle.setTextSize(circleRadius/6); canvas.drawText(firendDrank,-circleRadius,-(circleRadius-marginCircleSize),mCenterCircle); mCenterCircle.setColor(friendColor); mCenterCircle.setTextSize(circleRadius/10); mCenterCircle.getTextBounds(friendDrankTxt,0,friendDrankTxt.length(),txtRect); canvas.drawText(friendDrankTxt,-circleRadius,-(circleRadius-marginCircleSize)+(txtRect.bottom-txtRect.top),mCenterCircle); //画达标天数和对应的数值 mCenterCircle.setColor(Color.BLACK); mCenterCircle.setTextSize(circleRadius/6); canvas.drawText(standarDay,circleRadius,-(circleRadius-marginCircleSize),mCenterCircle); mCenterCircle.setColor(friendColor); mCenterCircle.setTextSize(circleRadius/10); mCenterCircle.getTextBounds(friendDrankTxt,0,friendDrankTxt.length(),txtRect); canvas.drawText(standarDayTxt,circleRadius,-(circleRadius-marginCircleSize)+(txtRect.bottom-txtRect.top),mCenterCircle); centerWatchDag=true; } //画中心圆的内容 public void centerCircleContent(Canvas canvas){ if(!centerWatchDag){ return ; } //画出颜色渐变的圆圈 canvas.rotate(140); float centerSize=circleRadius-marginCircleSize*3-(circleRadius/20); mCenterCircle.setShader(new SweepGradient(0,0,new int[]{ friendColor,friendColor,standardColor,averageColor},null)); canvas.drawCircle(0,0,centerSize,mCenterCircle); canvas.rotate(-140); //画出运动的总步数 mCenterCircle.setShader(null); mCenterCircle.setColor(friendColor); mCenterCircle.setTextSize(circleRadius/4); mCenterCircle.setTextAlign(Paint.Align.CENTER); Rect numRect=new Rect(); mCenterCircle.getTextBounds(allStep,0,allStep.length(),numRect); Camera camera=new Camera(); camera.rotateY(centerData); camera.applyToCanvas(canvas); canvas.drawText(allStep,0,(numRect.bottom-numRect.top)/2,mCenterCircle); //画出总运动步数右边的字 Rect tipRect=new Rect(); mCenterCircle.setTextSize(circleRadius/12); mCenterCircle.getTextBounds(tip,0,tip.length(),tipRect); canvas.drawText(tip,(numRect.right-numRect.left)/2+(tipRect.right-tipRect.left)/2+5 ,(numRect.bottom-numRect.top)/2-3,mCenterCircle); //画出总运动步数下面的提示 Rect theyRect=new Rect(); mCenterCircle.getTextBounds(theyCount,0,theyCount.length(),theyRect); float marginBottom=circleRadius/12; mCenterCircle.setTextSize(circleRadius/11); canvas.drawText(theyCount,0,marginBottom+(numRect.bottom-numRect.top)/2 +(theyRect.bottom-theyRect.top)/2,mCenterCircle); } //画圆点和虚线 public void drawDottedLine(Canvas canvas){ if(!lineWatchDag){ return; } for(int i=0;i<3;i++){ canvas.rotate(120); if(i==0){ //画好友排名的虚线 mLineCircle.setTextSize(18); mLineCircle.setColor(friendColor); drawDottedLine(canvas,judgeDotte(mFriendDranking)); }else if(i==1){ //画达标天数的虚线 mLineCircle.setColor(standardColor); drawDottedLine(canvas,judgeDotte(mStandardDay)); }else if(i==2){ //画平均步数的虚线 mLineCircle.setColor(averageColor); drawDottedLine(canvas,judgeDotte(mAverageCount)); } } canvas.restore(); } //判断虚线 public List<Float> judgeDotte(int value){ List<Float> temp=new ArrayList<>(); if(value==1){ temp.add(circleRadius-marginCircleSize*2); temp.add((float)circleRadius); temp.add(circleRadius-marginCircleSize*3); }else if(value==2){ temp.add(circleRadius-marginCircleSize); temp.add((float)circleRadius); temp.add(circleRadius-marginCircleSize*3); }else if(value==3){ temp.add(circleRadius-marginCircleSize*3); temp.add((float)circleRadius); } return temp; } //画虚线 public void drawDottedLine(Canvas canvas,List<Float> data){ if(data.size()==2){ /*当数值是最大的是时候也就是3*/ mLineCircle.setColor(Color.WHITE); Path path=new Path(); path.moveTo(0,data.get(0)); path.lineTo(0,data.get(1)); canvas.drawPath(path,mLineCircle); return ; }else{ /*当数值在1和2的时候*/ //画出数值外的虚线 Path pathOut=new Path(); pathOut.moveTo(0,data.get(0)); pathOut.lineTo(0,data.get(1)); mLineCircle.setPathEffect(new DashPathEffect(new float[]{7,5,7,5},5)); canvas.drawPath(pathOut,mLineCircle); //画出数值内的虚线 Path pathIn=new Path(); pathIn.moveTo(0,data.get(1)); pathIn.lineTo(0,data.get(2)); mLineCircle.setColor(Color.WHITE); canvas.drawPath(pathIn,mLineCircle); } } //画虚线上的圆点 public void drawCircleHold(Canvas canvas){ if(!lineWatchDag){ return; } float[] yuan1=calculatePoint(circleRadius-marginCircleSize*2); float[] yuan2=calculatePoint(circleRadius-marginCircleSize); float[] yuan3=calculatePoint(circleRadius); //画好友排名的圆点 drawCircleHoldImpl(-yuan1[0],-yuan1[1],-yuan2[0],-yuan2[1], -yuan3[0],-yuan3[1],mFriendDranking,canvas,friendColor); //画达标天数的圆点 drawCircleHoldImpl(yuan1[0],-yuan1[1],yuan2[0],-yuan2[1], yuan3[0],-yuan3[1],mStandardDay,canvas,standardColor); //画平均步数的圆点 drawCircleHoldImpl(0,circleRadius-marginCircleSize*2,0,circleRadius-marginCircleSize, 0,circleRadius,mAverageCount,canvas,averageColor); expainWatchDag=true; } //画圆的具体的方法 public void drawCircleHoldImpl(float mCirlce1X,float mCircle1Y,float mCirlce2X,float mCircle2Y, float mCirlce3X,float mCircle3Y,int action,Canvas canvas,int color){ mCircleHoldPaint.setColor(color); if(action==1){ //当数值为3时画所有圆圈 canvas.drawCircle(mCirlce1X,mCircle1Y,8,mCircleHoldPaint); canvas.drawCircle(mCirlce2X,mCircle2Y,8,mCircleHoldPaint); }else if(action==2){ //当数值为2时画中间的圆圈 canvas.drawCircle(mCirlce2X,mCircle2Y,8,mCircleHoldPaint); } //画一定要画的圆圈和圆点 canvas.drawCircle(mCirlce3X,mCircle3Y,8,mCircleHoldPaint); mCircleHoldPaint.setColor(Color.WHITE); canvas.drawCircle(mCirlce1X,mCircle1Y,6,mCircleHoldPaint); canvas.drawCircle(mCirlce2X,mCircle2Y,6,mCircleHoldPaint); canvas.drawCircle(mCirlce3X,mCircle3Y,6,mCircleHoldPaint); } //画出波浪图形 public void drawWaves(Canvas canvas){ if(!waveWatchDag){ return ; } canvas.rotate(waveData); float inCircleRadius=circleRadius-marginCircleSize*3; //最上面的点 float topPointX=0; float topPointY=-inCircleRadius; //左下角的点 float leftBottpmPointX=-(float)Math.sqrt(Math.pow(inCircleRadius,2)-Math.pow(inCircleRadius/2,2)); float leftBottomPointY=inCircleRadius/2; //右小角的点 float rightBottomPointX=-leftBottpmPointX; float rightBottomPointY=inCircleRadius/2; //好友排名半径 float mFriendDrankingData=circleValue(mFriendDranking); //达标天数半径 float mStandarDayData=circleValue(mStandardDay); //平均步数半径 float mAverageCountData=circleValue(mAverageCount); /*画好友排名*/ //得出左上角的圆的坐标 float[] mFriendDrankingPoint=calculatePoint(mFriendDrankingData); //好友排名的X轴坐标 mFriendDrankingX=-mFriendDrankingPoint[0]; //好友排名的Y轴坐标 mFriendDrankingY=-mFriendDrankingPoint[1]; //画出还有排名的波浪线 Path mFriendDrankingPath=new Path(); mFriendDrankingPath.moveTo(leftBottpmPointX,leftBottomPointY); mFriendDrankingPath.lineTo(mFriendDrankingX-6,mFriendDrankingY-6); mFriendDrankingPath.lineTo(topPointX,topPointY); mFriendDrankingPath.lineTo(topPointX+10,topPointY+10); mCirclePaintColor.setPathEffect(new CornerPathEffect(20)); mCirclePaintColor.setColor(friendColor); canvas.drawPath(mFriendDrankingPath,mCirclePaintColor); /*画达标天数*/ //得出右上角的圆的坐标 float[] mStandarDayPoint=calculatePoint(mStandarDayData); //达标天数的X轴坐标 mStandardDayX=mStandarDayPoint[0]; //达标天数的Y轴坐标 mStandardDayY=-mStandarDayPoint[1]; //画出还有达标天数的波浪线 Path mStandarDayPath=new Path(); mStandarDayPath.moveTo(topPointX,topPointY); mStandarDayPath.lineTo(mStandardDayX+6,mStandardDayY-6); mStandarDayPath.lineTo(rightBottomPointX,rightBottomPointY); mStandarDayPath.lineTo(rightBottomPointX-10,rightBottomPointY+10); mCirclePaintColor.setColor(standardColor); canvas.drawPath(mStandarDayPath,mCirclePaintColor); /*平均步数*/ //平均步数的X轴坐标 mAverageCountX=0; //平均步数的Y轴坐标 mAverageCountY=mAverageCountData; //画出还有平均步数的波浪线 Path mAverageCountPath=new Path(); mAverageCountPath.moveTo(rightBottomPointX,rightBottomPointY); mAverageCountPath.lineTo(topPointX,mAverageCountData+8); mAverageCountPath.lineTo(leftBottpmPointX,leftBottomPointY); mAverageCountPath.lineTo(leftBottpmPointX+10,leftBottomPointY+10); mCirclePaintColor.setColor(averageColor); canvas.drawPath(mAverageCountPath,mCirclePaintColor); //最里面的圆 mCirclePaintColor.setColor(Color.WHITE); canvas.drawCircle(0,0,circleRadius-marginCircleSize*3,mCirclePaintColor); } //画出三条圆圈 public void drawCircle(Canvas canvas){ //画出最大的圆 mCirclePaint.setAlpha(mCircleAlpha1); canvas.drawCircle(0,0,circleRadius,mCirclePaint); //画出第二大的圆 mCirclePaint.setAlpha(mCircleAlpha2); canvas.drawCircle(0,0,circleRadius-marginCircleSize,mCirclePaint); mCirclePaintColor.setColor(Color.parseColor("#F1FCFE")); mCirclePaintColor.setAlpha(mCircleAlpha2); canvas.drawCircle(0,0,circleRadius-marginCircleSize-2,mCirclePaintColor); //画出第三大的圆 mCirclePaint.setAlpha(mCircleAlpha3); canvas.drawCircle(0,0,circleRadius-marginCircleSize*2,mCirclePaint); mCirclePaintColor.setColor(Color.parseColor("#E7F9FE")); mCirclePaintColor.setAlpha(mCircleAlpha3); canvas.drawCircle(0,0,circleRadius-marginCircleSize*2-2,mCirclePaintColor); } //算出弧线区域的半径 public float circleValue(int mDataDranking){ if(mDataDranking==1){ return circleRadius-marginCircleSize*2; }else if(mDataDranking==2){ return circleRadius-marginCircleSize; }else if(mDataDranking==3){ return circleRadius; }else{ return circleRadius-marginCircleSize*2; } } //算出右上角或左上角的坐标 public float[] calculatePoint(float radius){ float[] result=new float[2]; float pointY=radius/2; float pointX=(float)Math.sqrt(Math.pow(radius,2)-Math.pow(pointY,2)); result[0]=pointX; result[1]=pointY; return result; } //启动动画的方法 public void loadAnimator(){ final ValueAnimator alphaAmimator3=ValueAnimator.ofInt(0,225); final ValueAnimator alphaAmimator2=ValueAnimator.ofInt(0,225); final ValueAnimator wavesAminator=ValueAnimator.ofInt(-30,0); final ValueAnimator centerAnimator=ValueAnimator.ofFloat(0,360); ValueAnimator alphaAmimator1=ValueAnimator.ofInt(0,225); centerAnimator.setDuration(1000); centerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { centerData=(float)animation.getAnimatedValue(); postInvalidate(); } }); wavesAminator.setDuration(1000); wavesAminator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { waveData=(int)animation.getAnimatedValue(); waveWatchDag=true; if(waveData==0&&lineWatchDag==false){ lineWatchDag=true; centerAnimator.start(); } postInvalidate(); } }); alphaAmimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCircleAlpha3=(int)animation.getAnimatedValue(); postInvalidate(); if(mCircleAlpha3==225){ wavesAminator.start(); } } }); alphaAmimator3.setDuration(250); alphaAmimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCircleAlpha2=(int)animation.getAnimatedValue(); postInvalidate(); if(mCircleAlpha2==225){ alphaAmimator3.start(); } } }); alphaAmimator2.setDuration(250); alphaAmimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCircleAlpha1=(int)animation.getAnimatedValue(); postInvalidate(); if(mCircleAlpha1==225){ alphaAmimator2.start(); } } }); alphaAmimator1.setDuration(250); alphaAmimator1.start(); } }