/** *@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; } } }