標籤:ogre attribute res rri ted value 決定 介紹 總結
一、背景介紹
我們在項目中,經常會見到圓形進度條,看起來很美觀、直觀。剛好最近項目中有這樣的需求,記錄一下,順便回顧下自訂View的知識。
二、實現思路
自訂View,就是在畫布中繪製View,需要重寫onDraw方法。該View可以拆分成以下幾部分:
1)需要畫一個淺綠色的圓
2)需要畫一個白色的圓
3)圓圈中有進度數位顯示
4)圓圈中可以自訂頂部和底部不同文案的提示
三、主要方法介紹
1、drawArc:由可以看出,該圓需要畫出圓弧表示進度,所以選擇drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)方法。
1)參數:
oval-用於確定圓弧形狀與尺寸的橢圓邊界(即橢圓外切矩形)
startAngle-開始角度(以時鐘3點鐘為0°,逆時針為正方向)
sweepAngle-旋轉角度(以時鐘3點鐘為0°,逆時針為正方向)
useCenter-是否包含圓心
paint-畫筆
2)繪製原理
- 當RectF(float left,float top,float right,float bottom)中right-left等於bottom-top時(長=寬),這時畫出的就是個圓。
- 以矩形中心為圓心,以3點鐘方向為0°,逆時針為正方向,從0°旋轉startAngle度,和橢圓相交得到一條直線和一個焦點。
- 從這條直線開始,正方向旋轉sweepAngle度,得到另一條直線和焦點,這樣就可以得到兩個焦點間的圓弧。
2、drawText(String text, float x, float y, Paint paint):文本的繪製方法。
參數:
text-文本
x-該文本的左邊與螢幕左邊的距離
y-該文本baseline在螢幕上的位置
paint-畫筆
需要注意的是,參數y不是表示豎直方向上的位置,而是該文本baseline在螢幕上的位置。
根據官方API說明,Paint的TextAlign屬性決定了text相對於起始座標x的相對位置。預設left,文本從x的右邊開始繪製,如果是center,則x座標在文本的中間。
baseline的介紹參考:http://www.xyczero.com/blog/article/20/
四、畫圓
1)畫一個背景圓
//1-圓弧的位置:整圓,再繪製進度圓弧 mArcCirclePaint.setColor(mCircleBackgroundColor); mArcCirclePaint.setStrokeWidth(mStrokeWidth); //螢幕寬度 int width = getMeasuredWidth(); RectF rectF = new RectF(); rectF.left = (width-mWidth)/2;//左上方X rectF.top = mWidth*0.1f;//左上方Y rectF.right = (width-mWidth)/2+mWidth;//右上方X rectF.bottom = mWidth*0.9f;//右上方Y if ((rectF.right - rectF.left) > (rectF.bottom- rectF.top)){//正方形矩形,保證畫出的圓不會變成橢圓 float space = (rectF.right - rectF.left) - (rectF.bottom- rectF.top); rectF.left += space/2; rectF.right -= space/2; } canvas.drawArc(rectF,270,360,false,mArcCirclePaint);//第2個參數:時鐘3點處為0度,逆時針為正方向
2)畫進度圓
使用同一個Paint,改變其顏色,在畫布上繪製一樣大小的圓,只是旋轉角度值不一樣。
mArcCirclePaint.setColor(mProgressColor); //設定邊角為圓 mArcCirclePaint.setStrokeCap(Paint.Cap.ROUND); mArcCirclePaint.setStrokeWidth(mInnerStrokeWidth); canvas.drawArc(rectF,270,mAngleValue,false,mArcCirclePaint);
3)繪製文本
不同文本只是位置不一樣,計算好位置就可以繪製出文本了。
//2-文本的位置:置中顯示 int centerX = width/2; //計算文本寬度 int textWidth = (int) mTextPaint.measureText(mText, 0, mText.length()); //計算baseline:垂直方向置中 Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt(); int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top; int textX = centerX-textWidth/2; mTextPaint.setColor(mTextColor); mTextPaint.setTextSize(mTextSize); canvas.drawText(mText,textX,baseline,mTextPaint); if (mTopText != null && !mTopText.equals("")) { textWidth = (int) mTextPaint.measureText(mTopText, 0, mTopText.length()); textX = centerX - textWidth / 2; mTextPaint.setTextSize(mTopTextSize); mTextPaint.setColor(mTopTextColor); canvas.drawText(mTopText, textX, baseline - 20, mTextPaint); } if (mBottomText != null && !mBottomText.equals("")) { textWidth = (int) mTextPaint.measureText(mBottomText, 0, mBottomText.length()); textX = centerX - textWidth / 2;// mTextPaint.reset();// mTextPaint.setAntiAlias(true);// mTextPaint.setLinearText(true); mTextPaint.setTextSize(mTopTextSize); mTextPaint.setColor(mBottomTextColor); canvas.drawText(mBottomText, textX, baseline + 20, mTextPaint); }
五、總結
其實很多的自訂View都是在畫布canvas中畫出來的,看著複雜(其實難在位置的計算),但是只要將其拆分成幾部分,一一畫出再組合就好了。
附上源碼:工程demo
package com.example.ViewDemo;import android.content.Context;import android.graphics.*;import android.util.AttributeSet;import android.view.View;/** * 自訂View方式三:重新繪製,繼承View * 第一步:畫出外圓drawArc * 第二步:畫出進度圓drawArc * 第三步:畫出文本:中間文本,頂部文本,底部文本drawText * Created by cjy on 17/6/14. */public class ArcCircleView extends View { private Context mContext; /** * 文本畫筆 */ private Paint mTextPaint; /** * 圓弧畫筆 */ private Paint mArcCirclePaint; /** * 寬度 */ private float mWidth = 100.0f; /** * 文本 */ private String mText ="0%"; /** * 底部文本 */ private String mTopText =""; /** * 底部文本 */ private String mBottomText =""; /** * 弧度 */ private int mAngleValue = 0; /** * 圓的背景色:預設淺綠色 */ private int mCircleBackgroundColor = 0x4c11af9c; /** * 進度的顏色,預設白色 */ private int mProgressColor = 0xffffffff; /** * 頂部文本的顏色,預設白色 */ private int mTopTextColor = 0xffffffff; /** * 底部文本的顏色,預設白色 */ private int mBottomTextColor = 0xffffffff; /** * 文本的顏色,預設白色 */ private int mTextColor = 0xffffffff; /** * 邊寬 */ private int mStrokeWidth = 8; /** * 進度圓邊寬 */ private int mInnerStrokeWidth = 7; /** * 文字大小 */ private int mTextSize = 12; /** * 頂部文字大小 */ private int mTopTextSize = 10; public ArcCircleView(Context context) { super(context); init(context); } public ArcCircleView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ArcCircleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context){ mContext = context; mTextPaint = new Paint(); //設定消除鋸齒 mTextPaint.setAntiAlias(true); //使文本看起來更清晰 mTextPaint.setLinearText(true); mArcCirclePaint = new Paint(); mArcCirclePaint.setAntiAlias(true); mArcCirclePaint.setStyle(Paint.Style.STROKE); } public void setWidth(float width){ mWidth = width; invalidate(); } public void setText(String text){ mText = text; invalidate(); } public void setTopText(String text){ mTopText = text; invalidate(); } public void setBottomText(String text){ mBottomText = text; invalidate(); } public void setTextColor(int textColor) { this.mTextColor = mContext.getResources().getColor(textColor); invalidate(); } public void setBottomTextColor(int bottomTextColor) { this.mBottomTextColor = mContext.getResources().getColor(bottomTextColor); invalidate(); } public void setTopTextColor(int topTextColor) { this.mTopTextColor = mContext.getResources().getColor(topTextColor); invalidate(); } public void setProgressColor(int progressColor) { this.mProgressColor = mContext.getResources().getColor(progressColor); invalidate(); } public void setCircleBackgroundColor(int circleBackgroundColor) { this.mCircleBackgroundColor = mContext.getResources().getColor(circleBackgroundColor); invalidate(); } public void setStrokeWidth(int strokeWidth){ this.mStrokeWidth = strokeWidth; invalidate(); } public void setInnerStrokeWidth(int innerStrokeWidth){ this.mInnerStrokeWidth = innerStrokeWidth; invalidate(); } public void setTextSize(int textSize){ this.mTextSize = textSize; invalidate(); } public void setTopTextSize(int topTextSize){ this.mTopTextSize = topTextSize; invalidate(); } /** * 設定進度 * @param progress */ public void setProgress(float progress){ int angleValue = (int) ((progress * 1.0)/100 * 360); if (angleValue != 0 && progress <= 100){ mAngleValue = angleValue; mText = String.valueOf(progress)+"%"; } invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //1-圓弧的位置:整圓,再繪製進度圓弧 mArcCirclePaint.setColor(mCircleBackgroundColor); mArcCirclePaint.setStrokeWidth(mStrokeWidth); //螢幕寬度 int width = getMeasuredWidth(); RectF rectF = new RectF(); rectF.left = (width-mWidth)/2;//左上方X rectF.top = mWidth*0.1f;//左上方Y rectF.right = (width-mWidth)/2+mWidth;//右上方X rectF.bottom = mWidth*0.9f;//右上方Y if ((rectF.right - rectF.left) > (rectF.bottom- rectF.top)){//正方形矩形,保證畫出的圓不會變成橢圓 float space = (rectF.right - rectF.left) - (rectF.bottom- rectF.top); rectF.left += space/2; rectF.right -= space/2; } canvas.drawArc(rectF,270,360,false,mArcCirclePaint);//第2個參數:時鐘3點處為0度,逆時針為正方向 mArcCirclePaint.setColor(mProgressColor); //設定邊角為圓 mArcCirclePaint.setStrokeCap(Paint.Cap.ROUND); mArcCirclePaint.setStrokeWidth(mInnerStrokeWidth); canvas.drawArc(rectF,270,mAngleValue,false,mArcCirclePaint); //2-文本的位置:置中顯示 int centerX = width/2; //計算文本寬度 int textWidth = (int) mTextPaint.measureText(mText, 0, mText.length()); //計算baseline:垂直方向置中 Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt(); int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top; int textX = centerX-textWidth/2; mTextPaint.setColor(mTextColor); mTextPaint.setTextSize(mTextSize); canvas.drawText(mText,textX,baseline,mTextPaint); if (mTopText != null && !mTopText.equals("")) { textWidth = (int) mTextPaint.measureText(mTopText, 0, mTopText.length()); textX = centerX - textWidth / 2; mTextPaint.setTextSize(mTopTextSize); mTextPaint.setColor(mTopTextColor); canvas.drawText(mTopText, textX, baseline - 20, mTextPaint); } if (mBottomText != null && !mBottomText.equals("")) { textWidth = (int) mTextPaint.measureText(mBottomText, 0, mBottomText.length()); textX = centerX - textWidth / 2;// mTextPaint.reset();// mTextPaint.setAntiAlias(true);// mTextPaint.setLinearText(true); mTextPaint.setTextSize(mTopTextSize); mTextPaint.setColor(mBottomTextColor); canvas.drawText(mBottomText, textX, baseline + 20, mTextPaint); } }}
Android繪製圓形進度條