《Android》『Spinner』- 下拉式選單的三種宣告方式
《Android Developers 參考文獻》
《簡單介紹》
Spinner 元件是一組預先設定好資料的選項,提供標準的下拉式選單介面,使用這個元件最大的好處是可以縮減在介面中被眾多選項所佔據的空間,藉以設計出更為簡潔的介面。
《宣告 & 使用方式》
在 Android 中,所提供的介面元件都給予了使用者非常大的自由度,也就是說,我們可以很快地利用基本的 Spinner 宣告來得到擁有預設基本樣式的 Spinner 元件,若對於 Spinner 樣式有特殊的需求,亦可以依照自己的需求對於 Spinner 樣式做出修改,也就是自訂 Spinner 樣式,當在設計一些具有美感要求的介面時,通常都會透過自訂 Spinner 樣式的方式,打造獨一無二具有設計感的 Spinner 介面。
以下透過程式碼片段的方式,分別說明基本樣式宣告以及自訂樣式宣告的使用方法。
三種宣告方式 :
1. 基本宣告
直接透過 layout.xml 設定 Spinner 的相關屬性與所參照的選項資料,快速產生一個基本預設樣式的 Spinner 元件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//MainActivity.java //----------------- public class MainActivity extends Activity { private Spinner mSpn; //宣告 mSpn 為 Spinner 物件 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSpn = (Spinner) findViewById(R.id.spn); mSpn.setOnItemSelectedListener(spnOnItemSelected); } private AdapterView.OnItemSelectedListener spnOnItemSelected = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View v, int position, long id) { // TODO Auto-generated method stub } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }; } |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Spinner android:id="@+id/spn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:entries="@array/spn_list" //設定 Spinner 選項資料 android:spinnerMode="dialog" //設定 Spinner 下拉模式 android:prompt="@string/select_dialog_title" /> //設定 Spinner 對話視窗標題 </LinearLayout> |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="select_region_dialog_title">Spinner 對話視窗標題</string> <string-array name="spn_list"> <item>選項1</item> <item>選項2</item> <item>選項3</item> <item>選項4</item> <item>選項5</item> </string-array> </resources> |
string.xml
透過layout.xml 中的屬性設定,將選項資料來源指向 string.xml 中寫好資源參數,最後在 MainActivity 中宣告使用,這是最方便快速的方式,但也是最沒有靈活性的方式。
2. 透過內建的 Adapter 宣告
透過內建的 Adapter 類別來指定所需的資料與樣式,並指定給 Spinner 元件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class MainActivity extends Activity { private Spinner mSpn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSpn = (Spinner) findViewById(R.id.spn); ArrayAdapter<CharSequence> arrAdapSpn = ArrayAdapter.createFromResource(MainActivity.this, //對應的Context R.array.spn_list, //選項資料內容 R.layout.spinner_item); //自訂getView()介面格式(Spinner介面未展開時的View) arrAdapSpn.setDropDownViewResource(R.layout.spinner_dropdown_item); //自訂getDropDownView()介面格式(Spinner介面展開時,View所使用的每個item格式) mSpn.setAdapter(arrAdapSpn); //將宣告好的 Adapter 設定給 Spinner mSpn.setOnItemSelectedListener(spnOnItemSelected); } private AdapterView.OnItemSelectedListener spnRegionOnItemSelected = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View v, int position, long id) { // TODO Auto-generated method stub } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }; } |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Spinner android:id="@+id/spn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:spinnerMode="dropdown" /> </LinearLayout> |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="select_region_dialog_title">Spinner 對話視窗標題</string> <string-array name="spn_list"> <item>選項1</item> <item>選項2</item> <item>選項3</item> <item>選項4</item> <item>選項5</item> </string-array> </resources> |
string.xml
與上一個方法一樣,Spinner 需要指定一個已知的選項資料,同樣是透過讀取 string.xml 裡面的資源檔獲得,但這邊不是在設定 layout.xml 屬性時指定,而是透過宣告一個內建的 ArrayAdapter<CharSequence> 來儲存所要設定的選項資料內容、getView() 介面格式以及getDropDownView() 介面格式。
(※ Spinner 元件包含了三個 View 元件,分別為 Spinner 元件本身的View (setBackground)、getView() 介面以及 getDropDownView() 介面,其中getView() 介面為選單尚未展開時的 View,而 getDropDownView() 介面則為選單展開後,每一個選項所使用的 View。)
1 2 3 4 5 6 7 |
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/txt_SpnDropDown" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/darker_gray" android:textSize="12dp" /> |
spinner_dropdown_item.xml
1 2 3 4 5 6 7 |
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/txtSpn_getView" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/background_light" android:textSize="12dp" /> |
spinner_item.xml
在宣告建構 ArrayAdapter<CharSequence> 的時候,可以分別將 getView() 以及 getDropDownView() 的介面設定為自己定義的 layout 格式,由此可以完成初步的自定義 Spinner 樣式。
3. 透過自訂的 Adapter 宣告
透過自訂的 Adapter 類別來指定所需的資料與樣式,並指定給 Spinner 元件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public class MainActivity extends Activity { private Spinner mSpn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); CharSequence[] spnList = getResources().getStringArray(R.array.spn_list); mSpn = (Spinner) findViewById(R.id.spn); ArrayAdapterSpinner arrAdapSpn = new ArrayAdapterSpinner(MainActivity.this, //對應的 Context R.layout.spinner_item, //自訂getView()介面格式(Spinner介面未展開時的View) spnList, // 選項資料內容 mSpn); arrAdapSpn.setDropDownViewResource(R.layout.spinner_dropdown_item); mSpn.setAdapter(arrAdapSpn); mSpn.setOnItemSelectedListener(spnRegionOnItemSelected); } private AdapterView.OnItemSelectedListener spnRegionOnItemSelected = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View v, int position, long id) { // TODO Auto-generated method stub } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }; } |
MainActivity.java
使用內建的 Adapter 雖然可以在宣告時,指定 ArrayAdapter<CharSequence> 中 getView() 以及 getDropDownView() 所使用的 layout 格式,但卻有它的侷限性,就是我們無法自行定義在 getView() 與 getDropDownView() 中所做的動作,這意味著若是使用內建的 Adapter, DropDownView 將會局限在同一種 layout 格式裡面,因此,若是我們想要讓 DropDownView 中的每個 item 可以自行定義不同的 layout 格式,就要透過自訂 Adapter 的方式,重新覆寫 ArrayAdapter<CharSequence>中 的 getView() 以及 getDropDownView() 方法。
這邊要提醒的是,覆寫 ArrayAdapter<CharSequence> 時,建構子所傳入的參數是可以自己設定的,通常所需的選項資料會在這邊傳入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
public class ArrayAdapterSpn extends ArrayAdapter<CharSequence> { //繼承 ArrayAdapter<CharSequence> private LayoutInflater mLayInf; private Spinner mSpinner; private TypedArray mTypedArr; public ArrayAdapterSpn(Context context, int textViewResourceId, CharSequence[] objects, Spinner spinner) { super(context, textViewResourceId, objects); mLayInf = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mSpinner = spinner; mTypedArr = context.getResources().obtainTypedArray(R.array.spn_list); } @Override public View getView(int position, View convertView, ViewGroup parent) { //可透過 position 得知位置,設定每個選項之介面 View v = mLayInf.inflate(R.layout.spinner_item, parent, false); TextView txt = (TextView) v.findViewById(R.id.txt_getview); txt.setText(getItem(position).toString()); ImageView imgView = (ImageView) v.findViewById(R.id.imgView); imgView.setImageResource(mTypedArr.getResourceId(position, 0)); return v; } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { //可透過 position 得知位置,設定每個選項之介面 View v = mLayInf.inflate(R.layout.spinner_dropdown_item, parent, false); TextView txt = (TextView) v.findViewById(R.id.txt_getDropDownView); txt.setText(getItem(position).toString()); ImageView imgView = (ImageView) v.findViewById(R.id.imgViewSpnDropDown); imgView.setImageResource(mTypedArr.getResourceId(position, 0)); if (position == mSpinner.getSelectedItemPosition()) { v.setBackgroundColor(Color.GRAY); // 修改被選中的選項顏色 } return v; } } |
自訂 ArrayAdapter – ArrayAdapterSpn.java
透過繼承的方式,覆寫出屬於自己的 ArrayAdapter,在裡面重新定義建構子、getView()、getDropDownView() 三種方法,這樣不僅大大提升了介面的自由度,對於一些特殊的介面要求,亦能透過程式的改寫來達成,這也是專案開發的時候,最常用到的介面宣告方式。
臉書留言
一般留言