/** *@content:实现计步的环形View *@time:2018-7-30 *@build: */ public class CountStepsAnnularView extends View { private final String TAG = "CountStepsAnnularView"; //文字组 private String mAimText; private float mAimNum;//目标步数 private String mStepText; private float mCurrentNum;//当前步数 //参数组 private float mPadding;//内边距 private float mOuterRaceWidth;//外环宽度 private float mInnerRaceWidth;//内环宽度 private Paint mPaint; private Path mPath; //颜色组 private int mAimTextColor; private int mCurrenStepNumColor; private int mStepTextColor; private int[] mOuterRaceColors; private float [] mOuterRaceColorPositions; private int[] mInnerRaceColors; private float [] mInnerRaceColorsPositions; //动画变量值 private int animation_innerRace; private int animation_currentStep; private boolean mStartAnimation; public CountStepsAnnularView(Context context) { super(context); init(); } public CountStepsAnnularView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public CountStepsAnnularView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } /** * 添加数据的方法 * @param setAimText ”目标“的文字 * @param setStepText “步” 的文字 * @param setAimStepNum 目标步数 * @param setCurrenStepNum 当前步数 * @param aimTextColor 目标文字颜色 * @param currenStepNumColor 当前步数文字颜色 * @param stepTextColor 步的显示颜色 * @param startAnimation 是否启用动画 */ public void setData(String setAimText,String setStepText,float setAimStepNum,float setCurrenStepNum, int aimTextColor,int currenStepNumColor,int stepTextColor,boolean startAnimation){ this.mAimText = setAimText;//设置目标文字 this.mStepText = setStepText;//设置步文字animation_innerRace this.mAimNum = setAimStepNum;//设置目标步数 this.mCurrentNum = setCurrenStepNum;//设置当前步数 animation_innerRace = 0; animation_currentStep = 0 ; if(aimTextColor != 0){ this.mAimTextColor = aimTextColor; }else { mAimTextColor = 0xF0111111; } if(currenStepNumColor != 0){ this.mCurrenStepNumColor = currenStepNumColor; }else { mCurrenStepNumColor = 0xF0111111; } if(stepTextColor != 0){ this.mStepTextColor = stepTextColor; }else { mStepTextColor = 0xF0111111; } this.mStartAnimation = startAnimation; } /** * 设置颜色的方法 * @param outerRaceColors 外环颜色组 例如: int [] colors = new int[]{0xff56F9D0,0xFF4194F9}; * @param outerRaceColorsPositions 外环颜色渐变点 例如: float [] floats = new float[]{0,0.5f}; * @param innerRaceColors 内环颜色组 * @param innerRaceColorspPositions 内环颜色渐变点 * @ps 颜色组和渐变点组 数量须要一致 */ public void setGradientColors(int [] outerRaceColors,float [] outerRaceColorsPositions, int [] innerRaceColors,float[] innerRaceColorspPositions){ this.mOuterRaceColors = outerRaceColors; this.mOuterRaceColorPositions = outerRaceColorsPositions; this.mInnerRaceColors = innerRaceColors; this.mInnerRaceColorsPositions = innerRaceColorspPositions; } private void init(){ mPaint = new Paint(); mPath = new Path(); } private void initData(){ mOuterRaceWidth = getWidth()/10; mPadding = mOuterRaceWidth/2+5; mInnerRaceWidth = mOuterRaceWidth - 3; if(mOuterRaceColors == null){ mOuterRaceColors = new int[]{0xff56F9D0,0xFF4194F9}; mOuterRaceColorPositions = new float[]{0,0.5f}; } if(mInnerRaceColors == null){ mInnerRaceColors = new int[]{0xFF8EF9BE,0xFF26FCB1}; mInnerRaceColorsPositions = new float[]{0,0.5f}; } } //画外环 private void outerRace(Canvas canvas){ mPaint.reset(); mPath.reset(); //setLayerType(LAYER_TYPE_SOFTWARE,null);//关闭硬件加速 mPaint.setAntiAlias(true); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(mOuterRaceWidth); mPaint.setStyle(Paint.Style.STROKE); SweepGradient sg = new SweepGradient(getWidth()/2,getHeight()/2,mOuterRaceColors,mOuterRaceColorPositions); Matrix matrix = new Matrix(); matrix.preRotate(135,getWidth(),getHeight()); sg.setLocalMatrix(matrix); mPaint.setShader(sg); RectF rectF = new RectF(); rectF.left = mPadding; rectF.top = mPadding; rectF.right = getWidth()-mPadding; rectF.bottom = getHeight()-mPadding; mPath.addArc(rectF,135,270); canvas.drawPath(mPath,mPaint); } //画内环 private void innerRace(Canvas canvas){ mPaint.reset(); mPath.reset(); mPaint.setAntiAlias(true); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(mInnerRaceWidth); mPaint.setStyle(Paint.Style.STROKE); SweepGradient sg = new SweepGradient(getWidth()/2,getHeight()/2,mInnerRaceColors,mInnerRaceColorsPositions); Matrix matrix = new Matrix(); matrix.preRotate(135,getWidth(),getHeight()); sg.setLocalMatrix(matrix); mPaint.setShader(sg); RectF rectF = new RectF(); rectF.left = mPadding; rectF.top = mPadding; rectF.right = getWidth() - mPadding; rectF.bottom = getHeight() - mPadding ; float currentNum = (float) 270 * (mCurrentNum / mAimNum); if(mStartAnimation) { //270度是内环最大值,不能够超过270 if (mCurrentNum > mAimNum) { if(animation_innerRace < 270){ animation_innerRace = animation_innerRace + 5; } mPath.addArc(rectF, 135, animation_innerRace); } else { if (animation_innerRace < currentNum) { animation_innerRace = animation_innerRace + 5; } mPath.addArc(rectF, 135, animation_innerRace); } }else { //270度是内环最大值,不能够超过270 if (mCurrentNum > mAimNum) { mPath.addArc(rectF, 135, 270); } else { mPath.addArc(rectF, 135, currentNum); } } canvas.drawPath(mPath,mPaint); } //目标文字 private void titleText(Canvas canvas){ mPath.reset(); mPaint.reset(); String aimNumText = Integer.toString((int)mAimNum); int num = aimNumText.length()+mAimText.length()+mStepText.length()+1; mPaint.setTextAlign(Paint.Align.CENTER); mPaint.setColor(mAimTextColor); mPaint.setAntiAlias(true); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(getWidth()/100); if(num < 10){ mPaint.setTextSize(getWidth()/10); }else { mPaint.setTextSize(getWidth()/(num)+2); } float y = getHeight()/2 - mPadding ; float x = getWidth()/2; canvas.drawText(mAimText+" "+aimNumText+mStepText,x,y,mPaint); } //当前数字 private void currentNumText(Canvas canvas){ mPath.reset(); mPaint.reset(); mPaint.setTextAlign(Paint.Align.CENTER); mPaint.setColor(mCurrenStepNumColor); mPaint.setAntiAlias(true); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(getWidth()/100); mPaint.setTextSize(getWidth()/5); float y = getHeight()/2+getWidth()/10+mPadding; float x = getWidth()/2; if(mStartAnimation) { if (animation_currentStep < mCurrentNum) { if (mCurrentNum < 300) { animation_currentStep++; } else { if (animation_currentStep < mCurrentNum - 500) { animation_currentStep = animation_currentStep + 300; }else if(animation_currentStep < mCurrentNum - 301){ animation_currentStep = animation_currentStep + 50; }else if(animation_currentStep < mCurrentNum -51){ animation_currentStep = animation_currentStep + 20; }else if (animation_currentStep < mCurrentNum -11){ animation_currentStep = animation_currentStep + 5; }else if (animation_currentStep < mCurrentNum){ animation_currentStep = animation_currentStep + 1; } } } canvas.drawText(Integer.toString((int) animation_currentStep), x, y, mPaint); }else { canvas.drawText(Integer.toString((int) mCurrentNum), x, y, mPaint); } } //步文字 private void stepText(Canvas canvas){ mPath.reset(); mPaint.reset(); mPaint.setTextAlign(Paint.Align.CENTER); mPaint.setColor(mStepTextColor); mPaint.setAntiAlias(true); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(getWidth()/100); mPaint.setTextSize(getWidth()/10); float y = getHeight()/2+getWidth()/10+getWidth()/5+5; float x = getWidth()/2; canvas.drawText(mStepText,x,y,mPaint); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); initData(); outerRace(canvas); innerRace(canvas); titleText(canvas); currentNumText(canvas); stepText(canvas); postInvalidateDelayed(1); } }
/** *@content:自定义柱状图View *@time:2018-7-31 *@build: */ public class BarGraphView extends View { private final String TAG = "BarGraphView"; private List<Item> mItemList = new ArrayList<>();; private Paint mPaint; private Paint mPaintTiemText; private Paint mPaintCurrenNumText; private Path mPath; private Path mSrc; private float mWPadding;//宽边距 X边距 private float mHPadding;//高边距 Y边距 private float mSpacing;// item之间的间距 private float mItemWidth; //item 的宽度 private float mItemHeight; //item 的高度 private float mItemNum; // item 的数量 private float mBottomLine; //底线上的Y坐标值 private float mMaxValue; //颜色组 private int[] mItemColors ; private float[] mItemColorsPosition; private int mTiemTextColor; private int mCurrenNumTextColor; public BarGraphView(Context context) { super(context); initPaint(); } public BarGraphView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initPaint(); } public BarGraphView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } /** * 添加数据的方法 * @param item 例子:view.addData(new BarGraphView.Item("12-7",1651)); */ public void addData(Item item){ mItemList.add(item); //计算添加到List中的最大值,而且给最大值增长2000上限 mMaxValue = 0; if(!mItemList.isEmpty()) { for (int j = 0; j < mItemList.size(); j++) { float numA = mItemList.get(j).currenNum; if (mMaxValue < numA) { mMaxValue = numA; } } mMaxValue = mMaxValue + 2000; } } public List<Item> getData(){ return mItemList; } /** * 设置颜色的方法 * @param mItemColors 圆柱体的颜色组 * @param mItemColorsPosition 圆柱体的颜色组渐变点 * @param mTiemTextColor 时间text的颜色 * @param mCurrenNumTextColor 步数text的颜色 */ public void setColors(int[] mItemColors,float[] mItemColorsPosition,int mTiemTextColor,int mCurrenNumTextColor){ this.mItemColors = mItemColors; this.mItemColorsPosition = mItemColorsPosition; this.mTiemTextColor = mTiemTextColor; this.mCurrenNumTextColor = mCurrenNumTextColor; } private void initPaint(){ this.mPaint = new Paint(); this.mPaintTiemText = new Paint(); this.mPaintCurrenNumText = new Paint(); this.mPath = new Path(); this.mSrc = new Path(); } private void initData(){ if(!mItemList.isEmpty()) { mItemNum = mItemList.size(); } if(mItemColors == null){ mItemColors = new int[]{0xFF2BF19E,0xFF1BE2FC}; } if (mItemColorsPosition == null){ mItemColorsPosition = new float[]{0.2f,0.8f}; } if (mTiemTextColor == 0){ mTiemTextColor = Color.BLACK; } if (mCurrenNumTextColor == 0){ mCurrenNumTextColor = Color.BLACK; } mWPadding = getWidth()/20; //宽度内边距 mHPadding = getHeight()/10; //高度内边距 mItemWidth = getWidth()/(10+mItemNum); //圆柱体的宽度 mBottomLine = getHeight()-mHPadding*2; //底部横线坐标 if(mItemList.size() == 1){ //只有一个item时,处理圆柱间距 mSpacing = getWidth()/2 - mItemWidth; }else if (mItemList.size() == 2) { //只有二个item时,处理圆柱间距 mSpacing = getWidth() / 4; }else if (mItemList.size() == 3){ //只有三个item时,处理圆柱间距 mSpacing = getWidth() / 6; }else { mSpacing = ((getWidth() - mWPadding*2 - mItemWidth*mItemNum)/mItemNum)/1.15f; //圆柱体之间的间距 } } /** * 画底部横线 * @param canvas 画布 */ private void drawXline(Canvas canvas){ mPaint.reset(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.BLACK); mPaint.setStrokeWidth(2); int [] colors = new int[]{0xFF7E42FF,0xFF2BB5FA}; float[] colorsPosition = new float[]{0.2f,0.6f}; RadialGradient rg = new RadialGradient(getWidth()/2, getHeight()-mHPadding*2, getWidth(), colors,colorsPosition,Shader.TileMode.CLAMP); mPaint.setShader(rg); canvas.drawLine(mWPadding,getHeight()-mHPadding*2,getWidth()-mWPadding,getHeight()-mHPadding*2,mPaint); } /** * 画圆柱 画日期 画数值 * @param canvas 画布 */ private void drawItem(Canvas canvas){ mPaint.reset(); mPaintTiemText.reset(); mPaintCurrenNumText.reset(); mPath.reset(); //柱状图画笔 mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.FILL); mPaint.setStrokeWidth(5); mPaint.setColor(Color.BLUE); LinearGradient lg = new LinearGradient(0,getHeight(),getWidth(),0,mItemColors,mItemColorsPosition,Shader.TileMode.CLAMP); mPaint.setShader(lg); //日期画笔 mPaintTiemText.setAntiAlias(true); mPaintTiemText.setStyle(Paint.Style.FILL); mPaintTiemText.setStrokeWidth(5); mPaintTiemText.setTextSize(getWidth()/35); mPaintTiemText.setTextAlign(Paint.Align.LEFT); mPaintTiemText.setColor(mTiemTextColor); //数值画笔 mPaintCurrenNumText.setAntiAlias(true); mPaintCurrenNumText.setStyle(Paint.Style.FILL); mPaintCurrenNumText.setStrokeWidth(5); mPaintCurrenNumText.setTextSize(getWidth()/35); mPaintCurrenNumText.setTextAlign(Paint.Align.LEFT); mPaintCurrenNumText.setColor(mCurrenNumTextColor); mItemHeight = (getHeight() - mHPadding * 3) * (mItemList.get(0).currenNum / mMaxValue); if(!mItemList.isEmpty()) { //画第一个圆柱 RectF rect = new RectF(); rect.left = mWPadding + mSpacing; rect.top = mBottomLine - mItemHeight; rect.right = mWPadding + mSpacing + mItemWidth; rect.bottom = mBottomLine; mPath.addRect(rect, Path.Direction.CW); //画日期 canvas.drawText(mItemList.get(0).time, mWPadding + mSpacing, mBottomLine + mHPadding, mPaintTiemText); //画数值 canvas.drawText(Integer.toString((int) (mItemList.get(0).currenNum)), mWPadding + mSpacing, mBottomLine - mItemHeight - 5, mPaintCurrenNumText); //画剩下的圆柱 for (int i = 1; i < mItemList.size(); i++) { Item item = mItemList.get(i); mItemHeight = (getHeight() - mHPadding * 3) * (item.currenNum / mMaxValue); RectF rectF = new RectF(); rectF.left = mWPadding + mSpacing * (i + 1) + mItemWidth * i; rectF.top = mBottomLine - mItemHeight; rectF.right = mWPadding + mSpacing * (i + 1) + mItemWidth * (i + 1); rectF.bottom = mBottomLine; mSrc = new Path();//画单个圆柱 mSrc.addRect(rectF, Path.Direction.CW); mPath.addPath(mSrc);//将单个圆柱添加到mPath中 canvas.drawText(item.time, mWPadding + mSpacing * (i + 1) + mItemWidth * i, mBottomLine + mHPadding, mPaintTiemText);//画日期 canvas.drawText(Integer.toString((int) (item.currenNum)), mWPadding + mSpacing * (i + 1) + mItemWidth * i, mBottomLine - mItemHeight - 5, mPaintCurrenNumText);//画步数 } canvas.drawPath(mPath, mPaint);//一次性添加所有圆柱 }else { mPaintTiemText.setTextSize(getWidth()/20); canvas.drawText("无数据",getWidth()/2,getHeight()/2,mPaintTiemText); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); initData(); drawXline(canvas); drawItem(canvas); } public static class Item { public String time; public float currenNum; public Item (String time,float currenNum){ this.time = time; this.currenNum = currenNum; } } }