第五章 用戶界面基礎(chǔ)(Spinner)

參考資料:
《Android應(yīng)用程序開發(fā)》ISBN 9787302283164
參考軟件:
Android Studio、Eclipse+ADT、Android SDK、JDK
Spinner
Spinner提供了從一個(gè)數(shù)據(jù)集合中快速選擇一項(xiàng)值的辦法。默認(rèn)情況下Spinner顯示的是當(dāng)前選擇的值,點(diǎn)擊Spinner會(huì)彈出一個(gè)包含所有可選值的dropdown菜單,從該菜單中可以為Spinner選擇一個(gè)新值。

一、最簡單的Spinner
在布局文件中添加Spinner控件
1.??????<LinearLayout
2.??????????android:layout_width="fill_parent"
3.??????????android:layout_height="fill_parent"
4.??????????android:orientation="vertical"?>
5.
6.??????????<Spinner
7.??????????????android:id="@+id/spinner1"
8.??????????????android:layout_width="wrap_content"
9.??????????????android:layout_height="wrap_content"
10.????????????android:entries="@array/languages"
11.??????????/>
12.????</LinearLayout>
其中android:entries="@array/languages"表示Spinner的數(shù)據(jù)集合是從資源數(shù)組languages中獲取的,languages數(shù)組資源定義在values/arrays.xml中:
1.??<?xml?version="1.0"?encoding="utf-8"?>
2.??<resources>
3.??????<string-array?name="languages">
4.??????????<item>c語言</item>
5.??????????<item>java?</item>
6.??????????<item>php</item>
7.??????????<item>xml</item>
8.??????????<item>html</item>
9.??????</string-array>
10.</resources>
如果你不需要對Spinner的選擇事件做響應(yīng),那么一個(gè)完整的Spinner使用流程就結(jié)束了。
運(yùn)行結(jié)果:

當(dāng)然,一般情況下我們是需要響應(yīng)Spinner選擇事件的,可以通過OnItemSelectedListener的回調(diào)方法實(shí)現(xiàn)
1.??public?class?MainActivity?extends?Activity?{
2.
3.??????@Override
4.??????protected?void?onCreate(Bundle?savedInstanceState)?{
5.??????????super.onCreate(savedInstanceState);
6.??????????setContentView(R.layout.activity_main);
7.??????????Spinner?spinner?=?(Spinner)?findViewById(R.id.spinner1);
8.??????????spinner.setOnItemSelectedListener(new?OnItemSelectedListener()?{
9.??????????????@Override
10.????????????public?void?onItemSelected(AdapterView<?>?parent,?View?view,
11.????????????????????int?pos,?long?id)?{
12.
13.????????????????String[]?languages?=?getResources().getStringArray(R.array.languages);
14.????????????????Toast.makeText(MainActivity.this,?"你點(diǎn)擊的是:"+languages[pos],?2000).show();
15.????????????}
16.????????????@Override
17.????????????public?void?onNothingSelected(AdapterView<?>?parent)?{
18.????????????????//?Another?interface?callback
19.????????????}
20.????????});
21.????}
22.
23.}
上面的Spinner看起來非常漂亮,不過它并不是總是如此,剛剛看到的是在android:Theme.Holo.Light主題下的效果,同樣的代碼如果在android:Theme.Light下面就會(huì)變得很丑。?


想必這也是很多人不想使用Spinner的原因了吧。如果想兼容2.3,則只能忍受這樣的效果。
二、設(shè)置Spinner的Adapter
上面使用Spinner數(shù)據(jù)源于xml數(shù)組,其實(shí)用的最多的還是通過adapter來跟Spinner綁定數(shù)據(jù)。
三、使用ArrayAdapter
1.??//?初始化控件
2.??Spinner?spinner?=?(Spinner)?findViewById(R.id.spinner1);
3.??//?建立數(shù)據(jù)源
4.??String[]?mItems?=?getResources().getStringArray(R.array.languages);
5.??//?建立Adapter并且綁定數(shù)據(jù)源
6.??ArrayAdapter<String>?adapter=new?ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,?mItems);
7.??adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
8.??//綁定?Adapter到控件
9.??spinner?.setAdapter(adapter);
10.spinner.setOnItemSelectedListener(new?OnItemSelectedListener()?{
11.????@Override
12.????public?void?onItemSelected(AdapterView<?>?parent,?View?view,
13.????????????int?pos,?long?id)?{
14.
15.????????String[]?languages?=?getResources().getStringArray(R.array.languages);
16.????????Toast.makeText(MainActivity.this,?"你點(diǎn)擊的是:"+languages[pos],?2000).show();
17.????}
18.????@Override
19.????public?void?onNothingSelected(AdapterView<?>?parent)?{
20.????????//?Another?interface?callback
21.????}
22.});
這是Spinner的標(biāo)準(zhǔn)使用方法,其中,有兩行代碼可以決定Spinner的外觀:
?ArrayAdapter<String>?adapter=new?ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,?mItems);
第二個(gè)參數(shù)是Spinner未展開菜單時(shí)Spinner的默認(rèn)樣式,android.R.layout.simple_spinner_item是系統(tǒng)自帶的內(nèi)置布局。
?adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
設(shè)置的是展開的時(shí)候下拉菜單的樣式(注意和上面區(qū)別),同理android.R.layout.simple_spinner_dropdown_item也是內(nèi)置布局。
如果不設(shè)置
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)會(huì)怎樣呢?
會(huì)造成未展開的sipnner和展開的菜單都是一種布局樣式。下面一運(yùn)行截圖來說明:
沒有
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item):

有setDropDownViewResource:

你可能會(huì)很好奇如果設(shè)置了setDropDownViewResource但是
setDropDownViewResource的參數(shù)和ArrayAdapter的第二個(gè)布局參數(shù)(simple_spinner_item)一致的情況下會(huì)怎樣。情況是和沒有setDropDownViewResource是一樣的,因?yàn)樯厦嬲f了不設(shè)置setDropDownViewResource Spinner未展開和展開都是用的一樣的布局。
其實(shí)simple_spinner_item和simple_spinner_dropdown_item兩者的名字正好反映了他們的區(qū)別。一個(gè)應(yīng)用于下拉一個(gè)應(yīng)用于Spinner本身。
?
四、使用自定義的BaseAdapter
這種情況適用于spinner比較復(fù)雜的情況,比如帶有圖標(biāo)。
下面我們定義一個(gè)選擇聯(lián)系人的Spinner。
1.??????<LinearLayout
2.??????????android:layout_width="fill_parent"
3.??????????android:layout_height="80dip"
4.??????????android:orientation="vertical"?>
5.
6.??????????<Spinner
7.??????????????android:id="@+id/spinner2"
8.??????????????android:layout_width="wrap_content"
9.??????????????android:layout_height="wrap_content"
10.??????????/>
11.????</LinearLayout>
activity中:
1.?????????????//?初始化控件
2.??????????Spinner?spinner2??=?(Spinner)?findViewById(R.id.spinner2);
3.??????????//?建立數(shù)據(jù)源
4.??????????List<Person>??persons=new?ArrayList<Person>();
5.??????????persons.add(new?Person("張三",?"上海?"));
6.??????????persons.add(new?Person("李四",?"上海?"));
7.??????????persons.add(new?Person("王五",?"北京"?));
8.??????????persons.add(new?Person("趙六",?"廣州?"));
9.??????????//??建立Adapter綁定數(shù)據(jù)源
10.????????MyAdapter?_MyAdapter=new?MyAdapter(this,?persons);
11.????????//綁定Adapter
12.????????spinner2.setAdapter(_MyAdapter);
Person.java
1.??package?com.example.spinnerdemo;
2.
3.??public?class?Person?{
4.??????private?String?personName;
5.??????private?String?personAddress;
6.??????public?Person(String?personName,?String?personAddress)?{
7.??????????super();
8.??????????this.personName?=?personName;
9.??????????this.personAddress?=?personAddress;
10.????}
11.????public?String?getPersonName()?{
12.????????return?personName;
13.????}
14.????public?void?setPersonName(String?personName)?{
15.????????this.personName?=?personName;
16.????}
17.????public?String?getPersonAddress()?{
18.????????return?personAddress;
19.????}
20.????public?void?setPersonAddress(String?personAddress)?{
21.????????this.personAddress?=?personAddress;
22.????}
23.
24.}
MyAdapter.java
1.??package?com.example.spinnerdemo;
2.
3.??import?java.util.List;
4.??import?android.content.Context;
5.??import?android.view.LayoutInflater;
6.??import?android.view.View;
7.??import?android.view.ViewGroup;
8.??import?android.widget.BaseAdapter;
9.??import?android.widget.ImageView;
10.import?android.widget.TextView;
11.
12./**
13.?*?自定義適配器類
14.?*?@author?jiangqq??<a?href=http://blog.csdn.net/jiangqq781931404></a>
15.?*
16.?*/
17.public?class?MyAdapter?extends?BaseAdapter?{
18.????private?List<Person>?mList;
19.????private?Context?mContext;
20.
21.????public?MyAdapter(Context?pContext,?List<Person>?pList)?{
22.????????this.mContext?=?pContext;
23.????????this.mList?=?pList;
24.????}
25.
26.????@Override
27.????public?int?getCount()?{
28.????????return?mList.size();
29.????}
30.
31.????@Override
32.????public?Object?getItem(int?position)?{
33.????????return?mList.get(position);
34.????}
35.
36.????@Override
37.????public?long?getItemId(int?position)?{
38.????????return?position;
39.????}
40.????/**
41.?????*?下面是重要代碼
42.?????*/
43.????@Override
44.????public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{
45.????????LayoutInflater?_LayoutInflater=LayoutInflater.from(mContext);
46.????????convertView=_LayoutInflater.inflate(R.layout.item_custom,?null);
47.????????if(convertView!=null)?{
48.????????????ImageView?imageView?=?(ImageView)convertView.findViewById(R.id.image);
49.????????????imageView.setImageResource(R.drawable.ic_launcher);
50.????????????TextView?_TextView1=(TextView)convertView.findViewById(R.id.textView1);
51.????????????TextView?_TextView2=(TextView)convertView.findViewById(R.id.textView2);
52.????????????_TextView1.setText(mList.get(position).getPersonName());
53.????????????_TextView2.setText(mList.get(position).getPersonAddress());
54.????????}
55.????????return?convertView;
56.????}
57.}
運(yùn)行效果:

?
Spinner的菜單顯示方式
它有兩種顯示形式,一種是下拉菜單,一種是彈出框,菜單顯示形式是spinnerMode屬性決定的:
1.??android:spinnerMode="dropdown"
2.??android:spinnerMode="dialog"
在android2.3上沒有這個(gè)屬性,系統(tǒng)默認(rèn)將Spinner彈出菜單顯示成dialog。
?
Spinner的xml屬性
其實(shí)上面已經(jīng)提到了Spinner的兩個(gè)屬性:
1 entries:?直接在xml布局文件中綁定數(shù)據(jù)源(可以不設(shè)置,即可以在Activity中動(dòng)態(tài)綁定)
2 spinnerMode: Spinner的顯示形式
除此之外還有如下屬性:
prompt:在Spinner彈出選擇對話框的時(shí)候?qū)υ捒虻臉?biāo)題:

?
屬性名稱
android:dropDownHorizontalOffset
對應(yīng)方法:? ??
setDropDownHorizontalOffset(int)
spinnerMode=”dropdown”時(shí),下拉的項(xiàng)目選擇窗口在水平方向相對于Spinner窗口的偏移量。
它必須是一個(gè)帶有單位的浮點(diǎn)型尺寸值,如:”14.5sp”。有效的單位包括:px(像素)、dp(密度無關(guān)的像素)、sp(基于引用字體的尺寸來縮放的像素)、in(英寸)、mm(毫米)。
這個(gè)屬性還可以引用一個(gè)資源(格式:@[package:]type:name)或者是包含這種類型值的主題屬性(格式:?[package][type:]name)。
這個(gè)屬性對應(yīng)全局屬性資源符號dropDownHorizontalOffset。
android:dropDownSelector
用于設(shè)定spinnerMode=”dropdown”時(shí)列表選擇器的顯示效果。
它可以用”@[+][package]:type:name”格式來引用另外的資源,或者是用”?[package:][type:]name”的格式來應(yīng)用主題屬性,還可以是”#rgb”、”#argb”、”#rrggbb”、”aarrggbb”格式的顏色值。
它對應(yīng)的全局屬性資源符號是dropDownSelector。
android:dropDownVerticalOffset
對應(yīng)方法:
setDropDownVerticalOffset(int)
spinnerMode=”dropdown”時(shí),下拉的項(xiàng)目選擇窗口在垂直方向相對于Spinner窗口的偏移量。
這個(gè)屬性它必須是一個(gè)帶有單位的浮點(diǎn)型尺寸值,如:”14.5sp”。有效的單位包括:px(像素)、dp(密度無關(guān)的像素)、sp(基于引用字體的尺寸來縮放的像素)、in(英寸)、mm(毫米)。
還可以引用一個(gè)資源(格式:@[package:]type:name)或者是包含這種類型值的主題屬性(格式:?[package][type:]name)。
這個(gè)屬性對應(yīng)全局屬性資源符號dropDownVerticalOffset。
android:dropDownWidth
對應(yīng)方法:
?setDropDownWidth(int)
在spinnerMode=”dropdown”時(shí),設(shè)定下拉框的寬度。
這個(gè)屬性可以是帶有單位的浮點(diǎn)型的尺寸值,如:14.5sp。有效的單位包括:px(像素)、dp(密度無關(guān)的像素)、sp(基于引用字體的尺寸來縮放的像素)、in(英寸)、mm(毫米)。
還可以引用一個(gè)資源(格式:@[package:]type:name)或者是包含這種類型值的主題屬性(格式:?[package][type:]name)。
還可以是下列常量之一:
fill_parent = -1,下拉框的寬度應(yīng)該使用屏幕的寬度來設(shè)定。這個(gè)常量從API Level 8開始被廢棄了,并且使用mach_parent常量來代替。
mach_parent = -1,下拉框的寬度應(yīng)該使用屏幕的寬度來設(shè)定。在API Level 8中被引入。
wrap_content = -2,下拉框的寬度應(yīng)該跟它的內(nèi)容相適應(yīng)。
它對應(yīng)的全局資源符號是dropDownWidth。
android:gravity
對應(yīng)方法:
setGravity(int)
這個(gè)屬性用于設(shè)置當(dāng)前選擇的項(xiàng)目的對齊方式。
它必須是以下常量值之一或組合(用”|”符號分離)。
top = 0x30:把選擇的對象放到它的容器的頂部,不改變它的尺寸。
bottom = 0x50:把選擇的對象放到它的容器的底部,不改變它的尺寸。
left = 0x03:把選擇的對象放到它的容器的左邊,不改變它的尺寸。
right = 0x05:把選擇的對象放到它的容器的右邊,不改變它的尺寸。
center_vertical = 0x10:把選擇的對象放到它的容器的垂直中心,不改變它的尺寸。
fill_vertical = 0x70:為了完全的填充它的容器,系統(tǒng)會(huì)根據(jù)需要來增加選擇對象的垂直尺寸。
center_horizontal = 0x01:把選擇的對象放到它的容器的水平中心,不改變它的尺寸。
fill_horizontal = 0x07:為了完全的填充它的容器,系統(tǒng)會(huì)根據(jù)需要來增加選擇對象的水平尺寸。
center = 0x11:把選擇的對象放到它的容器的垂直和水平中心,不改變它的尺寸。
fill = 0x77:為了完全的填充它的容器,系統(tǒng)會(huì)根據(jù)需要來增加選擇對象的水平和垂直尺寸。
clip_vertical = 0x80:附加的可選設(shè)置,它可以設(shè)置容器內(nèi)子對象的上下邊緣裁剪它的容器邊框。裁剪會(huì)基于垂直對齊的方式:頂部對齊的會(huì)裁剪底部邊緣,底部對齊的會(huì)裁剪頂部邊緣,不會(huì)上下邊緣都裁剪。
clip_horizontal = 0x08:附加的可選設(shè)置,它可以設(shè)置容器內(nèi)子對象的左右邊緣裁剪它的容器邊框。裁剪會(huì)基于水平對齊的方式:左對齊的會(huì)裁剪右邊緣,右對齊的會(huì)裁剪左邊緣,不會(huì)左右邊緣都裁剪。
start = 0x00800003:把對象放到它的容器的開始位置,不改變它的尺寸。
end = 0x00800005:把對象放到它的容器的結(jié)束位置,不改變它的尺寸。
對應(yīng)的全局屬性資源符號是gravity。
注:Spinner對象是一個(gè)視窗對象容器,設(shè)置它的gravity屬性時(shí),只會(huì)改變?nèi)萜鲀?nèi)部子視窗對象的對齊方式,并不會(huì)改變子視窗內(nèi)部內(nèi)容的對齊方式。
android:popupBackground
對應(yīng)方法:
setPopupBackgroundResource(int)
在spinner=”dropdown”時(shí),使用這個(gè)屬性來設(shè)置下拉列表的背景。
可以使用”@[+][package:]type:name”格式來引用另外的資源,或者使用”?[package:][type:]name”格式來應(yīng)用主題屬性,也可以使用”#rgb”、”#argb”、”#rrggbb”、”#aarrggbb”格式的顏色值。
對應(yīng)的全局屬性資源符號是popupBackground
?