Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 自定義View--一個簡單地圓形Progress效果,view--圓形progress

自定義View--一個簡單地圓形Progress效果,view--圓形progress

編輯:關於android開發

自定義View--一個簡單地圓形Progress效果,view--圓形progress


先看效果圖吧

我們要實現一個自定義的再一個圓形中繪制一個弧形的自定義View,思路是這樣的:

  先要創建一個類ProgressView,繼承自View類,然後重寫其中的兩個構造方法,一個是一個參數的,一個是兩個參數的,因為我們要在xml文件中使用該自定義控件,所以必須要定義這個兩個參數的構造函數。創建完了這個類後,我們先不去管它,先考慮我們實現的這個自定義View,我們想讓它的哪些部分可以由使用者自己指定,比如說這個Demo中我們讓他的外面圓的外邊框顏色和寬度,還有扇形部分的顏色,扇形增長的速度等等屬性,這時候我們要在項目工程目錄的res/values目錄下創建一個資源文件命名為attrs(注意,名字隨意,只是大多數情況下都這麼叫而已),然後我們在這個資源文件中添加我們想要的屬性,如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3     <declare-styleable name="ProgressView">
 4         <!--circleColor 設置圓形邊框的顏色  sweepColor設置扇形變換的顏色
 5          startAngle 設置起始角度 sweepStep 設置變換的步長-->
 6         <attr name="circleColor" format="color|reference"></attr>
 7         <attr name="sweepColor" format="color|reference"></attr>
 8         <attr name="startAngle" format="integer"></attr>
 9         <attr name="sweepStep" format="integer"></attr>
10         <attr name="padding" format="integer"></attr>
11     </declare-styleable>
12 </resources>

可以看到,<declare-styleable>標簽中的name屬性是為了方便我們獲取AttributeSet時候使用,而<attr>標簽中name,則是我們希望控件可以自定義的屬性部分,類似於xml文件中的android:name=""等標簽的使用。format屬性是設置該屬性可以接受什麼類型的參數。

定義好了自定義資源類,我們開始寫ProgressView中的主要代碼:

  1 package com.yztc.customprogressview;
  2 
  3 import android.content.Context;
  4 import android.content.res.TypedArray;
  5 import android.graphics.Canvas;
  6 import android.graphics.Color;
  7 import android.graphics.Paint;
  8 import android.graphics.RectF;
  9 import android.util.AttributeSet;
 10 import android.view.View;
 11 
 12 /**
 13  * 自定義的
 14  */
 15 public class ProgressView extends View {
 16     private int sweepStep = 10;//扇形變換的步長(就是角度)
 17     private int padding = 40;//外邊框距離扇形的距離 填充
 18     private int circleColor = Color.GRAY;//邊框的顏色
 19     private int sweepColor = Color.BLUE;//扇形顏色
 20     private int startAngle = 90;//起始角度
 21     //設置外邊框圓的邊框粗細
 22     private int storke = 20;
 23 
 24     private int sweepAngle = 0;//掃過的角度
 25 
 26     private static final int DEFAULT_WIDTH = 200;
 27     private static final int DEFAULT_HEIGHT = 200;
 28 
 29     public ProgressView(Context context) {
 30         super(context);
 31     }
 32 
 33     //如果要在xml文件中使用該自定義控件,則必須重寫兩個參數的構造函數
 34     //因為我們使用自定義的屬性的時候,會默認傳遞過來一個AttributeSet集合
 35     public ProgressView(Context context, AttributeSet attrs) {
 36         super(context, attrs);
 37         TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProgressView);
 38         if (array != null) {
 39             //獲取我們在xml中設置的各個自定義屬性
 40             sweepStep = array.getInteger(R.styleable.ProgressView_sweepStep, sweepStep);
 41             padding = array.getInteger(R.styleable.ProgressView_padding, padding);
 42             circleColor = array.getColor(R.styleable.ProgressView_circleColor, circleColor);
 43             sweepColor = array.getColor(R.styleable.ProgressView_sweepColor, sweepColor);
 44             startAngle = array.getInteger(R.styleable.ProgressView_startAngle, startAngle);
 45 
 46             //回收TypeArray資源
 47             array.recycle();
 48         }
 49     }
 50 
 51     /**
 52      * 先繪制外邊框 --內部扇形
 53      *
 54      * @param canvas
 55      */
 56     @Override
 57     protected void onDraw(Canvas canvas) {
 58         Paint mPaint = new Paint();
 59         mPaint.setAntiAlias(true);  //設置抗鋸齒
 60         //繪制外層的圓框
 61         mPaint.setColor(circleColor);
 62         mPaint.setStrokeWidth(storke);
 63         mPaint.setStyle(Paint.Style.STROKE);//設置圓形為空心的圓
 64         //這裡我們得到控件的Height和Width,根據Heigh和Width來確定圓心的位置,來繪制外層圓
 65         canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2 - storke / 2, mPaint);
 66 //        Log.d("tag", "onDraw: "+getWidth());
 67         invalidate();//請求重新繪制view
 68 
 69         //繪制內部的扇形
 70         mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
 71         mPaint.setColor(sweepColor);
 72         /*
 73         drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)
 74         RectF oval 指定扇形的矩形容器對象 指定圓弧的外輪廓的矩形
 75         float startAngle 表示圓弧的起始角度
 76         float sweepAngle 表示圓弧走過掃過的角度 順時針方向
 77         boolean useCenter 如果設置為true 在繪制圓弧時將圓心包括在內,是指以一個固定的圓心來繪制弧形(扇形),
 78         如果指定為false,則不規則繪制扇形
 79         Paint paint 畫筆 顏色 填充
 80 
 81          public RectF(float left, float top, float right, float bottom)
 82          float left 矩形的左邊點(左切點)的x坐標
 83          float top 矩形上邊點(上切點)的y軸坐標
 84          float right, 矩形的右邊點(右切點)的x坐標
 85          float bottom 矩形的下邊點(下切點)的y坐標
 86          */
 87         //RectF中的四個參數,分別對應其內切圓的四個切點的坐標
 88         RectF rectF = new RectF(padding + storke, padding + storke, getWidth() - padding - storke, getWidth() - padding - storke);
 89         canvas.drawArc(rectF, startAngle, sweepAngle, true, mPaint);
 90 
 91         sweepAngle += sweepStep;//根據步長更新掃過的角度
 92         sweepAngle = sweepAngle > 360 ? 0 : sweepAngle;
 93         invalidate();//重繪view
 94     }
 95 
 96     //因為我們是繼承的View來自定義的View,所以onMeasure()方法要重寫
 97     @Override
 98     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 99         int wMode = MeasureSpec.getMode(widthMeasureSpec);
100         int hMode = MeasureSpec.getMode(heightMeasureSpec);
101         int wSize = MeasureSpec.getSize(widthMeasureSpec);
102         int hSize = MeasureSpec.getSize(heightMeasureSpec);
103 
104         //因為繪制的是圓,所以判斷一下高度或者寬度中的一個就可以。
105         switch (wMode) {
106             case MeasureSpec.AT_MOST://android:layout_width="warp_content"
107                 //獲取屏幕像素
108                 float density = getResources().getDisplayMetrics().density;
109                 wSize = (int) (DEFAULT_WIDTH * density);
110                 hSize = (int) (DEFAULT_HEIGHT * density);
111                 break;
112             //當在xml中指定控件的寬高為match_parent或者指定數值的寬高時,回調以下代碼
113             case MeasureSpec.EXACTLY://android:layout_width="match_parent" android:layout_width="40dp"
114                 wSize = hSize = Math.min(wSize, hSize);
115                 break;
116         }
117         //只要重寫onMeasure()方法,一定要調用以下方法,不然會報錯
118         setMeasuredDimension(wSize, hSize);
119     }
120 }

我們先畫一個外部的圓,也就是都用drawCircle()方法,這裡我們調用getWidth(),getHeight()表示得到布局中設置的控件的尺寸,因為是圓,所以可以使用getWidth()/2來表示圓心位置。而畫內部弧形的時候,確定其圓心位置,左部點的坐標是外面圓的邊框加上弧形與原的間距padding來確定,右側點的x坐標則是getWidth()得到總長度,減去邊框寬度,再減去padding得到,上邊距和下邊距同樣,不明白的畫一個圖立馬明白。大部分不好理解的地方都有注釋,只要認真看不會看不明白的~

然後就是在布局中引入我們的自定義View了:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     xmlns:app="http://schemas.android.com/apk/res-auto"
 6     android:layout_width="match_parent"
 7     android:layout_height="match_parent"
 8     android:paddingBottom="@dimen/activity_vertical_margin"
 9     android:paddingLeft="@dimen/activity_horizontal_margin"
10     android:paddingRight="@dimen/activity_horizontal_margin"
11     android:paddingTop="@dimen/activity_vertical_margin"
12     tools:context="com.yztc.customprogressview.MainActivity">
13 
14     <com.yztc.customprogressview.ProgressView
15         android:id="@+id/pv"
16         android:layout_width="match_parent"
17         android:layout_height="match_parent"
18         android:background="#0000ff"
19         app:padding="20"
20         app:circleColor="#aa0000"
21         app:sweepColor="#00aa00"
22         app:sweepStep="1"
23         app:startAngle="180"
24         />
25 </RelativeLayout>

需要注意的是我們需要在布局的跟標簽下面加上這麼一段代碼:xmlns:app="http://schemas.android.com/apk/res-auto"

用來指定我們可以使用自己再attrs中自定義的屬性啦~,使用的形式就是app:你定義的屬性。當然,這個app也不是固定的寫法,只要跟上面你加的那段代碼的xmlns後面的字段一致就可以了~

 

 

還有需要注意的是:

默認使用Canvas類的drawCircle()方法來畫圓的時候,圓的半徑是你指定的半徑,再加上一半的邊長,比如你的邊框size=10,radius=50,則實際空心部分的半徑為55.注意這點,否則畫出來的圓的四個切點位置會與其他位置有些不一樣,類似出現鋸齒的效果。具體請看drawCircle()的Rect邊框問題。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved