android:創建自定義控件


在前面兩節我們已經學習了 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,返回按鈕和編輯按鈕的點擊事件就 已經自動實現好了,也是省去了很多編寫重復代碼的工作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM