【朝花夕拾】Android自定義View篇之(四)自定義View的三種實現方式及自定義屬性詳解

宋者為王發表於2019-06-05

前言

       儘管Android系統提供了不少控制元件,但是有很多酷炫效果仍然是系統原生控制元件無法實現的。好在Android允許自定義控制元件,來彌補原生控制元件的不足。但是在很多初學者看來,自定義View似乎很難掌握。其中有很大一部分原因是我們平時看到的自定義View使用中,有多種形式,有的寥寥數筆,有的邏輯很複雜,有的直接繼承View或ViewGroup,有的卻直接繼承系統的原生控制元件,有的可以直接使用系統定義的屬性,而有的卻自定義了自己的屬性......所以不明白使用規則的開發者,很容易被這隻“紙老虎”嚇到。

       實際上實現自定義View的方式,從整體上看,只分為三種:組合控制元件,繼承控制元件,自繪控制元件。然後就是根據需要來新增自定義的屬性,就這麼簡單。本文將會針對這4個方面進行詳細的講解。主要內容如下:

 

 

 

一、組合控制元件

       組合控制元件,顧名思義,就是將系統原有的控制元件進行組合,構成一個新的控制元件。這種方式下,不需要開發者自己去繪製圖上顯示的內容,也不需要開發者重寫onMeasure,onLayout,onDraw方法來實現測量、佈局以及draw流程。所以,在實現自定義view的三種方式中,這一種相對比較簡單。

       實際開發中,標題欄就是一個比較常見的例子。因為在一個app的各個介面中,標題欄基本上是大同小異,複用率很高。所以經常會將標題欄單獨做成一個自定義view,在不同的介面直接引入即可,而不用每次都把標題欄佈局一遍。本節就自定義一個標題欄,包含標題和返回按鈕兩個控制元件,來介紹這種組合控制元件的實現方式。

  1、定義標題欄佈局檔案

       定義標題欄的佈局檔案custom_title_view.xml,將返回按鈕和標題文字進行組合。這一步用於確定標題欄的樣子,程式碼如下所示:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="wrap_content"
 5     android:background="@android:color/holo_orange_light">
 6     <Button
 7         android:id="@+id/btn_left"
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:layout_centerVertical="true"
11         android:layout_marginLeft="5dp"
12         android:text="Back"
13         android:textColor="@android:color/white" />
14 
15     <TextView
16         android:id="@+id/title_tv"
17         android:layout_width="wrap_content"
18         android:layout_height="wrap_content"
19         android:layout_centerInParent="true"
20         android:text="Title"
21         android:textColor="@android:color/white"
22         android:textSize="20sp" />
23 </RelativeLayout>

這個佈局很簡單,就不多說了。

 

  2、根據給定佈局實現自定義View

 1 public class CustomTitleView extends FrameLayout implements View.OnClickListener {
 2     private View.OnClickListener mLeftOnClickListener;
 3     private Button mBackBtn;
 4     private TextView mTittleView;
 5 
 6     public CustomTitleView(@NonNull Context context, @Nullable AttributeSet attrs) {
 7         super(context, attrs);
 8         LayoutInflater.from(context).inflate(R.layout.custom_title_view, this);
 9         mBackBtn = findViewById(R.id.btn_left);
10         mBackBtn.setOnClickListener(this);
11         mTittleView = findViewById(R.id.title_tv);
12     }
13 
14     @Override
15     public void onClick(View v) {
16         switch (v.getId()) {
17             case R.id.btn_left:
18                 if (mLeftOnClickListener != null) {
19                     mLeftOnClickListener.onClick(v);
20                 }
21                 break;
22         }
23     }
24 
25     public void setLeftOnClickListener(View.OnClickListener leftOnClickListener) {
26         mLeftOnClickListener = leftOnClickListener;
27     }
28 
29     public void setTittle(String title){
30         mTittleView.setText(title);
31     }
32 }

為了編譯理解和記憶,這裡對該部分做一點說明:

    (1)程式碼中對外提供了兩個介面,一是動態設定標題,二是使用者可以自定義返回按鈕的點選事件。

    (2)CustomTitleView的建構函式,要選擇兩個引數的,選擇其它引數的建構函式會報錯。這一點是筆者開發機測試的結果,暫時不清楚是不是所有手機上都是這樣。

    (3)這裡是繼承的FrameLayout,但是繼承LinearLayout,RelativeLayout等系統佈局控制元件都可以。之所以要繼承這些系統現成的ViewGroup,是因為這樣可以不用再重寫onMeasure,onLayout等,這樣省事很多。由於這裡是一個佈局控制元件,要用LayoutInflater來填充,所以需要繼承ViewGroup,如果繼承View的直接子類,編譯會不通過。所以,CustomTitleView自己就是一個容器,完全可以當成容器使用,此時CustomTitleView自身的內容會和其作為父佈局新增的子控制元件,效果會疊加,具體的疊加效果是根據繼承的容器特性決定的。

 

  3、在Activity的佈局檔案中新增CustomTitleView

       在Activity的佈局檔案activity_custom_view_compose_demo.xml中,像使用系統控制元件一樣使用CustomTitleView即可。前說了,CustomTitleView自己就是繼承的現成的系統佈局,所以它們擁有的屬性特性,CustomTitleView一樣擁有。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent">
 5     <com.example.demos.customviewdemo.CustomTitleView
 6         android:id="@+id/customview_title"
 7         android:layout_width="match_parent"
 8         android:layout_height="wrap_content">
 9     </com.example.demos.customviewdemo.CustomTitleView>
10 </RelativeLayout>

 

  4、在Activity中操作CustomTitleView

 1 public class CustomViewComposeDemoActivity extends AppCompatActivity {
 2 
 3     private CustomTitleView mCustomTitleView;
 4     @Override
 5     protected void onCreate(Bundle savedInstanceState) {
 6         super.onCreate(savedInstanceState);
 7         setContentView(R.layout.activity_custom_view_compose_demo);
 8         mCustomTitleView = findViewById(R.id.customview_title);
 9         mCustomTitleView.setTittle("This is Title");
10         mCustomTitleView.setLeftOnClickListener(new View.OnClickListener() {
11             @Override
12             public void onClick(View v) {
13                 finish();
14             }
15         });
16 
17     }
18 }

在第8行中,獲取到CustomTitleView例項,第9行設定標題文字,第10行自定義“Back”按鈕點選事件。

 

  5、效果圖

       按照如上的4步,就通過組合控制元件完成了一個比較簡單的自定義標題欄。可見,這種方式是非常簡單的。

 

二、繼承控制元件

       通過繼承系統控制元件(View子類控制元件或ViewGroup子類控制元件)來完成自定義View,一般是希望在原有系統控制元件基礎上做一些修飾性的修改,而不會做大幅度的改動,如在TextView的文字下方新增下劃線,在LinearLayout佈局中加一個蒙板等。這種方式往往都會複用系統控制元件的onMeasure和onLayout方法,而只需要重寫onDraw方法,在其中繪製一些需要的內容。下面會分別繼承View類控制元件和ViewGroup類控制元件來舉例說明。

  1、繼承View類系統控制元件

       如下示例為在TextView文字下方顯示紅色下劃線,其基本步驟如下:

    (1)繼承View控制元件,並重寫onDraw方法

 1 @SuppressLint("AppCompatCustomView")
 2 public class UnderlineTextView extends TextView{
 3     public UnderlineTextView(Context context, @Nullable AttributeSet attrs) {
 4         super(context, attrs);
 5     }
 6 
 7     @Override
 8     protected void onDraw(Canvas canvas) {
 9         super.onDraw(canvas);
10         Paint paint = new Paint();
11         paint.setColor(Color.RED);
12         paint.setStrokeWidth(5);
13         int width = getWidth();
14         int height = getBaseline();
15         canvas.drawLine(0,height,width,height,paint);
16     }
17 }

    (2)在佈局檔案中呼叫

       就像使用一個普通TextView一樣使用UnderlineTextView。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent">
 5     <com.example.demos.customviewdemo.UnderlineTextView
 6         android:layout_width="wrap_content"
 7         android:layout_height="wrap_content"
 8         android:textSize="50dp"
 9         android:layout_centerInParent="true"
10         android:text="Hello World!"/>
11 </RelativeLayout>

    (3)效果圖

    

 

  2、繼承ViewGroup類系統控制元件

       如下示例演示,在layout佈局上新增一個淺紅色的半透明蒙板,這種需求在工作中也是非常常見的。

    (1)繼承ViewGroup類系統控制元件

 1 public class ForegroundLinearLayout extends LinearLayout{
 2     public ForegroundLinearLayout(Context context, @Nullable AttributeSet attrs) {
 3         super(context, attrs);
 4     }
 5 
 6     @Override
 7     protected void dispatchDraw(Canvas canvas) {
 8         super.dispatchDraw(canvas);
 9         canvas.drawColor(Color.parseColor("#50FF0000"));
10     }
11 }

     (2)在佈局檔案中呼叫

       對ForegroundLinearLayout的使用,就和使用其父類LinearLayout一樣。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent">   
 5        <com.example.demos.customviewdemo.ForegroundLinearLayout
 6         android:layout_width="match_parent"
 7         android:layout_height="200dp"
 8         android:layout_centerInParent="true"
 9         android:gravity="center">
10 
11         <TextView
12             android:layout_width="wrap_content"
13             android:layout_height="wrap_content"
14             android:layout_centerInParent="true"
15             android:text="Hello World!"
16             android:textColor="@android:color/black"
17             android:textSize="50dp" />
18     </com.example.demos.customviewdemo.ForegroundLinearLayout>
19 </RelativeLayout>

     (3)效果圖

       在寬為全屏寬度,高為200dp的佈局範圍內,繪製完子其子控制元件TextView後,在上面覆蓋了一層淺紅色的半透明蒙板。

 

        從上面兩個例子可見,繼承系統原有的控制元件來實現自定義View,步驟非常簡單,比組合控制元件簡單多了。但是這一節需要對Canvas,paint等繪製方面的知識有一定的瞭解,且還需要對ViewGroup的中內容的繪製順序有一定的瞭解,才能在原生控制元件的基礎上做出想要的效果來。

 

三、自繪控制元件

       這三種方法中,自繪控制元件是最複雜的,因為所有的繪製邏輯和流程都需要自己完成。採用自繪控制元件這種方式時,如果自定義View為最終的葉子控制元件,那麼需要直接繼承View;而不過自定義View為容器類控制元件,則需要直接繼承ViewGroup。這裡依然針對直接繼承View和ViewGroup分別舉例進行說明。

  1、自繪葉子View控制元件

       這裡通過畫一個直方圖來展示自繪View控制元件的實現。

    (1)直接繼承View類

       自繪葉子View控制元件時,最主要工作就是繪製出豐富的內容,這一過程是在重寫的onDraw方法中實現的。由於是葉子view,它沒有子控制元件了,所以重寫onLayout沒有意義。onMeasure的方法可以根據自己的需要來決定是否需要重寫,很多情況下,不重寫該方法並不影響正常的繪製。

 1 public class HistogramView extends View{
 2 
 3     private Paint mPaint;
 4     private Path mPath;
 5 
 6     public HistogramView(Context context, @Nullable AttributeSet attrs) {
 7         super(context, attrs);
 8         mPaint = new Paint();
 9         mPath = new Path();
10     }
11 
12     @Override
13     protected void onDraw(Canvas canvas) {
14         super.onDraw(canvas);
15         //繪製座標軸
16         mPaint.reset();
17         mPath.reset();
18         mPaint.setColor(Color.BLACK);
19         mPaint.setStyle(Paint.Style.STROKE);
20         mPath.moveTo(100,100);
21         mPath.rLineTo(0,402);
22         mPath.rLineTo(800,0);
23         canvas.drawPath(mPath,mPaint);
24         //繪製文字
25         mPaint.reset();
26         mPaint.setTextSize(30);
27         mPaint.setStyle(Paint.Style.FILL);
28         canvas.drawText("Froyo",160,540,mPaint);
29         canvas.drawText("CB",280,540,mPaint);
30         canvas.drawText("ICS",380,540,mPaint);
31         canvas.drawText("J",480,540,mPaint);
32         canvas.drawText("KitKat",560,540,mPaint);
33         canvas.drawText("L",690,540,mPaint);
34         canvas.drawText("M",790,540,mPaint);
35         //繪製直方圖,柱形圖是用較粗的直線來實現的
36         mPaint.reset();
37         mPaint.setColor(Color.GREEN);
38         mPaint.setStrokeWidth(80);
39         float[] lines3={
40                 200,500,200,495,
41                 300,500,300,480,
42                 400,500,400,480,
43                 500,500,500,300,
44                 600,500,600,200,
45                 700,500,700,150,
46                 800,500,800,350,
47         };
48         canvas.drawLines(lines3,mPaint);
49     }
50 }

     (2)在Activity介面的佈局檔案中引入

       和其它自定義控制元件一樣,直接在佈局檔案中引入即可。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent">
 5 
 6     <com.example.demos.customviewdemo.HistogramView
 7         android:layout_width="match_parent"
 8         android:layout_height="wrap_content"/>
 9 
10 </RelativeLayout>

     (3)效果圖

 

  2、自繪ViewGroup控制元件

       這裡通過自定義一個父佈局控制元件,並新增一個子view來作為例子講解該方法的實現。

    (1)直接繼承ViewGroup類

       自繪ViewGroup控制元件,需要直接繼承ViewGroup,在該系列第一篇文章中將繪製流程的時候就講過,onLayout是ViewGroup中的抽象方法,其直接繼承者必須實現該方法。所以這裡,onLayout方法必須要實現的,如果這裡面的方法體為空,那該控制元件的子view就無法顯示了。要想準確測量,onMeasure方法也是要重寫的。下面例子中,只演示了第一個子view的測量和佈局,onLayout方法中的child.layout,就完成了對子view的佈局。

 1 public class CustomLayout extends ViewGroup {
 2     public CustomLayout(Context context, AttributeSet attrs) {
 3         super(context, attrs);
 4     }
 5 
 6     @Override
 7     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 8         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 9         if (getChildCount() > 0) {
10             //只測量第一個child
11             View child = getChildAt(0);
12             measureChild(child, widthMeasureSpec, heightMeasureSpec);
13         }
14     }
15 
16     @Override
17     protected void onLayout(boolean changed, int l, int t, int r, int b) {
18         if (getChildCount() > 0) {
19             //只佈局第一個child
20             View child = getChildAt(0);
21             child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
22         }
23     }
24 }

     (2)在佈局檔案中和普通父佈局一樣被引入

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent">
 5 
 6     <com.example.demos.customviewdemo.CustomLayout
 7         android:layout_width="match_parent"
 8         android:layout_centerInParent="true"
 9         android:layout_height="wrap_content">
10         <TextView
11             android:layout_width="wrap_content"
12             android:layout_height="wrap_content"
13             android:text="Hello World!"
14             android:textSize="50dp"/>
15 
16     </com.example.demos.customviewdemo.CustomLayout>
17 
18 </RelativeLayout>

    (3)效果圖

       上述程式碼中第8行沒有起效,從佈局上看TextView應該是處於螢幕的正中央,但是實際結果卻還是在左上方顯示。這是因為CustomLayout控制元件,並沒有實現“android:layout_centerInParent”這個屬性,所以是無效的。關於屬性的問題,正是下一節要介紹的內容。

 

四、在自定義View中使用自定義屬性

       我們在使用Android原生控制元件的時候,經常可以看到在佈局檔案中可以設定很多的屬性值,如

1 <TextView
2         android:id="@+id/title_tv"
3         android:layout_width="wrap_content"
4         android:layout_height="wrap_content"
5         android:layout_centerInParent="true"
6         android:text="Title"
7         android:textColor="@android:color/white"
8         android:textSize="20sp" />

這裡可以根據需要隨時設定TextView要顯示的文字,文字顏色,文字大小等各種屬性,給使用者帶來了極大的方便。我們在使用自定義View的時候,也非常希望能夠像TextView等系統原生控制元件一樣通過設定屬性值來個性化自定義View。本節我們們在上一節自定義直方圖的基礎上,來介紹自定義屬性的基本使用流程。

 

  1、在values中編寫需要的屬性

       在res/values/下新建資原始檔,這裡我們們命名為attrs.xml,在其中編寫所需要的屬性

1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3     <declare-styleable name="HistogramView">
4         <attr name="textColor" format="color"/>
5         <attr name="histogramColor" format="color"/>
6     </declare-styleable>
7 </resources>

這裡<declare-styleable>中的name是自行命名的,可以理解為這個自定義屬性集合的名稱。程式碼中包含了兩個自定義屬性,名稱分別為“textColor”和“histogramColor”,這裡用來設定直方圖中文字的顏色和直方圖的顏色。format表示的是屬性的格式,這裡均設定為“color”,表示對應的屬性是用來設定顏色值的。對於“format”,後面還會詳細講到。其它的就是固定的格式了,直接套用就行。

 

  2、在自定義View中引入屬性

 1 public class HistogramView extends View{
 2 
 3     private Paint mPaint;
 4     private Path mPath;
 5     private int mTextColor,mHistogramColor;
 6 
 7     public HistogramView(Context context, @Nullable AttributeSet attrs) {
 8         super(context, attrs);
 9         mPaint = new Paint();
10         mPath = new Path();
11         initAttrs(context,attrs);
12     }
13 
14 
15     private void initAttrs(Context context, AttributeSet attrs){
16         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HistogramView);
17         mTextColor = typedArray.getColor(R.styleable.HistogramView_textColor,Color.BLACK);
18         mHistogramColor = typedArray.getColor(R.styleable.HistogramView_histogramColor,Color.GREEN);
19         typedArray.recycle();
20     }
21 
22     @Override
23     protected void onDraw(Canvas canvas) {
24         super.onDraw(canvas);
25         //繪製座標軸
26         mPaint.reset();
27         mPath.reset();
28         mPaint.setColor(Color.BLACK);
29         mPaint.setStyle(Paint.Style.STROKE);
30         mPath.moveTo(100,100);
31         mPath.rLineTo(0,402);
32         mPath.rLineTo(800,0);
33         canvas.drawPath(mPath,mPaint);
34         //繪製文字
35         mPaint.reset();
36         mPaint.setTextSize(30);
37         mPaint.setColor(mTextColor);
38         mPaint.setStyle(Paint.Style.FILL);
39         canvas.drawText("Froyo",160,540,mPaint);
40         canvas.drawText("CB",280,540,mPaint);
41         canvas.drawText("ICS",380,540,mPaint);
42         canvas.drawText("J",480,540,mPaint);
43         canvas.drawText("KitKat",560,540,mPaint);
44         canvas.drawText("L",690,540,mPaint);
45         canvas.drawText("M",790,540,mPaint);
46         //繪製直方圖,柱形圖是用較粗的直線來實現的
47         mPaint.reset();
48         mPaint.setColor(mHistogramColor);
49         mPaint.setStrokeWidth(80);
50         float[] lines3={
51                 200,500,200,495,
52                 300,500,300,480,
53                 400,500,400,480,
54                 500,500,500,300,
55                 600,500,600,200,
56                 700,500,700,150,
57                 800,500,800,350,
58         };
59         canvas.drawLines(lines3,mPaint);
60     }
61 }

       將上述程式碼和前面第三節中自繪直方圖程式碼對比,紅色部分是修改或新增的程式碼。第15~20行程式碼就是初始化屬性的地方,這個過程需要在建構函式中完成。其中,第16行是和自定義屬性集建立聯絡,第17和18行是獲取開發者在佈局檔案中使用時設定的相應屬性值,如果沒有設定,則會使用預設設定的顏色,分別為Color.BLACK和Color.GREEN。這裡注意第19行,用完後一定要回收資源。這樣就初始化了文字顏色mTextColor值和mHistogramColor值,在後面onDraw中就使用該值來繪製對應的部分。

  

  3、在佈局檔案中設定屬性值

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent">
 6 
 7     <com.example.demos.customviewdemo.HistogramView
 8         android:layout_width="match_parent"
 9         android:layout_height="wrap_content"
10         app:textColor="@android:color/holo_red_light"
11         app:histogramColor="@android:color/holo_blue_bright"/>
12 
13 </RelativeLayout>

這段程式碼中,第3,10,11行和以往的佈局檔案有些不一樣,這是使用自定義屬性時的固定格式。第3行中,如果佈局檔案中沒有這一句,一定要加上,這句是宣告名稱空間,只有宣告瞭名稱空間才能使用自定義屬性。“app”是該名稱空間的名稱,這裡是自行命名的,不一定非要用“app”。第10行和11行,“app:attrName”表示用的是自定義的屬性,固定用法,前面mTextColor和mHistogramColor值就是從這裡獲取的。

       還記得上一節結尾處說“android:layout_centerInParent”沒有起效嗎?現在我們知道,這裡設定的屬性,是在自定義View程式碼中獲取該值,根據該值來確定顯示效果的。“android:layout_centerInParent”的值在View的原始碼中沒有被使用,所以設定後也就無效了。“android:layout_width”和“android:layout_height”屬性是必須要有的,所有的View的實現都要用到這兩個屬性來確定寬高。現在,我們們應該明白,設定控制元件屬性值是如何起作用的了吧。

 

  4、效果圖

      

五、自定義屬性格式彙總

       在上面一節中,僅僅只是對文字顏色和直方圖顏色的屬性值做了設定,是為了演示自定義屬性的使用步驟。在實際開發中,完全可以定義更多型別的屬性,如顯示文字的內容,文字的大小,直方圖的寬度等。format也不只限定於“color”,還有“String”,“Integer”等,多種多樣。本節就彙總一下平時比較常用的一些屬性format。

       本節主要參考瞭如下文章:【Android自定義View全解

   1、常用的11種format型別

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3     <declare-styleable name="SelfAttr">
 4         <!--1.reference:參考某一資源ID-->
 5         <attr name="background" format="reference" />
 6         <!--2. color:顏色值-->
 7         <attr name = "textColor" format = "color" />
 8         <!--3.boolean:布林值-->
 9         <attr name = "focusable" format = "boolean" />
10         <!--4.dimension:尺寸值-->
11         <attr name = "layout_width" format = "dimension" />
12         <!--5. float:浮點值-->
13         <attr name = "fromAlpha" format = "float" />
14         <!--6.integer:整型值-->
15         <attr name = "lines" format="integer" />
16         <!--7.string:字串-->
17         <attr name = "text" format = "string" />
18         <!--8.fraction:百分數-->
19         <attr name = "pivotX" format = "fraction" />
20         <!--9.enum:列舉值。屬性值只能選擇列舉值中的一個-->
21         <attr name="orientation">
22             <enum name="horizontal" value="0" />
23             <enum name="vertical" value="1" />
24         </attr>
25         <!--10.flag:位或運算。屬性值可以選擇其中多個值-->
26         <attr name="gravity">
27             <flag name="top" value="0x01" />
28             <flag name="bottom" value="0x02" />
29             <flag name="left" value="0x04" />
30             <flag name="right" value="0x08" />
31             <flag name="center_vertical" value="0x16" />
32             ...
33         </attr>
34         <!--11.混合型別:屬性定義時可以指定多種型別值-->
35         <attr name = "background_2" format = "reference|color" />
36     </declare-styleable>
37 </resources>

如上列出了平時工作中在常見的11種型別的格式,說是11種,但最後一種是前面10種的組合而已。看到上述的屬性名稱應該很熟悉吧,都是系統原生控制元件的屬性名稱。

  

  2、使用舉例

       如下對上述屬性的使用一一舉例演示,可以對照著來理解,都是平時常用的系統控制元件。

 1 <!--1.reference:參考某一資源ID-->
 2     <ImageView android:background = "@drawable/圖片ID"/>
 3     <!--2. color:顏色值-->
 4     <TextView android:textColor = "#00FF00"/>
 5     <!--3.boolean:布林值-->
 6     <Button android:focusable = "true"/>
 7     <!--4.dimension:尺寸值-->
 8     <Button android:layout_width = "42dp"/>
 9     <!--5. float:浮點值-->
10     <alpha android:fromAlpha = "1.0"/>
11     <!--6.integer:整型值-->
12     <TextView android:lines="1"/>
13     <!--7.string:字串-->
14     <TextView android:text = "我是文字"/>
15     <!--8.fraction:百分數-->
16     <rotate android:pivotX = "200%"/>
17     <!--9.enum:列舉值-->
18     <LinearLayout
19         android:orientation = "vertical">
20     </LinearLayout>
21     <!--10.flag:位或運算-->
22     <TextView android:gravity="bottom|left"/>
23     <!--11.混合型別:屬性定義時可以指定多種型別值-->
24     <ImageView android:background = "@drawable/圖片ID" />
25     <!--或者-->
26     <ImageView android:background = "#00FF00" />

 

結語

       關於自定義View的3中實現方式以及自定義屬性的使用,這裡就講完了。讀完後,是不是發現基本的實現流程其實非常簡單呢?當然,本文為了說明實現流程,所以舉的例子都比較簡單,但不是說繪製內容也一樣簡單。就好像辦理入學手續很簡單,但讀書這件事卻不那麼容易一樣。要完成一些酷炫的自定義View,還需要好好地掌握Canvas,Paint,Path等工具的使用,以及View的繪製流程原理。當然,本文肯定有很多描述不妥或不準確的地方,歡迎來拍磚。

相關文章