Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義view之環形等待控件的實現

Android自定義view之環形等待控件的實現

編輯:關於Android編程

 

拖了這麼久才開始更新csdn,著實是懶到家了,寫這篇博客的目的就是為了幫助更多的android入門開發者更多的了解自定義控件,畢竟自定義控件對新手來說還是比較神秘的,多說無益,直接上圖:

\

 

以上就是今天我們要實現的效果,乍一看是不是覺得高端大氣上檔次,完全沒有什麼頭緒怎麼去實現這麼“高端”的東西。還會不定時的反問自己可以嗎?對,你可以的。讓我們一起來學習如何寫這樣的控件吧。

 

【前言】自定義view 的幾個步驟

 

自定義view的屬性在view 的構造方法中獲取我們自定義的屬性的值重寫onMeasure方法(有時不需要重寫這個方法)重寫onDraw方法

 

【正文】

項目結構圖奉上:

\

\

我們先來分析一下這個控件。這個控件主要有兩種顏色,加載的速度,圓環的寬度,好像也沒有其他屬性值了。

1.自定義屬性:attrs.xml

 




    
    
    
    

    
        
        
        
        
    

這裡的format主要常見的有以下幾種屬性:reference 、color、boolean、dimension、float、integer、string、fraction、enum、flag。更多用法以及如何在初始化時獲取相應的值,可以百度,這裡不是我們的重點。

2.在構造方法中獲取我們自定義的屬性:CustomProgressbar.java

 

	// 設置第一圈顏色
	private int mFirstColor=Color.GREEN;
	// 設置第二圈顏色
	private int mSecondColor=Color.RED;
	// 設置圈的寬度
	private int mCircleWidth=20;
	// 設置顏色填充畫筆
	private Paint mPaint;
	// 設置當前進度
	private int mProgress;
	// 設置當前進度加載速度
	private int speed=20;
	// 是否開始下一個
	private boolean isNext = false;

	public CustomProgressbar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public CustomProgressbar(Context context) {
		this(context, null);
	}

	/**
	 * 必要的初始化,獲取一些自定義的值
	 * 
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public CustomProgressbar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// 獲取自定義的屬性集合
		TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomProgressbar, defStyle, 0);
		// 獲取自定義屬性的個數
		int n = array.getIndexCount();
		Log.i(test, 自定義屬性的個數: + n);
		// 遍歷屬性值
		for (int i = 0; i < n; i++) {
			int attr = array.getIndex(i);
			Log.i(test, 自定義的屬性為:+attr);
			switch (attr) {
			case R.styleable.CustomProgressbar_firstColor:
				// 獲取第一圈顏色值
				mFirstColor = array.getColor(attr, Color.GREEN);
				break;
			case R.styleable.CustomProgressbar_secondColor:
				// 獲取第一圈顏色值
				mSecondColor = array.getColor(attr, Color.RED);
				break;
			case R.styleable.CustomProgressbar_circleWidth:
				// 設置默認圈的寬度為20px
				mCircleWidth = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
				break;
			case R.styleable.CustomProgressbar_speed:
				// 獲取默認加載速度
				speed = array.getInt(attr, 20);
				break;
			}
		}
		// 回收
		array.recycle();
		mPaint = new Paint();
		// 繪圖線程 此線程為耗時線程,放在子線程中執行,防止主線程的卡頓
		new Thread() {
			public void run() {
				while (true) {
					mProgress++;
					if (mProgress == 360) {
						mProgress = 0;
						// 如果沒有開始下一個,則設置isNext為true
						if (!isNext) {
							isNext = true;
						} else {
							isNext = false;
						}
					}
					// 刷新UI
					// postInvalidate()此方法可以直接在UI線程調用,invalidate()則需要在handler中進行調用
					postInvalidate();
					try {
						Thread.sleep(speed);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

 

很多童鞋肯定會問,為什麼這個操作要放在thread裡進行操作?重寫view是一個耗時操作,所以我們這裡就直接放在子線程裡進行重繪了,防止程序卡死。還有一個需要注意的就是postInvalidate()方法。postInvalidate()此方法可以直接在UI線程調用,invalidate()則需要在handler中進行調用,想要了解更多的童鞋也可以自己百度兩者之間的區別。


3.重寫onMeasure方法:本例中沒有用到重寫onMeasure方法,此處就不貼代碼了。

4.重寫onDraw方法,進行view 的繪制:CustomProgressbar.java

 

@Override
	protected void onDraw(Canvas canvas) {
		// 獲取圓心的x坐標
		int center = getWidth() / 2;
		// 獲取圓的半徑
		int radius = center - mCircleWidth / 2;
		// 設置填充的寬度
		mPaint.setStrokeWidth(mCircleWidth);
		mPaint.setAntiAlias(true);
		// 設置填充的style
		mPaint.setStyle(Paint.Style.STROKE);
		// new RectF(left, top, right, bottom) 為距離x軸,y軸之間的距離
		// 定義rect的形狀
		RectF f = new RectF(center - radius, center - radius, center + radius, center + radius);
		if (!isNext) {
			// 第一圈顏色完整,第二圈顏色跑
			mPaint.setColor(mFirstColor);// 設置畫筆顏色
			// 畫出圓環
			canvas.drawCircle(center, center, radius, mPaint);
			// 設置圓環顏色
			mPaint.setColor(mSecondColor);
			/*
			 * public void drawArc(RectF oval, float startAngle, float sweepAngle,
			 * boolean useCenter, Paint paint) oval :指定圓弧的外輪廓矩形區域。 startAngle:
			 * 圓弧起始角度,單位為度。 sweepAngle: 圓弧掃過的角度,順時針方向,單位為度。 useCenter:
			 * 如果為True時,在繪制圓弧時將圓心包括在內,通常用來繪制扇形。 paint: 繪制圓弧的畫板屬性,如顏色,是否填充等。
			 */
			canvas.drawArc(f, -90, mProgress, false, mPaint);
		} else {
			// 第一圈顏色完整,第二圈顏色跑
			mPaint.setColor(mSecondColor);// 設置畫筆顏色
			// 畫出圓環
			canvas.drawCircle(center, center, radius, mPaint);
			// 設置圓環顏色
			mPaint.setColor(mFirstColor);
			/*
			 * public void drawArc(RectF oval, float startAngle, float sweepAngle,
			 * boolean useCenter, Paint paint) oval :指定圓弧的外輪廓矩形區域。 startAngle:
			 * 圓弧起始角度,單位為度。 sweepAngle: 圓弧掃過的角度,順時針方向,單位為度。 useCenter:
			 * 如果為True時,在繪制圓弧時將圓心包括在內,通常用來繪制扇形。 paint: 繪制圓弧的畫板屬性,如顏色,是否填充等。
			 */
			canvas.drawArc(f, -90, mProgress, false, mPaint);
		}
	}

 

這裡關於drawArc的方法,我已經加了詳細的注釋,不明白的同學可以自己百度一下。

 

由於上面貼的是片段代碼,這裡給出CustomProgressbar.java的全部代碼:

 

package com.beyole.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;

import com.beyole.circlewaitting.R;

public class CustomProgressbar extends View {

	// 設置第一圈顏色
	private int mFirstColor=Color.GREEN;
	// 設置第二圈顏色
	private int mSecondColor=Color.RED;
	// 設置圈的寬度
	private int mCircleWidth=20;
	// 設置顏色填充畫筆
	private Paint mPaint;
	// 設置當前進度
	private int mProgress;
	// 設置當前進度加載速度
	private int speed=20;
	// 是否開始下一個
	private boolean isNext = false;

	public CustomProgressbar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public CustomProgressbar(Context context) {
		this(context, null);
	}

	/**
	 * 必要的初始化,獲取一些自定義的值
	 * 
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public CustomProgressbar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// 獲取自定義的屬性集合
		TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomProgressbar, defStyle, 0);
		// 獲取自定義屬性的個數
		int n = array.getIndexCount();
		Log.i(test, 自定義屬性的個數: + n);
		// 遍歷屬性值
		for (int i = 0; i < n; i++) {
			int attr = array.getIndex(i);
			Log.i(test, 自定義的屬性為:+attr);
			switch (attr) {
			case R.styleable.CustomProgressbar_firstColor:
				// 獲取第一圈顏色值
				mFirstColor = array.getColor(attr, Color.GREEN);
				break;
			case R.styleable.CustomProgressbar_secondColor:
				// 獲取第一圈顏色值
				mSecondColor = array.getColor(attr, Color.RED);
				break;
			case R.styleable.CustomProgressbar_circleWidth:
				// 設置默認圈的寬度為20px
				mCircleWidth = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
				break;
			case R.styleable.CustomProgressbar_speed:
				// 獲取默認加載速度
				speed = array.getInt(attr, 20);
				break;
			}
		}
		// 回收
		array.recycle();
		mPaint = new Paint();
		// 繪圖線程 此線程為耗時線程,放在子線程中執行,防止主線程的卡頓
		new Thread() {
			public void run() {
				while (true) {
					mProgress++;
					if (mProgress == 360) {
						mProgress = 0;
						// 如果沒有開始下一個,則設置isNext為true
						if (!isNext) {
							isNext = true;
						} else {
							isNext = false;
						}
					}
					// 刷新UI
					// postInvalidate()此方法可以直接在UI線程調用,invalidate()則需要在handler中進行調用
					postInvalidate();
					try {
						Thread.sleep(speed);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// 獲取圓心的x坐標
		int center = getWidth() / 2;
		// 獲取圓的半徑
		int radius = center - mCircleWidth / 2;
		// 設置填充的寬度
		mPaint.setStrokeWidth(mCircleWidth);
		mPaint.setAntiAlias(true);
		// 設置填充的style
		mPaint.setStyle(Paint.Style.STROKE);
		// new RectF(left, top, right, bottom) 為距離x軸,y軸之間的距離
		// 定義rect的形狀
		RectF f = new RectF(center - radius, center - radius, center + radius, center + radius);
		if (!isNext) {
			// 第一圈顏色完整,第二圈顏色跑
			mPaint.setColor(mFirstColor);// 設置畫筆顏色
			// 畫出圓環
			canvas.drawCircle(center, center, radius, mPaint);
			// 設置圓環顏色
			mPaint.setColor(mSecondColor);
			/*
			 * public void drawArc(RectF oval, float startAngle, float sweepAngle,
			 * boolean useCenter, Paint paint) oval :指定圓弧的外輪廓矩形區域。 startAngle:
			 * 圓弧起始角度,單位為度。 sweepAngle: 圓弧掃過的角度,順時針方向,單位為度。 useCenter:
			 * 如果為True時,在繪制圓弧時將圓心包括在內,通常用來繪制扇形。 paint: 繪制圓弧的畫板屬性,如顏色,是否填充等。
			 */
			canvas.drawArc(f, -90, mProgress, false, mPaint);
		} else {
			// 第一圈顏色完整,第二圈顏色跑
			mPaint.setColor(mSecondColor);// 設置畫筆顏色
			// 畫出圓環
			canvas.drawCircle(center, center, radius, mPaint);
			// 設置圓環顏色
			mPaint.setColor(mFirstColor);
			/*
			 * public void drawArc(RectF oval, float startAngle, float sweepAngle,
			 * boolean useCenter, Paint paint) oval :指定圓弧的外輪廓矩形區域。 startAngle:
			 * 圓弧起始角度,單位為度。 sweepAngle: 圓弧掃過的角度,順時針方向,單位為度。 useCenter:
			 * 如果為True時,在繪制圓弧時將圓心包括在內,通常用來繪制扇形。 paint: 繪制圓弧的畫板屬性,如顏色,是否填充等。
			 */
			canvas.drawArc(f, -90, mProgress, false, mPaint);
		}
	}
}

 

 

自定義的控件已經定義結束,接下來就是如何調用我們寫的view了,首先,在我們的主布局文件:activity_main.xml中進行引用:

 



    


這裡注意,我們定義了自己的命名控件,也就是
 xmlns:beyole=http://schemas.android.com/apk/res/com.beyole.circlewaitting
這裡的com.beyole.circlewaitting就是我們應用程序的包名。如何知道我們應用程序的包名?直接在AndroidManifest.xml文件中
\

 

主布局文件裡面沒有更改內容:MainActivity.java

 

package com.beyole.circlewaitting;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
}

 

 

寫到這裡是不是不難了,其實代碼也就這麼一點點,只要多寫多練,就一定會熟能生巧的。
 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved