很多時候我們需要用一個優美好看的圓之類的來表示進度或者選擇程度,但是android自帶的控件一般很難滿足我們的需求,這時候就到自定義view登場啦!
文章結構:1.解析一個手動選擇的程度圓的自定義view制作 2.解析一個圓環中的圓弧轉動來表示進度的進度圓 (這兩個例子已經幫各位寫好調大小的方法了,復制即可使用)【接下來一段時間,本博主還會持續更新一系列的自定義view,敬請關注。】
先上圖 可以看到上面的就是點擊選擇程度的圓,下面就是用圓弧旋轉表示進度的進度圓
這里寫圖片描述
這里寫圖片描述
一、一個手動選擇的程度圓的自定義view制作
1.先給出代碼,在代碼里面解析
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import com.demo.myview.R;
/**
* Created by ${符柱成} on 2016/8/20.
*/
public class ManualCircle extends View {
private Paint circlePaint, arcPaint, textPaint; //畫圓的筆,畫弧線的筆,畫圓中文字的筆
private RectF rectF; //畫弧線--弧線根據矩形生成
//弧線度數變量
int i = 0;
/**
* 圓環的寬度
*/
private int mCircleWidth;
//中心圓的顏色
private int centerCircleColor;
//圓環的顏色
private int ringColor;
//圓文字的顏色
private int textColor;
public ManualCircle(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar);//將獲取的屬性轉化為我們最先設好的屬性
int n = typedArray.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.CustomProgressBar_circleWidth :
mCircleWidth = (int) typedArray.getDimension(attr, 0);
break;
case R.styleable.CustomProgressBar_centercircleColor :
centerCircleColor=typedArray.getColor(attr,0); //默認黃色
break;
case R.styleable.CustomProgressBar_ringColor :
ringColor=typedArray.getColor(attr,0); //默認綠色
break;
case R.styleable.CustomProgressBar_textColor :
textColor=typedArray.getColor(attr,0); //默認黑色
break;
}
}
typedArray.recycle(); //回收屬性對象
initPaint();
}
private void initPaint() {
//畫文字
textPaint = new TextPaint(0);
textPaint.setColor(textColor);
textPaint.setTextSize(80);
textPaint.setTextAlign(Paint.Align.CENTER);
//實心圓畫筆
circlePaint = new Paint();
circlePaint.setColor(centerCircleColor);
//畫弧線的畫筆
arcPaint = new Paint();
arcPaint.setStyle(Paint.Style.STROKE); //設置不填充中間,樣式為描邊
arcPaint.setColor(ringColor);
//是根據矩形來畫弧線的
rectF = new RectF();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//這是圓心的坐標,這個是在xml設置引用的這個布局控件的大小的中心點到這個布局控件的最左邊
float xy = getWidth() / 2;
//圓圈的半徑 這里是100
float radius = xy - mCircleWidth; //改半徑會造成聯動的,因為圍繞著mCircleWidth這個變量去開展繪制,要理解就要畫圖,大家拿起手上的紙畫一下就好
//設置圓弧 //注意先確定圓弧的寬度,然后根據得到這個布局的中心點,然后進行演算,得到半徑。然后確定一個矩形來畫圓弧。圓弧
rectF.left = xy - radius - mCircleWidth / 2;
rectF.top = xy - radius - mCircleWidth / 2;
rectF.right = xy + radius + mCircleWidth / 2;
rectF.bottom = xy + radius + mCircleWidth / 2;
arcPaint.setStrokeWidth(mCircleWidth);
//畫里面的圓
canvas.drawCircle(xy, xy, radius, circlePaint);
//畫弧線
int progress=i*10/36;
canvas.drawArc(rectF, 270, i, false, arcPaint);
//顯示度數與提示
canvas.drawText(String.valueOf(progress)+"%", xy, xy, textPaint);
}
/**
* 公開一個方法,可以更新弧線的度數,也就是選擇程度啦,設置為單擊一次就增加10%
*/
public void add() {
//超過360度就還原到10度
if (i >= 360) {
i = 36;
postInvalidate(); //通知onDraw重新繪制
} else {
this.i += 36;
postInvalidate();
}
}
}
2.然后給出屬性文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 手動選擇的程度圓-->
<declare-styleable name="CustomProgressBar">
<attr name="circleWidth" format="dimension" />
<attr name="ringColor" format="color" />
<attr name="centercircleColor" format="color" />
<attr name="textColor" format="color" />
</declare-styleable>
<!--用弧度變化表示進度的程度圓,一會就不貼這個的代碼了-->
<declare-styleable name="AutomaticCircleProgress">
<attr name="automaticCircleWidth" format="dimension" />
<attr name="automaticBottomRingColor" format="color" />
<attr name="automaticDrawRingColor" format="color" />
<attr name="automaticCentercircleColor" format="color" />
<attr name="automaticTextColor" format="color" />
</declare-styleable>
</resources>
3.接下來就是給出在xml中的調用啦:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.demo.myview.progressCircle.ProgressCircleActivity">
<!-- 手動選擇的程度圓-->
<com.demo.myview.progressCircle.ManualCircle
android:id="@+id/myview"
android:layout_width="160dp"
android:layout_height="160dp"
android:layout_centerInParent="true"
app:centercircleColor="#FFFF00"
app:circleWidth="11dp"
app:ringColor="#008000"
app:textColor="#000000"></com.demo.myview.progressCircle.ManualCircle>
<!--用弧度變化表示進度的程度圓,一會就不貼這個的代碼了-->
<com.demo.myview.progressCircle.AutomaticCircle
android:id="@+id/automaticCircle"
android:layout_width="160dp"
android:layout_height="160dp"
app:automaticBottomRingColor="#000000"
app:automaticCentercircleColor="#aaa"
app:automaticCircleWidth="20dp"
app:automaticDrawRingColor="#FFFFFF"
app:automaticTextColor="#FFFFFF" />
</LinearLayout>
然后就是為選擇程度的圓添加我們剛剛在view里面暴露的接口方法
public class ProgressCircleActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progress_circle);
//<!-- 手動選擇的程度圓-->
final ManualCircle myView = (ManualCircle) findViewById(R.id.myview);
myView.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
myView.add();
}
});
//<!--用弧度變化表示進度的程度圓,一會就不貼這個的代碼了-->
final AutomaticCircle automaticCircle=(AutomaticCircle)findViewById(R.id.automaticCircle);
automaticCircle.setScore(80);
}
}
二、用弧度變化表示進度的程度圓
1.先給出view的代碼,在代碼里面解析
package com.demo.myview.progressCircle;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import com.demo.myview.R;
/**
* Created by ${符柱成} on 2016/8/21.
*/
public class AutomaticCircle extends View {
private int mScore; //方法傳進來的表示進度
private Paint mBlackPaint, mWhitePaint, mCirclePaint, mTextPaint; //白色圓弧與黑色圓弧
/**
* 圓環的寬度
*/
private int mCircleWidth;
//圓弧的矩形
private RectF mRectF;
//白弧線度數變量
int i = 0;
//根據進度來白圓掃
int count;
//中心圓的顏色
private int centerCircleColor;
//底圓環的顏色
private int bottomRingColor;
//旋轉圓環的顏色
private int drawRingColor;
//圓文字的顏色
private int textColor;
public AutomaticCircle(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AutomaticCircleProgress);//將獲取的屬性轉化為我們最先設好的屬性
int n = typedArray.getIndexCount();
for (int i = 0; i < n; i++) {
//屬性文件在上面已經給出
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.AutomaticCircleProgress_automaticCircleWidth:
mCircleWidth = (int) typedArray.getDimension(attr, 0);
break;
case R.styleable.AutomaticCircleProgress_automaticCentercircleColor:
centerCircleColor = typedArray.getColor(attr, 0);
Log.e("centerColor", String.valueOf(centerCircleColor));
break;
case R.styleable.AutomaticCircleProgress_automaticBottomRingColor:
bottomRingColor = typedArray.getColor(attr, 0);
Log.e("centerColor", String.valueOf(bottomRingColor));
break;
case R.styleable.AutomaticCircleProgress_automaticDrawRingColor:
drawRingColor = typedArray.getColor(attr, 0);
break;
case R.styleable.AutomaticCircleProgress_automaticTextColor:
textColor = typedArray.getColor(attr, 0);
break;
}
}
initPaint();
}
private void initPaint() {
//初始化中心圓的黑色筆
mCirclePaint = new Paint();
//設置抗鋸齒,優化繪制效果的精細度
mCirclePaint.setAntiAlias(true);
//設置圖像抖動處理,也是用于優化圖像的顯示效果
mCirclePaint.setDither(true);
//設置畫筆的顏色
mCirclePaint.setColor(centerCircleColor);
//初始圓弧黑色筆
mBlackPaint = new Paint();
//設置抗鋸齒,優化繪制效果的精細度
mBlackPaint.setAntiAlias(true);
//設置圖像抖動處理,也是用于優化圖像的顯示效果
mBlackPaint.setDither(true);
//設置畫筆的顏色
mBlackPaint.setColor(bottomRingColor);
//設置畫筆的風格為空心
mBlackPaint.setStyle(Paint.Style.STROKE);
//設置“空心”的外框寬度為2dp
mBlackPaint.setStrokeWidth(mCircleWidth);
//初始白色筆
mWhitePaint = new Paint();
mWhitePaint.setAntiAlias(true);
mWhitePaint.setStyle(Paint.Style.STROKE);
mWhitePaint.setStrokeWidth(mCircleWidth);
mWhitePaint.setDither(true);
mWhitePaint.setColor(drawRingColor);
//文本的筆
mTextPaint = new Paint();
//設置文本的字號大小
mTextPaint.setTextSize(40);
mTextPaint.setDither(true);
//設置文本的對其方式為水平居中
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setColor(textColor);
//獲取該view的視圖樹觀察者并添加繪制變化監聽者
//實現有繪制變化時的回調方法
this.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
//2.開啟子線程對繪制用到的數據進行修改
new DrawThread();
getViewTreeObserver().removeOnPreDrawListener(this);
return false;
}
});
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//這是圓心的坐標,這個是在xml設置引用的這個布局控件的大小的中心點到這個布局控件的最左邊
float xy = getWidth() / 2;
//圓圈的半徑
float radius = xy - mCircleWidth; //改半徑會造成聯動的,因為圍繞著mCircleWidth這個變量去開展繪制
//初始化圓弧所需條件(及設置圓弧的外接矩形的四邊)
mRectF = new RectF();
mRectF.set(xy - radius - mCircleWidth / 2, xy - radius - mCircleWidth / 2, xy + radius + mCircleWidth / 2, xy + radius + mCircleWidth / 2);
//畫里面的灰色圓
canvas.drawCircle(xy, xy, radius, mCirclePaint);
//繪制弧形
//黑筆畫的是一個整圓所有從哪里開始都一樣
canvas.drawArc(mRectF, 0, 360, false, mBlackPaint);
//白筆之所以從-90度開始,是因為0度其實使我們的3點鐘的位置,所以-90才是我們的0點的位置
canvas.drawArc(mRectF, -90, i, false, mWhitePaint);
//繪制文本
canvas.drawText(count + "", xy, xy, mTextPaint);
}
//暴露一個方法給外部調用來調整進度
public void setScore(int score) {
this.mScore = score;
}
//開啟子線程,并通過繪制監聽實時更新繪制數據
public class DrawThread implements Runnable {
private final Thread mDrawThread;
private int statek;
public DrawThread() {
mDrawThread = new Thread(this);
mDrawThread.start();
}
@Override
public void run() {
while (true) {
switch (statek) {
case 0://給一點點緩沖的時間
try {
Thread.sleep(200);
statek = 1;
} catch (InterruptedException e) {
}
break;
case 1:
try {//更新顯示的數據
Thread.sleep(20);
i += 3.6f;
count++;
postInvalidate(); //每count加1就去刷新onDraw來刷新圖
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
if (count >= mScore)//滿足該條件就結束循環
break;
}
}
}
}