android:建立自定義控制元件

yufan發表於2016-01-08

在前面兩節我們已經學習了 Android 中的一些常見控制元件以及基本佈局的用法,不過當時 我們並沒有關注這些控制元件和佈局的繼承結構,現在是時候應該看一下了,如圖 3.26 所示。

 

 

 

 

 

圖   3.26

 

可以看到,我們所用的所有控制元件都是直接或間接繼承自 View 的,所用的所有佈局都是 直接或間接繼承自 ViewGroup 的。View 是 Android 中一種最基本的 UI 元件,它可以在螢幕 上繪製一塊矩形區域,並能響應這塊區域的各種事件,因此,我們使用的各種控制元件其實就是 在 View 的基礎之上又新增了各自特有的功能。而 ViewGroup 則是一種特殊的 View,它可以 包含很多的子 View 和子 ViewGroup,是一個用於放置控制元件和佈局的容器。

這個時候我們就可以思考一下,如果系統自帶的控制元件並不能滿足我們的需求時,可不可 以利用上面的繼承結構來建立自定義控制元件呢?答案是肯定的,下面我們就來學習一下建立自 定義控制元件的兩種簡單方法。先將準備工作做好,建立一個 UICustomViews 專案。

 

3.4.1    引入佈局

 

如果你用過 iPhone 應該會知道,幾乎每一個 iPhone 應用的介面頂部都會有一個標題欄, 標題欄上會有一到兩個按鈕可用於返回或其他操作(iPhone 沒有實體返回鍵)。現在很多的 Android 程式也都喜歡模仿 iPhone 的風格,在介面的頂部放置一個標題欄。雖然 Android 系 統已經給每個活動提供了標題欄功能,但這裡我們仍然決定不使用它,而是建立一個自定義 的標題欄。

經過前面兩節的學習,我想建立一個標題欄佈局對你來說已經不是什麼困難的事情了, 只需要加入兩個 Button 和一個 TextView,然後在佈局中擺放好就可以了。可是這樣做卻存 在著一個問題,一般我們的程式中可能有很多個活動都需要這樣的標題欄,如果在每個活的佈局中都編寫一遍同樣的標題欄程式碼,明顯就會導致程式碼的大量重複。這個時候我們就可

以使用引入佈局的方式來解決這個問題,新建一個佈局 title.xml,程式碼如下所示:

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/title_bg" >

 

<Button android:id="@+id/title_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="5dip" android:background="@drawable/back_bg" android:text="Back" android:textColor="#fff" />

 

<TextView android:id="@+id/title_text" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="1" android:gravity="center" android:text="Title Text" android:textColor="#fff" android:textSize="24sp" />

 

<Button android:id="@+id/title_edit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="5dip" android:background="@drawable/edit_bg" android:text="Edit" android:textColor="#fff" />

 

</LinearLayout>

 

 

 

可以看到,我們在 LinearLayout 中分別加入了兩個 Button 和一個 TextView,左邊的 Button

可用於返回,右邊的 Button 可用於編輯,中間的 TextView 則可以顯示一段標題文字。上面 的程式碼中大多數的屬性你都已經是見過的,下面我來說明一下幾個之前沒有講過的屬性。 android:background 用於為佈局或控制元件指定一個背景,可以使用顏色或圖片來進行填充,這 裡我提前準備好了三張圖片,title_bg.png、back_bg.png 和 edit_bg.png,分別用於作為標題欄、 返回按鈕和編輯按鈕的背景。另外在兩個 Button 中我們都使用了 android:layout_margin 這個屬 性,它可以指定控制元件在上下左右方向上偏移的距離,當然也可以使用 android:layout_marginLeft 或 android:layout_marginTop 等屬性來單獨指定控制元件在某個方向上偏移的距離。

現在標題欄佈局已經編寫完成了,剩下的就是如何在程式中使用這個標題欄了,修改

activity_main.xml 中的程式碼,如下所示:

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >

 

<include layout="@layout/title" />

 

 

</LinearLayout>

沒錯!我們只需要通過一行 include 語句將標題欄佈局引入進來就可以了。 最後別忘了在 MainActivity 中將系統自帶的標題欄隱藏掉,程式碼如下所示:

 

public class MainActivity extends Activity {

 

 

@Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);

setContentView(R.layout.activity_main);

}

 

 

}

現在執行一下程式,效果如圖 3.27 所示。

 

 

圖   3.27

 使用這種方式,不管有多少佈局需要新增標題欄,只需一行 include 語句就可以了。

 

3.4.2    建立自定義控制元件

 

引入佈局的技巧確實解決了重複編寫佈局程式碼的問題,但是如果佈局中有一些控制元件要求 能夠響應事件,我們還是需要在每個活動中為這些控制元件單獨編寫一次事件註冊的程式碼。比如 說標題欄中的返回按鈕,其實不管是在哪一個活動中,這個按鈕的功能都是相同的,即銷燬 掉當前活動。而如果在每一個活動中都需要重新註冊一遍返回按鈕的點選事件,無疑又是增 加了很多重複程式碼,這種情況最好是使用自定義控制元件的方式來解決。

新建 TitleLayout 繼承自 LinearLayout,讓它成為我們自定義的標題欄控制元件,程式碼如下 所示:

 

public class TitleLayout extends LinearLayout {

 

 

public TitleLayout(Context context, AttributeSet attrs) {

super(context, attrs);

LayoutInflater.from(context).inflate(R.layout.title, this);

}

 

}

 

 

 

首先我們重寫了 LinearLayout 中的帶有兩個引數的建構函式,在佈局中引入 TitleLayout

控制元件就會呼叫這個建構函式。然後在建構函式中需要對標題欄佈局進行動態載入,這就要借 助 LayoutInflater 來實現了。通過 LayoutInflater 的 from()方法可以構建出一個 LayoutInflater 物件,然後呼叫 inflate()方法就可以動態載入一個佈局檔案,inflate()方法接收兩個引數,第 一個引數是要載入的佈局檔案的 id,這裡我們傳入 R.layout.title,第二個引數是給載入好的 佈局再新增一個父佈局,這裡我們想要指定為 TitleLayout,於是直接傳入 this。

現在自定義控制元件已經建立好了,然後我們需要在佈局檔案中新增這個自定義控制元件,修改

activity_main.xml 中的程式碼,如下所示:

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >

 

<com.example.uicustomviews.TitleLayout android:layout_width="match_parent" android:layout_height="wrap_content"

></com.example.uicustomviews.TitleLayout>

 

 

</LinearLayout>

新增自定義控制元件和新增普通控制元件的方式基本是一樣的,只不過在新增自定義控制元件的時候 我們需要指明控制元件的完整類名,包名在這裡是不可以省略的。

重新執行程式,你會發現此時效果和使用引入佈局方式的效果是一樣的。 然後我們來嘗試為標題欄中的按鈕註冊點選事件,修改 TitleLayout 中的程式碼,如下所示:

 

public class TitleLayout extends LinearLayout {

 

 

public TitleLayout(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.title, this); Button titleBack = (Button) findViewById(R.id.title_back); Button titleEdit = (Button) findViewById(R.id.title_edit); titleBack.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) { ((Activity) getContext()).finish();

}

});

titleEdit.setOnClickListener(new OnClickListener() {

@Override

 

 

 

public void onClick(View v) {

Toast.makeText(getContext(), "You clicked Edit button",

Toast.LENGTH_SHORT).show();

}

});

}

 

}

首先還是通過 findViewById()方法得到按鈕的例項,然後分別呼叫 setOnClickListener() 方法給兩個按鈕註冊了點選事件,當點選返回按鈕時銷燬掉當前的活動,當點選編輯按鈕時 彈出一段文字。重新執行程式,點選一下編輯按鈕,效果如圖 3.28 所示。

 

 

 

圖   3.28

 

這樣的話,每當我們在一個佈局中引入 TitleLayout,返回按鈕和編輯按鈕的點選事件就 已經自動實現好了,也是省去了很多編寫重複程式碼的工作。

相關文章