1. 程式人生 > >Android 打造形形色色的進度條 實現可以如此簡單

Android 打造形形色色的進度條 實現可以如此簡單

轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/43371299 ,本文出自:【張鴻洋的部落格】

1、概述

最近需要用進度條,秉著不重複造輪子的原則,上github上搜索了一番,看了幾個覺得比較好看的ProgressBar,比如:daimajia的等。簡單看了下程式碼,基本都是繼承自View,徹徹底底的自定義了一個進度條。盯著那絢麗滾動條,忽然覺得,為什麼要通過View去寫一個滾動條,系統已經提供了ProgressBar以及屬於它的特性,我們沒必要重新去構建一個,但是系統的又比較醜,不同版本變現還不一定一樣。那麼得出我們的目標:改變系統ProgressBar的樣子。 

  對沒錯,我們沒有必要去從0打造一個ProgressBar,人家雖然長的不好看,但是特性以及穩定性還是剛剛的,我們只需要為其整下容就ok了。 

說到整容,大家都知道我們的控制元件是通過onDraw()畫出來的,那麼我們只需要去覆蓋它的onDraw()方法,自己寫下就ok 。 

對了,我建立了一個微信公眾號,歡迎關注,左邊欄目上掃一掃即可。

  接下來,我們貼下效果圖:

2、效果圖

1、橫向的進度條

2、圓形的進度條


沒錯,這就是我們的進度條效果,橫向的模仿了daimajia的進度條樣子。不過我們繼承子ProgressBar,簡單的為其整個容,程式碼清晰易懂 。為什麼說,易懂呢?

橫向那個進度條,大家會drawLine()和drawText()吧,那麼通過getWidth()拿到控制元件的寬度,再通過getProgress()拿到進度,按比例控制繪製線的長短,字的位置還不是分分鐘的事。

3、實現

橫向的滾動條繪製肯定需要一些屬性,比如已/未到達進度的顏色、寬度,文字的顏色、大小等。
本來呢,我是想通過系統ProgressBar的progressDrawable,從裡面提取一些屬性完成繪製需要的引數的。但是,最終呢,反而讓程式碼變得複雜。所以最終還是改用自定義屬性。 說道自定義屬性,大家應該已經不陌生了。

1、HorizontalProgressBarWithNumber

1、自定義屬性

values/attr_progress_bar.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="HorizontalProgressBarWithNumber">
        <attr name="progress_unreached_color" format="color" />
        <attr name="progress_reached_color" format="color" />
        <attr name="progress_reached_bar_height" format="dimension" />
        <attr name="progress_unreached_bar_height" format="dimension" />
        <attr name="progress_text_size" format="dimension" />
        <attr name="progress_text_color" format="color" />
        <attr name="progress_text_offset" format="dimension" />
        <attr name="progress_text_visibility" format="enum">
            <enum name="visible" value="0" />
            <enum name="invisible" value="1" />
        </attr>
    </declare-styleable>
    
    <declare-styleable name="RoundProgressBarWidthNumber">
        <attr name="radius" format="dimension" />
    </declare-styleable>

</resources>

2、構造中獲取

public class HorizontalProgressBarWithNumber extends ProgressBar
{

	private static final int DEFAULT_TEXT_SIZE = 10;
	private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
	private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
	private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;
	private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
	private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;

	/**
	 * painter of all drawing things
	 */
	protected Paint mPaint = new Paint();
	/**
	 * color of progress number
	 */
	protected int mTextColor = DEFAULT_TEXT_COLOR;
	/**
	 * size of text (sp)
	 */
	protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);

	/**
	 * offset of draw progress
	 */
	protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);

	/**
	 * height of reached progress bar
	 */
	protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);

	/**
	 * color of reached bar
	 */
	protected int mReachedBarColor = DEFAULT_TEXT_COLOR;
	/**
	 * color of unreached bar
	 */
	protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;
	/**
	 * height of unreached progress bar
	 */
	protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
	/**
	 * view width except padding
	 */
	protected int mRealWidth;
	
	protected boolean mIfDrawText = true;

	protected static final int VISIBLE = 0;

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

	public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,
			int defStyle)
	{
		super(context, attrs, defStyle);
		
		setHorizontalScrollBarEnabled(true);

		obtainStyledAttributes(attrs);

		mPaint.setTextSize(mTextSize);
		mPaint.setColor(mTextColor);

	}
	
	/**
	 * get the styled attributes
	 * 
	 * @param attrs
	 */
	private void obtainStyledAttributes(AttributeSet attrs)
	{
		// init values from custom attributes
		final TypedArray attributes = getContext().obtainStyledAttributes(
				attrs, R.styleable.HorizontalProgressBarWithNumber);

		mTextColor = attributes
				.getColor(
						R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
						DEFAULT_TEXT_COLOR);
		mTextSize = (int) attributes.getDimension(
				R.styleable.HorizontalProgressBarWithNumber_progress_text_size,
				mTextSize);

		mReachedBarColor = attributes
				.getColor(
						R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,
						mTextColor);
		mUnReachedBarColor = attributes
				.getColor(
						R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
						DEFAULT_COLOR_UNREACHED_COLOR);
		mReachedProgressBarHeight = (int) attributes
				.getDimension(
						R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
						mReachedProgressBarHeight);
		mUnReachedProgressBarHeight = (int) attributes
				.getDimension(
						R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,
						mUnReachedProgressBarHeight);
		mTextOffset = (int) attributes
				.getDimension(
						R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,
						mTextOffset);

		int textVisible = attributes
				.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,
						VISIBLE);
		if (textVisible != VISIBLE)
		{
			mIfDrawText = false;
		}
		attributes.recycle();
	}

嗯,看起來程式碼挺長,其實都是在獲取自定義屬性,沒什麼技術含量。

3、onMeasure

剛才不是出onDraw裡面寫寫就行了麼,為什麼要改onMeasure呢,主要是因為我們所有的屬性比如進度條寬度讓使用者自定義了,所以我們的測量也得稍微變下。

	@Override
	protected synchronized void onMeasure(int widthMeasureSpec,
			int heightMeasureSpec)
	{
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);

		if (heightMode != MeasureSpec.EXACTLY)
		{

			float textHeight = (mPaint.descent() + mPaint.ascent());
			int exceptHeight = (int) (getPaddingTop() + getPaddingBottom() + Math
					.max(Math.max(mReachedProgressBarHeight,
							mUnReachedProgressBarHeight), Math.abs(textHeight)));

			heightMeasureSpec = MeasureSpec.makeMeasureSpec(exceptHeight,
					MeasureSpec.EXACTLY);
		}
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

	}

寬度我們不變,所以的自定義屬性不涉及寬度,高度呢,只考慮不是EXACTLY的情況(使用者明確指定了,我們就不管了),根據padding和進度條寬度算出自己想要的,如果非EXACTLY下,我們進行exceptHeight封裝,傳入給控制元件進行測量高度。

測量完,就到我們的onDraw了~~~

4、onDraw

@Override
	protected synchronized void onDraw(Canvas canvas)
	{
		canvas.save();
		//畫筆平移到指定paddingLeft, getHeight() / 2位置,注意以後座標都為以此為0,0
		canvas.translate(getPaddingLeft(), getHeight() / 2);

		boolean noNeedBg = false;
		//當前進度和總值的比例
		float radio = getProgress() * 1.0f / getMax();
		//已到達的寬度
		float progressPosX = (int) (mRealWidth * radio);
		//繪製的文字
		String text = getProgress() + "%";

		//拿到字型的寬度和高度
		float textWidth = mPaint.measureText(text);
		float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;

		//如果到達最後,則未到達的進度條不需要繪製
		if (progressPosX + textWidth > mRealWidth)
		{
			progressPosX = mRealWidth - textWidth;
			noNeedBg = true;
		}

		// 繪製已到達的進度
		float endX = progressPosX - mTextOffset / 2;
		if (endX > 0)
		{
			mPaint.setColor(mReachedBarColor);
			mPaint.setStrokeWidth(mReachedProgressBarHeight);
			canvas.drawLine(0, 0, endX, 0, mPaint);
		}
	
		// 繪製文字
		if (mIfDrawText)
		{
			mPaint.setColor(mTextColor);
			canvas.drawText(text, progressPosX, -textHeight, mPaint);
		}

		// 繪製未到達的進度條
		if (!noNeedBg)
		{
			float start = progressPosX + mTextOffset / 2 + textWidth;
			mPaint.setColor(mUnReachedBarColor);
			mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
			canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
		}

		canvas.restore();

	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh)
	{
		super.onSizeChanged(w, h, oldw, oldh);
		mRealWidth = w - getPaddingRight() - getPaddingLeft();

	}

其實核心方法就是onDraw了,但是呢,onDraw也很簡單,繪製線、繪製文字、繪製線,結束。

還有兩個簡單的輔助方法:

	/**
	 * dp 2 px
	 * 
	 * @param dpVal
	 */
	protected int dp2px(int dpVal)
	{
		return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
				dpVal, getResources().getDisplayMetrics());
	}

	/**
	 * sp 2 px
	 * 
	 * @param spVal
	 * @return
	 */
	protected int sp2px(int spVal)
	{
		return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
				spVal, getResources().getDisplayMetrics());

	}

好了,到此我們的橫向進度就結束了,是不是很簡單~~如果你是自定義View,你還得考慮progress的更新,考慮狀態的銷燬與恢復等等複雜的東西。

接下來看我們的RoundProgressBarWidthNumber圓形的進度條。

2、RoundProgressBarWidthNumber 

圓形的進度條和橫向的進度條基本變數都是一致的,於是我就讓RoundProgressBarWidthNumber extends HorizontalProgressBarWithNumber 了。

然後需要改變的就是測量和onDraw了:

完整程式碼:

package com.zhy.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.util.AttributeSet;

import com.zhy.library.view.R;

public class RoundProgressBarWidthNumber extends
		HorizontalProgressBarWithNumber {
	/**
	 * mRadius of view
	 */
	private int mRadius = dp2px(30);

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

	public RoundProgressBarWidthNumber(Context context, AttributeSet attrs) {
		super(context, attrs);

		mReachedProgressBarHeight = (int) (mUnReachedProgressBarHeight * 2.5f);
		TypedArray ta = context.obtainStyledAttributes(attrs,
				R.styleable.RoundProgressBarWidthNumber);
		mRadius = (int) ta.getDimension(
				R.styleable.RoundProgressBarWidthNumber_radius, mRadius);
		ta.recycle();

		mTextSize = sp2px(14);

		mPaint.setStyle(Style.STROKE);
		mPaint.setAntiAlias(true);
		mPaint.setDither(true);
		mPaint.setStrokeCap(Cap.ROUND);

	}

	@Override
	protected synchronized void onMeasure(int widthMeasureSpec,
			int heightMeasureSpec) {
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);

		int paintWidth = Math.max(mReachedProgressBarHeight,
				mUnReachedProgressBarHeight);

		if (heightMode != MeasureSpec.EXACTLY) {

			int exceptHeight = (int) (getPaddingTop() + getPaddingBottom()
					+ mRadius * 2 + paintWidth);
			heightMeasureSpec = MeasureSpec.makeMeasureSpec(exceptHeight,
					MeasureSpec.EXACTLY);
		}
		if (widthMode != MeasureSpec.EXACTLY) {
			int exceptWidth = (int) (getPaddingLeft() + getPaddingRight()
					+ mRadius * 2 + paintWidth);
			widthMeasureSpec = MeasureSpec.makeMeasureSpec(exceptWidth,
					MeasureSpec.EXACTLY);
		}

		super.onMeasure(heightMeasureSpec, heightMeasureSpec);

	}

	@Override
	protected synchronized void onDraw(Canvas canvas) {

		String text = getProgress() + "%";
		// mPaint.getTextBounds(text, 0, text.length(), mTextBound);
		float textWidth = mPaint.measureText(text);
		float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;

		canvas.save();
		canvas.translate(getPaddingLeft(), getPaddingTop());
		mPaint.setStyle(Style.STROKE);
		// draw unreaded bar
		mPaint.setColor(mUnReachedBarColor);
		mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
		canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
		// draw reached bar
		mPaint.setColor(mReachedBarColor);
		mPaint.setStrokeWidth(mReachedProgressBarHeight);
		float sweepAngle = getProgress() * 1.0f / getMax() * 360;
		canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2), 0,
				sweepAngle, false, mPaint);
		// draw text
		mPaint.setStyle(Style.FILL);
		canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight,
				mPaint);

		canvas.restore();

	}

}

首先獲取它的專有屬性mRadius,然後根據此屬性去測量,測量完成繪製;

繪製的過程呢?

先繪製一個細一點的圓,然後繪製一個粗一點的弧度,二者疊在一起就行。文字呢,繪製在中間~~~總體,沒什麼程式碼量。

好了,兩個進度條就到這了,是不是發現簡單很多。總體設計上,存在些問題,如果抽取一個BaseProgressBar用於獲取公共的屬性;然後不同樣子的進度條繼承分別實現自己的測量和樣子,這樣結構可能會清晰些~~~

4、使用

佈局檔案

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:zhy="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="25dp" >

        <com.zhy.view.HorizontalProgressBarWithNumber
            android:id="@+id/id_progressbar01"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dip"
            android:padding="5dp" />

       

        <com.zhy.view.HorizontalProgressBarWithNumber
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dip"
            android:padding="5dp"
            android:progress="50"
            zhy:progress_text_color="#ffF53B03"
            zhy:progress_unreached_color="#ffF7C6B7" />

        <com.zhy.view.RoundProgressBarWidthNumber
            android:id="@+id/id_progress02"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dip"
            android:padding="5dp"
            android:progress="30" />

        <com.zhy.view.RoundProgressBarWidthNumber
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dip"
            android:padding="5dp"
            android:progress="50"
            zhy:progress_reached_bar_height="20dp"
            zhy:progress_text_color="#ffF53B03"
            zhy:radius="60dp" />
     
    </LinearLayout>

</ScrollView>

MainActivity

package com.zhy.sample.progressbar;

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

import com.zhy.annotation.Log;
import com.zhy.view.HorizontalProgressBarWithNumber;

public class MainActivity extends Activity {

	private HorizontalProgressBarWithNumber mProgressBar;
	private static final int MSG_PROGRESS_UPDATE = 0x110;

	private Handler mHandler = new Handler() {
		@Log
		public void handleMessage(android.os.Message msg) {
			int progress = mProgressBar.getProgress();
			mProgressBar.setProgress(++progress);
			if (progress >= 100) {
				mHandler.removeMessages(MSG_PROGRESS_UPDATE);
				
			}
			mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE, 100);
		};
	};

	@Log
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mProgressBar = (HorizontalProgressBarWithNumber) findViewById(R.id.id_progressbar01);
		mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE);

	}

}

最後,本篇部落格的目的呢?就是為了說下,類似ProgressBar這樣的控制元件,如果你只是想去改變顯示的樣子,完全沒必要從0去建立,複寫onDraw即可,當然是個人觀點,提出供大家參考。



相關推薦

Android 打造形形色色進度 實現可以如此簡單

1、概述 最近需要用進度條,秉著不重複造輪子的原則,上github上搜索了一番,看了幾個覺得比較好看的ProgressBar,比如:daimajia的等。簡單看了下程式碼,基本都是繼承自View,徹徹底底的自定義了一個進度條。盯著那絢麗滾動條,忽然覺得,為什麼要通過View去寫

Android 打造形形色色進度 實現可以如此簡單

轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/43371299 ,本文出自:【張鴻洋的部落格】1、概述最近需要用進度條,秉著不重複造輪子的原則,上github上搜索了一番,看了幾個覺得比較好看的Progre

Android原生繪圖進度+簡單自定義屬性程式碼生成器

零、前言 1.感覺切拼字串是個很有意思的事,好的拼接方式可以自動生成一些很實用的東西 2.本文自定義控制元件並不是很高大上的東西,目的在於計錄自定義控制元件的書寫規範與行文流程 3.建議大家自定義控制元件時自定義屬性有自己專屬字首,有利無害,何樂不為 4.本文是根據鴻洋在慕課網上的教程敲的:詳見,自己

linux—進度彩色版簡單實現

一、緩衝區理解: 1.無緩衝:將所得到的資訊馬上顯示出來。 2.行緩衝:輸入輸出遇到換行才執行的I/O操作,比如鍵盤操作。 3.全緩衝:輸入輸出寫滿緩衝區蔡執行I/O操作。比如磁碟讀寫。 當我們在實現的時候需要使用fflush(stdout)來重新整理緩衝區,以

Android】一、Progress進度實現的三種方式:主執行緒實現,Service載入,動態建立

前言 更新版本,上傳資料到服務端,都是需要進度顯示的,Android進度顯示兩種方式 ProgressDialog 和 ProgressBar 新版本中ProgressDialog不被推薦使用,所以專案採用ProgressBar 分為三種實現方式: 1、MainAct

Android自定義圓形進度實現程式碼

基本思路是這樣的: 1.首先繪製一個實心圓 2.繪製一個白色實心的正方形,遮住實心圓 3.在圓的中心動態繪製當前進度的百分比字元 4.繪製一個與之前實心圓相同顏色的空心圓 5.逐漸改變當前的百分比 6.根據百分比,逐漸改變正方形的大小,逐漸減小正方形的底部y軸的座標,不斷重繪

Android檔案下載進度實現

package com.pocketdigi.download;    import java.io.FileOutputStream;    import java.io.IOException;    import java.io.InputStream;    import java.net.URL; 

Android花樣loading進度(二)-簡單環形進度

背景 Android花樣loading進度條系列文章主要講解如何自定義所需的進度條,包括水平、圓形、環形、圓弧形、不規則形狀等。 本篇我們從圓形進度條講起,講簡單形式的環形進度條,只有進度色彩,沒有進度文字,主要是使用Canvas繪製圓和圓弧。 效果

Android閃屏頁圓形倒計時進度實現

前言 現在我們的App中基本都會有閃屏頁面,而閃屏頁中大多又都會加入廣告資訊或者我們自己logo等宣傳圖片的展示,類似如下效果: 思路 使用自定義View,通過View的重繪方法Invalidate()在onDraw()中不斷繪製不同弧度的圓弧來改

Android 自定義進度ColorfulProgressBar,原理簡單、效果很棒

Android-ColorfulProgressBar 簡介: 這是一個自定義的Progressbar,效果看著還行吧,滾動的雙色斜條作為進度條,有點類似Bootstrap風格。原生Progress的基本操作都有,自行觀摩我的原始碼吧,挺簡單的。

Android 仿微信載入H5頁面進度實現

前言 Android中WebView打卡前端頁面時受到網路環境,頁面內容大小的影響有時候會讓使用者等待很久。顯示一個載入進度條可以提升很大的體驗。微信內訪問H5頁面載入效果不錯,效仿著寫了一個。 1

jquery 簡單進度實現程式碼

效果圖 需要用到的圖片: 背景圖片: 進度顯示圖片: 網頁結構: 複製程式碼 程式碼如下: <div id="center"> <div id="message"></div> <div id="loading">

Android更新帶進度的通知欄

text linear archive last sys package 初始 麻煩 httputils 在網上查詢了下。Android版本號更新通知欄帶進度條,醉了,基本都是復制過來。有的代碼不全,連源代碼下載都沒有。有下載也須要積分,還不能用,真黑心啊!!之前自己也

aNDROID自定義進度顏色

定義 hao123 自定義進度條 com list andro 顏色 androi baidu DIaLOGFRaGMENT%E9%97%AE%E9%A2%98%E6%B1%82%E8%A7%A3 http://music.baidu.com/songlist/49564

javascript使用ajax下載文件進度實現

javascript使用ajax下載文件代碼: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="te

PHP 遠程文件下載的進度實現

其他 compact AS lose 信息 tint spinner ajax style download.php 1 <?php 2 // 當前文件:download.php 3 4 $action = @$_GET[‘action‘]; 5

進度 ProgressBar的簡單運用

進度條 ProgressBar 1 常用屬性 style=”?android:attr/progressBarStyleHorizontal” 預設為圓形 android:progress=”33” android:max=”100” 執行緒休眠 Thread.sleep(100

android:漸變色進度(圓環)

public class CircleView extends View { private Paint paint;//畫筆 private Paint textPaint;//文言畫筆 private RectF oval;//rectF物件(圓環) priv

頁面載入進度實現——readyState和onreadystatechange

document.readyState 屬性返回當前文件的狀態(載入中……)。 共有四種取值: 1,uninitialized - 還未開始載入  uninitialized  英 [ʌnɪ'nɪʃlaɪzd]  未初始化 2,loading

自定義控制元件Android圓環進度

Android自定義控制元件學習之圓環進度條,學習了一段時間,自定義控制元件,對一些自定義所需要的Api,基本上也掌握了,但是對於比較複雜的自定義控制元件,他們的座標計算 一直比較噁心(可能,我數學比較差~),記錄自定義控制元件學習過程。    對於圓環進度條的自定義