2011-04-25

Android UI

Android UI 元件的 parent class 主要為 View 與 ViewGroup 兩個 abstract class,其中 ViewGroup 也是繼承自 View class。

ViewGroup 主要作為 AdapterView 與 Layout 的 parent class,就是一種 View 的 container,剩下的 Android UI 元件都是繼承自 View class。

開發 Android UI 可以單獨用 coding 的方式,也可以用 XML 設定的方式,或者兩種方法混著用,用 XML 定義 UI,然後用 coding 加上互動。


使用 coding 方式建立 UI:
public class LayoutMgr extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout main = new LinearLayout(this);
        main.setOrientation(LinearLayout.VERTICAL);
        Button newBtn = new Button(this);
        newBtn.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        newBtn.setText("新遊戲");
        main.addView(newBtn);
        Button confBtn = new Button(this);
        confBtn.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        confBtn.setText("設定");
        main.addView(confBtn);
        this.setContentView(main);
    }
}

使用 XML 設定方式建立 UI 的部份,請參考 Android Layout Managers - LinearLayout,要補充的是,讓 Android 知道是使用 XML 設定。
public class LayoutMgr extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.main);
    }
}
特別的地方是 this.setContentView(R.layout.main) 裡的 R.layout.main,這是 Android 自動產生的 class,Android 會將 res 目錄下的 XML 設定檔產生 class 檔到 gen 目錄下,供 coding reference 使用。

最後一種建立 UI 的方式,也是最常見的方式,就是使用 XML 建立頁面,然後使用 coding 加上互動的行為,XML 部份請參考 Android Layout Managers - LinearLayout
public class LayoutMgr extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        this.findViewById(R.id.startBtn).setOnClickListener(
                new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        // TODO - start a new game
                    }
                });
        this.findViewById(R.id.endBtn).setOnClickListener(
                new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        // TODO - exit the game
                    }
                });
    }
}
這邊要強調的是使用 this.findViewById(...) 來取得 XML 裡定義的元件,另外也可以在 coding 裡改變 UI 的外觀或設定。

TextView

像是 HTML 裡的 lable,除了純粹文字輸出,Android 另外強化了自動連結的功能。
<TextView  
        android:id="@+id/tv"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:autoLink="all"
    android:text="..."
    />
加上 autoLink 屬性之後,Android 會自動解析內容,適當地加上連結,autoLink 支援的連結種類有 web(網址)、phone(電話號碼)、email、map(地址)以及 all,預設為 none。

也可以使用 coding 的方式設定,參考 Linkify。

EditText

像是 HTML 裡的 text input + textarea,預設為 text input,在編輯狀態按下 enter 就會多一行變成 textarea,可以加上 singelLine 屬性強制為 text input。

有很多像是自動檢查拼字的 autoText、自動轉大寫的capitalize、只接受數字的 digits、或密碼專用的 password 等屬性可以使用,請參考 TextView Attributes(因為 EditText 繼承自 TextView)。

EditText 允許一點點的 style,只接受 <i/>、<b/>、<u/>,要從 XML 輸入 style,只能用 reference 的方式,如果直接在 XML 輸入 style,可是會看到驚奇的。
<EditText
    android:id="@+id/et"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="<i>aaa<i/><b>bbb<b/><u>ccc<u/>"
    />

只能用 reference 的方式輸入 style。
<EditText
    android:id="@+id/et"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/style"
    />
res/values/strings.xml
<resources>
  <string name="style"><i>iii</i> <b>bbb</b> <u>uuu</u></string>
</resources>
正確的 style:

AutoCompleteTextView

從自訂的字串集中產生自動完成功能,XML 設定如下:
<AutoCompleteTextView
 android:id="@+id/actv"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"/>
特別的地方在 coding 部份:
public class UI extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String[] phoneList = new String[] {
                "0910123456", "0920123456", "0921123456", "0935123456",
                "0938123456"
        };
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_dropdown_item_1line, phoneList);
        ((AutoCompleteTextView) this.findViewById(R.id.actv)).setAdapter(adapter);
    }
}
先建立字串集,再建立 adapter,最後將 adpater 傳給 AutoCompleteTextView 元件。


這邊有一個特別的地方,就是 adapter 的 UI 來源,上面用的是 Android 內建的範本(android.R.layout.simple_dropdown_item_1line),還有很多範本可用,也可以自訂專屬的範本,只要在 res/layout 目錄下建立 XML 設定檔,例如 list_item.xml。
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="6dp"
    android:textSize="12sp"
    android:textColor="#000">
</TextView>
這樣就可以使用 R.layout.list_item 得到一個緊實的下拉清單。


最後一個重點是,自動完成的功能得輸入兩個字元才會驅動,只輸入一個字元是沒有反應的。

MultiAutoCompleteTextView

怪怪版的 AutoCompleteTextView,可以在一個 EditText 使用多次自動完成,只要輸入指定的字元後,就可以重新使用自動完成。


從前一個 AutoCompleteTextView 範例做修改,只要將 AutoCompleteTextView 改成 MultiAutoCompleteTextView,然後在 coding 裡,呼叫 mactv.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer()) 就可以了。


Button

在 XML 建立一個 Button,然後在 coding 裡加上互動行為。
public class Dialog extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ((Button) this.findViewById(R.id.dialogA)).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // do something
            }
        });
    }
}
但是這樣會有一個小小地效能問題,就是使用匿名 inner class 會消耗一些記憶體,當 Button 用的愈多,inner class 愈多,效能就愈慢。

可以在使用最少 class 的前提下,將主 activity 實做 OnClickListener,再用 switch 判斷不同的 Button,就可以避免因為 inner class 造成記憶體過載的情況。
public class Dialog extends Activity implements OnClickListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ((Button) this.findViewById(R.id.dialogA)).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.dialogA:
            this.startActivity(new Intent(this, DialogA.class));
            break;
        }
    }
}
ImageButton

影像按鈕。
<ImageButton
    android:id="@+id/imgBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/appengine_lowres"/>
<ImageButton
    android:id="@+id/imgBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ae_gwt_java"/>

特別的地方在於讀取影像的方式,只要將影像檔放置於 drawable 目錄下即可,支援 png、jpg與 gif 三種格式,不用另外在 XML 中定義,即可以在 XML 或 coding 中用檔名(不包括副檔名)reference。

ToggleButton

雙態按鈕。
<ToggleButton
    android:id="@+id/tglBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textOn="錄音中"
    android:textOff="開始錄音"/>


CheckBox

同 HTML 的 checkbox。
<CheckBox
    android:id="@+id/oneBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="One"/>
<CheckBox
    android:id="@+id/twoBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Two"/>
<CheckBox
    android:id="@+id/threeBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Three"/>

常用的 method 有 isChecked()、setChecked(...)、toggle() 與 setOnCheckedChangeListener(...)。

RadioGroup & RadioButton

同 HMLT 的 radio。
<RadioGroup
    android:id="@+id/rdoBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <RadioButton
        android:id="@+id/oneBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="One"/>
    <RadioButton
        android:id="@+id/twoBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Two"/>
    <RadioButton
        android:id="@+id/threeBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Three"/>
</RadioGroup> 

RadioGroup 裡可以放置 RadioButton 以外的 View 元件,而 RadioGroup 的單選限制僅作用於 RadioGroup 裡的 RadioButton 子元件,所以 RadioGroup 裡的非 RadioButton 子元件或者 RadioGroup 外的 RadioButton 元件不會影響 RadioGroup 的單選限制。

一旦任一個 RadioButton 元件被點選之後,就無法從頁面上回復到所有未點選的初始狀態,只能透過呼叫 clearCheck() 來回復到所有未點選的初始狀態。

DatePicker & TimePicker
<DatePicker
    android:id="@+id/datePicker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
<TimePicker
    android:id="@+id/timePicker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

沒有留言:

張貼留言