Android自定義元件


Android提供了一個預建的部件,如Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner, AutoCompleteTextView等可以直接使用在Android應用程式開發中,但有可能還有一種情況,當不滿意現有可用的視窗小部件的功能。 Android 提供建立自定義元件功能,客製化以滿足需求。 

如果只需要進行小的調現有的小工具或佈局,可以簡單的子類的小工具或佈局和覆蓋它的方法,這將精確地控制螢幕元素的外觀和功能。

本教學介紹了如何建立自定義檢視,並利用它們在應用程式,如下步驟。

建立一個簡單的自定義元件

最簡單的建立自定義的元件方法是擴充套件現有的widget類或子類,如果想擴充套件現有部件,如Button, TextView, EditText, ListView, CheckBox等,否則可以從android.view.View類開始擴充套件。 

在其最簡單的形式,編寫建構函式對應的所有基礎類別的建構函式。例如,如果要擴充套件 TextView 建立DateView 以下三個構造,建立DateView類:

public class DateView extends TextView {
   public DateView(Context context) {
      super(context);
      //--- Additional custom code --
   }

   public DateView(Context context, AttributeSet attrs) {
      super(context, attrs);
      //--- Additional custom code --
   }

   public DateView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      //--- Additional custom code --
   }
}

TextView 的子類DateView已經建立,所以可以獲得有關TextView 的所有屬性、方法和事件,能夠使用不需要任何進一步的實現。這裡將實現額外的自定義功能在自己編寫的程式碼,如下面的例子解釋。

如果要求執行自定義繪圖/客製化部件的尺寸,那麼需要重寫 onMeasure(int widthMeasureSpec, int heightMeasureSpec) 和 onDraw(Canvas canvas) 方法。如果不打算調整或變更內建元件的形狀,那麼並不需要使用這些方法在自定義元件。 

布局管理報告部件的寬度和高度需要協調 onMeasure() 方法,需要呼叫setMeasuredDimension(int width, int height),這種方法來報告尺寸大小。

可以執行自定義繪圖裡Canvas 的onDraw(Canvas canvas) 方法,其中android.graphis.Canvas其對應 Swing 是非常相似的,drawRect(), drawLine(), drawString(), drawBitmap() 等,可以用它來繪製元件。 

完成了一個自定義元件的實現之後,通過擴大現有的部件,將能夠範例化這些自定義元件在應用程式開發兩種方式:

Activity類範例內使用程式碼

這是非常相似的方式範例化自定義元件範例的方式,在活動類的內建部件。例如,可以使用下面的程式碼範例上面定義的自定義元件:

@Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     
     DateView dateView = new DateView(this);
     setContentView(dateView);
 }

檢視這個例子來了解如何使用程式碼裡面活動範例化一個基本的Android自定義元件

使用布局XML檔案範例

使用傳統布局XML檔案範例的內建部件,相同的概念適用於自定義部件,因此將能夠範例化自定義元件布局XML檔案,解釋如下。在com.yiibai.dateviewdemo包,已經把所有的程式碼相關DateView 和 DateView 類,已經把自定義元件的完整的邏輯的Java類名。 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    
    <com.yiibai.dateviewdemo.DateView
     android:layout_width="match_parent"
     android:layout_height="wrap_content" 
     android:textColor="#fff"
     android:textSize="40sp"
     android:background="#000"
     />
</RelativeLayout>

要注意,在這裡我們使用的所有 TextView 屬性以及自定義元件沒有任何變化。類似的方式能夠使用所有的事件、方法,以及DateView元件。

通過這個例子,了解如何使用布局XML檔案範例化一個基本的Android自定義元件。 

使用自定義屬性的自定義元件

我們已經看到可以如何擴充套件功能的內建部件,但上面給出兩個例子中看到,擴充套件元件,可以利用它的父類別的所有預設屬性。但考慮到一種情況,當想從頭開始建立自己的屬性。下面是一個簡單的程式建立和使用Android的自定義元件的新屬性。這裡介紹三個屬性,並使用它們,如下所示:

<com.yiibai.dateviewdemo.DateView
   android:layout_width="match_parent"
   android:layout_height="wrap_content" 
   android:textColor="#fff"
   android:textSize="40sp"
   custom:delimiter="-"
   custom:fancyText="true"
/>

第1步

第一步,使用自定義的屬性在 res/values/ 目錄下建立新XML檔案中定義attrs.xml。看看一個例子檔案 attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <declare-styleable name="DateView">
   <attr name="delimiter" format="string"/>
   <attr name="fancyText" format="boolean"/>
   </declare-styleable>
</resources>

這裡 name=value 就是要使用的布局XML檔案中並作為屬性,format=type 屬性的型別。 

第2步

第二個步驟將是從布局XML檔案中讀取這些屬性,並將其設定為元件。這個邏輯將獲得通過屬性集的建構函式,因為這是包含XML屬性。要讀取XML中的值,首先需要從AttributeSet建立一個TypedArray,然後用它來讀取和設定值,如下面的範例程式碼所示:

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DateView);

final int N = a.getIndexCount();
for (int i = 0; i < N; ++i)
{
   int attr = a.getIndex(i);
   switch (attr)
   {
      case R.styleable.DateView_delimiter:
         String delimiter = a.getString(attr);
         //...do something with delimiter...
         break;
      case R.styleable.DateView_fancyText:
         boolean fancyText = a.getBoolean(attr, false);
         //...do something with fancyText...
         break;
   }
}
a.recycle();

第3步

最後,可以使用布局XML檔案中定義的屬性如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res/com.yiibai.dateviewdemo"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    
    <com.yiibai.dateviewdemo.DateView
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
    android:textColor="#fff"
    android:textSize="40sp"
    custom:delimiter="-"
    custom:fancyText="true"
    />

</RelativeLayout>

重要的部分是xmlns:custom="http://schemas.android.com/apk/res/com.yiibai.dateviewdemo"。需要注意的是http://schemas.android.com/apk/res/將保持原樣,但最後一部分需要設定包名,也可以使用任何xmlns:在這個例子中,使用的是custom,但可以使用任何喜歡的名字。 

看看這個例子,以了解如何建立自定義屬性Android自定義元件 的簡單步驟。