Android 自定義組合控件小結
引言
接觸Android UI開發的這段時間以來,對自定義組合控件有了一定的了解,為此小結一下,本文小結內容主要討論的是如何使用Android SDK提供的布局和控件組成一個功能完整組合控件並將其封裝為面向對象的類,而並非討論如何繼承自SDK提供的控件類(比如TextView),對其進行自定義擴展的問題。
進入正題前,我們先來看一組功能需求
假設在手機需求上,那么如上三個界面我們可以使用三個Activity,每個Activity一個布局文件,實現起來比較獨立,但是假設在Android pad上要求如上三個界面在一個對話框上實現,而且切換過程中要有漸變動畫,那么該如何實現呢?我的方案是通過使用一個浮動的Activity外加ViewFlipper來實現。雖然我們可以在這個浮動的Activity類內能夠獲取到每個界面的控件並添加相應的操作,但是如果全部放在一個Activity類內,會使這個類內代碼量很大,代碼走讀起來也不容易,而且也少了些OO的概念,為此可以考慮將每一個界面用一個自定義的組合控件類來實現。同理,假設上面的第一個界面里面關於微博綁定的列表界面,我們可以考慮使用ListView控件外加一個自定義擴展的Adapter,其中的每一項,其實也是一個組合控件,需要我們在自定義的Adapter中創建出來。為了嘗試自定義組合控件的使用,對於微博列表我也沒有使用ListView來實現,而是采用了基礎的addView方式。
自定義組合控件的步驟
下面具體分步驟來說明自定義組合控件的實現和封裝:
新建並編寫組合控件的布局
這一步和其它新建和編寫布局資源的方法一樣,可以使用拖動控件,也可以使用代碼輸入,亦可以通過其它第三方開發工具編寫,總之,結果是要得到一個滿足需求的布局,為了后面行文的方便,我就取上面第二個界面布局account_info_preview.xml中的部分代碼來說明下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/login_view_back">
<RelativeLayout
android:layout_height="@dimen/content_top_land_height"
android:layout_width="fill_parent"
android:padding="@dimen/login_title_padding"
android:background="@drawable/login_title_back">
……
</RelativeLayout>
</LinearLayout>
這一步的實現要求就是通過所見即所得的原理,使得編輯完后布局在Graphical Layout界面看到的效果就是你想要實現的界面的靜態效果就可以了。
新建一個組合控件的自定義類
上面的account_info_preview.xml布局文件創建好之后,就可以為這個組合控件的布局創建一個你需要的自定義類了,假設這個類被命名為AccountInfoPreView類,那么通過eclipse先創建該類,該類的父類就是組合控件根元素對應的類,這里是LinearLayout,所以這個AccountInfoPreView就應該派生自LinearLayout。
LinearLayout有兩個構造函數,在AccountInfoPreView類中我們必須重寫父類的構造函數,由於在使用中,我們不采用直接new AccountInfoPreView(Context context)方式創建該組合控件,所以我們只需要重載一個public AccountInfoPreView(Context context, AttributeSet attrs)構造函數就可以了,這個就看你自定義的組合控件的需求了。
另外為了在自定義類中進行對控件對象的實例化,我們需要重寫protected void onFinishInflate()函數,以實現資源id和控件對象的一一對應。下面以貼出代碼為例
package com.netease.pris.hd.view;
……
public class AccountInfoPreView extends LinearLayout
{
TextView mViewTitle;
ImageView mHeader;
public AccountInfoPreView(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
}
@Override
protected void onFinishInflate()
{
mViewTitle =(TextView)findViewById(R.id.aip_title_text);
mHeader = (ImageView)findViewById(R.id.aip_header_imgae);
}
……
}
如上就為自定義控件類搭好了框架,具體需要進行何種操作,就往里面寫操作就可以了,比如添加控件點擊事件等等。
修改組合控件布局根元素為自定義類
自定義組合控件的類有了,自定義組合控件的布局也有了,雖然類內也用findViewById對組合控件內部的控件進行了一一實例化,但是整個組合控件類和布局還沒有建立起關聯關系,這一步就通過用自定義類的包名+類名來修改自定義組合控件布局的根元素完成。我們看到我們上面的自定義類的包名為com.netease.pris.hd.view,類名為AccountInfoPreView,所以我們重新將上面的account_info_preview.xml內的LinearLayout根元素替換為AccountInfoPreView就可以了。具體如下示例
<?xml version="1.0" encoding="utf-8"?>
<com.netease.pris.hd.view.AccountInfoPreView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/login_view_back">
<RelativeLayout
android:layout_height="@dimen/content_top_land_height"
android:layout_width="fill_parent"
android:padding="@dimen/login_title_padding"
android:background="@drawable/login_title_back">
……
</RelativeLayout>
</com.netease.pris.hd.view.AccountInfoPreView>
使用自定義組合控件
好了,上面已經將創建自定義組合控件的步驟介紹完了,也創建了一個AccountInfoPreView的自定義組合控件,接下來我們就要講解使用這個自定義組合控件了。
根據資源加載的靜態和動態兩種方式,使用自定義組合控件,也同樣有靜態和動態兩種方式,其實也很簡單的兩種方式,跟Android的Inflate有關系。
靜態加載
這里所說的靜態加載,就是自定義組合控件被使用它的布局在XML資源中包含了,而這個布局又通過Activity的setConentView()函數設置進去了,那么我們就可以通過findViewById的方式來實例化自定義組合控件的對象。
比如上面創建的AccountInfoPreView自定義組合控件被Activity的setConentView函數設置的布局account_view_flipper.xml所包含,其內容如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="@dimen/login_dialog_width"
android:layout_height="@dimen/login_dialog_height">
<ViewFlipper
android:id="@+id/account_view_flippe"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include
android:id="@+id/account_info_preview"
layout="@layout/account_info_preview" />
</ViewFlipper>
</LinearLayout>
我們就可以通過findViewById的方法來實例化自定義組合控件的對象,代碼如下
AccountInfoPreView mAIPView = (AccountInfoPreView)findViewById(R.id.account_info_preview);
成功實例化了對象,至於后面對該對象的具體使用就不羅列了。
動態加載
動態加載,就是自定義組合控件在資源布局中沒有包含,我們通過代碼動態創建到所需要的ViewGroup中去。由於自定義組合控件,不像TextView等基礎控件或自定義的不關聯資源的View,所以不能通過new方式直接進行創建,需要通過Inflate方法實例化自定義組合控件對象,並將其添加到ViewGroup中去,我們可以改寫下上面的布局account_view_flipper.xml文件為
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="@dimen/login_dialog_width"
android:layout_height="@dimen/login_dialog_height">
<ViewFlipper
android:id="@+id/account_view_flippe"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ViewFlipper>
</LinearLayout>
則在Activity的onCreate函數中我們可以如下編寫代碼
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.account_view_flipper);
ViewFlipper mViewFlipper =(ViewFlipper)findViewById(R.id.account_view_flippe);
AccountInfoPreView mAIPView = (AccountInfoPreView)getLayoutInflater().inflate(R.id.account_info_preview, null);
mViewFlipper.addView(mAIPView);
}
通過上面的代碼,我們同樣實例化了一個AccountInfoPreView控件對象,並將其動態加載到了界面上進行顯示。具體操作同樣根據具體需求來實現,這里就不做展開了。
關於Android自定義組合控件就小結到這里,假如文中有不正確的地方還望幫忙斧正,謝謝。