Android 自定義view --圓形百分比(進度條)
起因
最近公司項目有需求需要用到輕量級圖表如下圖,是一些簡單的扇形圖,圓形圖,折線圖,雖然有好用的三方庫MPChart (教程地址http://blog.csdn.net/wingichoy/article/details/50428246), 但是過于龐大,像這樣的簡約的界面明顯不合適,又因為許久沒有堅持寫博客,覺得自己很是墮落,深知自學不易,于是便想寫一些博客來幫助后來像我一樣的初學者,所以便想把這些效果寫一個系列。其中包括: 1.圓形百分比圖表 2.簡易折線圖圖表 3.簡易柱狀圖圖表
效果圖
說了這么多沒有效果圖還是廢話,效果圖如下:
預備知識
本篇博客的預備知識內容有:
1.自定義屬性
2.自定義view
關于以上兩點,可以查看 Hongyang大神的博客:自定義View(一)
知識點補充
如果你已經掌握了以上的基本知識,那么可以開始本篇博客的內容啦。但是還是有幾點內容補充。
1.MeasureSpec對象包含了測量的模式和大小。他是一個32位的int值,其中高兩位為測量的模式,低30位是測量的大小。采用位運算和運行效率有關。所以可以從一個MeasureSpec對象分別獲取模式和值 如:
//獲取模式 值為 EXACTLY AT_MOST UNSPECIFIED int specMode = MeasureSpec.getMode(measureSpec); //獲取測量值 int specSize = MeasureSpec.getSize(measureSpec);2.畫扇形,調用drawArc()方法,其中第一個參數是圓所在的矩形,第二個參數是開始的弧度,值得主意的是,最頂的弧度是270度,而地圖東方向的弧度為0.第三個參數是需要畫的弧度,第四個參數是一個布爾值,表示是否連接圓心,畫為扇形,第五個是Paint,即所需要的畫筆。
canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);
現在開始吧
1.首先分析需求,我們的圓形進度總共分為三層, 最底層是一個大園形,作為底色。 第二層是一個扇形,大小跟底色一樣,用來表示進度。 第三層是一個小圓形,比背景色小,用于實現弧線的效果。 2.新建一個類叫做CirclePercentView.java 他繼承與View類重寫他的構造函數,來獲取他的自定義屬性。
public CirclePercentView(Context context) { this(context, null); } public CirclePercentView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CirclePercentView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 獲取自定義屬性 TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.CirclePercentView, defStyleAttr, 0); //獲取色帶的寬度 mStripeWidth = a.getDimension(R.styleable.CirclePercentView_stripeWidth, PxUtils.dpToPx(30, context)); //獲取當前的百分比 mCurPercent = a.getInteger(R.styleable.CirclePercentView_percent, 0); //獲取小園的顏色 mSmallColor = a.getColor(R.styleable.CirclePercentView_smallColor,0xffafb4db); //獲取大圓的顏色 mBigColor = a.getColor(R.styleable.CirclePercentView_bigColor,0xff6950a1); //獲取中心文字的大小 mCenterTextSize = a.getDimensionPixelSize(R.styleable.CirclePercentView_centerTextSize,PxUtils.spToPx(20,context)); //獲取園的半徑 mRadius = a.getDimensionPixelSize(R.styleable.CirclePercentView_radius,PxUtils.dpToPx(100,context)); }
3.獲取到了自定義屬性以后,我們來測量這個view,告訴系統這個view有多大
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //獲取測量模式 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); //獲取測量大小 int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); //如果為確定大小值,則圓的半徑為寬度/2 if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) { mRadius = widthSize / 2; x = widthSize / 2; y = heightSize / 2; mWidth = widthSize; mHeight = heightSize; } //如果為wrap_content 那么View大小為圓的半徑大小*2 if(widthMode == MeasureSpec.AT_MOST&&heightMode ==MeasureSpec.AT_MOST){ mWidth = (int) (mRadius*2); mHeight = (int) (mRadius*2); x = mRadius; y = mRadius; } //設置視圖的大小 setMeasuredDimension(mWidth,mHeight); }
4.測量完成后,我們就要開始畫view了。首先畫大圓,之后畫扇形圖,最后畫小圓蓋住 就有了圓形進度條的效果,之后把百分比進度文字畫在上面就大功告成啦。
具體步驟如圖:
@Override protected void onDraw(Canvas canvas) { mEndAngle = (int) (mCurPercent * 3.6); //繪制大圓 Paint bigCirclePaint = new Paint(); //消除鋸齒 bigCirclePaint.setAntiAlias(true); bigCirclePaint.setColor(mBigColor); //x,y 為圓心坐標 mRadius為半徑 canvas.drawCircle(x, y, mRadius, bigCirclePaint); //餅狀圖 Paint sectorPaint = new Paint(); sectorPaint.setColor(mSmallColor); sectorPaint.setAntiAlias(true); RectF rect = new RectF(0, 0, mWidth, mHeight); //參數說明見知識補充 canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint); //繪制小圓 Paint smallCirclePaint = new Paint(); smallCirclePaint.setAntiAlias(true); smallCirclePaint.setColor(mBigColor); //圓心是相同的 不過半徑有差別,這個差別就是我們的 色帶寬度 canvas.drawCircle(x, y, mRadius - mStripeWidth, smallCirclePaint); //繪制文本 Paint textPaint = new Paint(); String text = mCurPercent + "%"; textPaint.setTextSize(mCenterTextSize); //測量字符串長度 float textLength = textPaint.measureText(text); textPaint.setColor(Color.WHITE); //把文本畫在圓心居中 canvas.drawText(text, x - textLength/2, y, textPaint); }
值得注意的是,在編寫的過程中,文字的位置總是不對,但是根據畫圖計算, 公式是沒錯的,最后才發現我先測量了字符串長度,又修改了字體的大小導致偏差。所以一定要注意這些細節,先改變字體大小,再去測量。 5.添加setPercent方法
public void setPercent(int percent) { //百分比不可能超過100 如果超過100則拋出異常 if (percent > 100) { throw new IllegalArgumentException("percent must less than 100!"); } setCurPercent(percent); } //內部設置百分比 用于動畫效果 private void setCurPercent(int percent) { mPercent = percent; new Thread(new Runnable() { @Override public void run() { for(int i =0;i<mPercent;i++){ try { Thread.sleep(15); } catch (InterruptedException e) { e.printStackTrace(); } mCurPercent = i; CirclePercentView.this.postInvalidate(); } } }).start(); }
這里在setPercent改變的時候,開啟一個線程,來不斷重繪view,達到一個動畫效果。其實view的動畫效果就是不停地重繪 (即執行onDraw(),因為每次執行onDraw()里面的參數會變化,所以會看到不同的畫面)。這樣便完成了一個輕量級的圓形百分比進度條自定義View。
你可以在https://github.com/githubwing/CirclePercentView克隆到源碼。(求star)
你還可以看本系列第二篇博客:簡易折線圖,鏈接:http://blog.csdn.net/wingichoy/article/details/50434634。
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!