同樣是自定義view的練習。
圖片錄製有問題,將就看吧。
效果圖:
思路:
1. 繼承ProgressBar
2. 實現其構造器
3. 初始化畫筆 、提取xml屬性
4. 測量
5. 繪圖
傳統進度條
繼承ProgressBar
public class MyProgressBar1_Horizontal extends ProgressBar{}
實現其構造器
public MyProgressBar1_Horizontal(Context context) {
this(context, null);
}
public MyProgressBar1_Horizontal(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyProgressBar1_Horizontal(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
parseStyle(context, attrs);
初始化畫筆 、提取xml屬性
//提取xml屬性
private void parseStyle(Context context, AttributeSet attr) {
TypedArray typedArray = context.obtainStyledAttributes(attr, R.styleable.MyProgressBar1_Horizontal);
color_text = typedArray.getColor(R.styleable.MyProgressBar1_Horizontal_colortext, COLOR_TEXT);
color_fore = typedArray.getColor(R.styleable.MyProgressBar1_Horizontal_colorfore, COLOR_FORE);
color_background = typedArray.getColor(R.styleable.MyProgressBar1_Horizontal_colorbackground, COLOR_BACKGROUND);
height_text = (int) typedArray.getDimension(R.styleable.MyProgressBar1_Horizontal_heighttext, HEIGHT_TEXT);
height_fore = (int) typedArray.getDimension(R.styleable.MyProgressBar1_Horizontal_heightfore, HEIGHT_FORE);
height_background = (int) typedArray.getDimension(R.styleable.MyProgressBar1_Horizontal_heightbacground, HEIGHT_BACKGROUND);
gap = (int) typedArray.getDimension(R.styleable.MyProgressBar1_Horizontal_gap, GAP);
typedArray.recycle();
}
//初始化畫筆
protected void init() {
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStrokeCap(Paint.Cap.ROUND);
}
測量
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
drawWiath = width - getPaddingLeft() - getPaddingRight();
drawHeight = height;
setMeasuredDimension(width, height);
}
private int measureHeight(int heightMeasureSpec) {
if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) {
return Math.max(Math.max(height_background, height_fore), height_text);
}
return MeasureSpec.getSize(heightMeasureSpec);
}
繪圖
@Override
protected synchronized void onDraw(Canvas canvas) {
canvas.save();
// canvas.translate();//這裏沒有移動座標
float percentage = getProgress() * 1.0f / getMax();
String text = getProgress() + "%";
float measureText = paint.measureText(text);
if (measureText + percentage * drawWiath + gap / 2 <= drawWiath) {
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(height_fore);
paint.setColor(color_fore);
canvas.drawLine(0, drawHeight / 2, percentage * drawWiath, drawHeight / 2, paint);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(height_text);
paint.setStrokeWidth(height_text);
paint.setColor(color_text);
canvas.drawText(text, percentage * drawWiath + gap / 2, drawHeight / 2 - (paint.descent() + paint.ascent() / 2), paint);
measureText = paint.measureText(text);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(height_background);
paint.setColor(color_background);
canvas.drawLine(percentage * drawWiath + gap + measureText, drawHeight / 2, drawWiath, drawHeight / 2, paint);
} else {
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(height_fore);
paint.setColor(color_fore);
canvas.drawLine(0, drawHeight / 2, drawWiath - measureText - gap/2, drawHeight / 2, paint);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(height_text);
paint.setStrokeWidth(height_text);
paint.setColor(color_text);
canvas.drawText(text, drawWiath - measureText, (drawHeight - paint.descent() - paint.ascent()) / 2, paint);
}
canvas.restore();
}
其他的大致都是這個思路。
比如圓形的:同樣是重複上面的步驟,只不過測量和繪圖時會有寫不同
測量:以寬高中最小的一方爲圓的半徑
繪製:
@Override
protected synchronized void onDraw(Canvas canvas) {
paint.setDither(true);
paint.setAntiAlias(true);
String text = getProgress() + "%";
float textWidth;
float textHeight = paint.descent() + paint.ascent();
float sweepAngle = getProgress() * 1.0f / getMax() * 360;//角度
RectF rectF = new RectF(0, 0, drawRadius * 2, drawRadius * 2);
canvas.save();
canvas.translate(getPaddingLeft() + maxPaintWidth / 2, getPaddingTop() + maxPaintWidth / 2);
//背景
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(height_background);
paint.setColor(color_background);
canvas.drawCircle(drawRadius, drawRadius, drawRadius, paint);
//前景
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(height_fore);
paint.setColor(color_fore);
canvas.drawArc(rectF, 0, sweepAngle, false, paint);
//文字
paint.setStyle(Paint.Style.FILL);
paint.setColor(color_text);
paint.setTextSize(height_text);
paint.setStrokeWidth(height_text);
textWidth = paint.measureText(text);
canvas.drawText(text, drawRadius - textWidth / 2, drawRadius - textHeight / 2, paint);
canvas.restore();
}
在這裏要注意一點,在繪製文字時候,應該將畫筆設置爲paint.setStyle(Paint.Style.FILL);
如果畫筆仍然爲paint.setStyle(Paint.Style.STROKE);則會出現繪製失敗(繪製亂七八糟的)。
clip類型進度條(我也不知道叫啥)
效果就是效果圖下面的杯子。
顯示
1. 在佈局文件中寫出(不要在意我起什麼名字了)
<sunshine.myapplication.MyProgressBar_2
android:layout_width="wrap_content"
android:layout_marginTop="300dp"
android:layout_height="wrap_content"
sunshine:max="100"
sunshine:progress="80" />
2. 在drawable中創建一個 clip 便籤的xml文件
clipOrientation和gravity 可以控制顯示的方向位置等
loading_progress是杯子的圖片
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="vertical"
android:drawable="@drawable/loading_progress"
android:gravity="bottom" >
</clip>
3. 創建一個ImageView
這個ImageView其實就是顯示出來的控件,只不過我們在這個View上進行了一些小的‘內幕’操作
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/myprogressbar_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="3dp"
android:paddingTop="3dp"
android:scaleType="centerInside"
android:src="@drawable/myprogressbar_2" />
實現
對我們的ImageView進行“內幕”操作
public class MyProgressBar_2 extends FrameLayout {
private final int DEF_MAX = 100;
private final int DEF_PROGRESS = 0;
private int pro = 0;
private int max, progress;
private ClipDrawable drawable;
public MyProgressBar_2(Context context) {
this(context, null);
}
public MyProgressBar_2(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyProgressBar_2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyProgressBar_2);
max = typedArray.getInteger(R.styleable.MyProgressBar_2_max, DEF_MAX);
progress = typedArray.getInteger(R.styleable.MyProgressBar_2_progress, DEF_PROGRESS);
typedArray.recycle();
//看這裏
View view = LayoutInflater.from(context).inflate(R.layout.myprogressbar_2, null);
addView(view);
ImageView imageView = (ImageView) findViewById(R.id.myprogressbar_2);
drawable = (ClipDrawable) imageView.getDrawable();
setProgress(progress);
}
public void setProgress(int progress) {
pro = progress;
if (pro > max)
pro = max;
drawable.setLevel(pro * (10000/ max ));
}
public int getProgress() {
return pro;
}
擴展
我們有時候可能會看見儀表盤這樣的進度條
其實原理還是一樣的
第一個:繪製的起點和中點發送了改變
第二個:其實是以圓直徑爲總長度,根據進度來繪製相應角度的扇形,然後將畫筆設置爲FILL就可以了(當時不知道設置爲fill就可以填充,走了點彎路)
至於那些有顏色漸變的,也就是將畫筆設置一下就可以了,網上有很多資料的。
差不多就到這裏了,學會舉一反三就好了,
分享一個專門做繪圖的第三方庫:XCL:http://www.oschina.net/p/xcl-charts
在鴻洋大神的微博上看見他分享了一個繪圖的,也拿來分享下:SmallChart https://github.com/Idtk/SmallChart
本週任務原應本月15號完成,實際爲12號完成。
任務完成~