部落格 Spinner(1): 由SDK引發的問題、Spinner(2): 動態添加資源 簡單介紹了spinner,但是 Spinner 還有陷阱,所以使用時應該注意。
本篇部落格繼續探討Spinner及其注意事項,歡迎拍磚。
為 Spinner 設定 OnItemSelectedListener、OnTouchListener、OnFocusChangeListener 事件,看看在什麼情況下觸發這些事件。
看代碼,如下:
package mark.zhang;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.Spinner;public class SpinnerTestActivity extends Activity {private static final String[] strArrays = {"w" , "x", "y", "z"};private Spinner mSpinner;private ArrayAdapter<String> adapter;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mSpinner = (Spinner) findViewById(R.id.mySpinner);adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, strArrays);// 自訂spinner下拉樣式adapter.setDropDownViewResource(R.layout.myspinner_dropdown);mSpinner.setAdapter(adapter);// 設定選擇條目事件mSpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> arg0, View arg1,int arg2, long arg3) {Log.d("mark", "onItemSelected() is invoked!");arg0.setVisibility(View.VISIBLE);}@Overridepublic void onNothingSelected(AdapterView<?> arg0) {}});// 設定觸摸事件監聽mSpinner.setOnTouchListener(new Spinner.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {Log.d("mark", "onTouch() is invoked!");v.setVisibility(View.INVISIBLE);return false;}});// 設定焦點變化事件監聽mSpinner.setOnFocusChangeListener(new Spinner.OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {Log.d("mark", " onFocusChange() is invoked!");}});}}
代碼中,建立 ArrayAdapter 對象的同時,為 spinner 添加備選項目:
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, strArrays);
直接運行該 Android project,看看效果:
D/mark ( 1799): onItemSelected() is invoked!
注意:此時spinner中有預設顯示值。
可以看出,OnItemSelectedListener 監聽事件 onItemSelected 被調用。這就很讓人奇怪,根本沒有點擊 Spinner,為何會觸發該事件呢???
如果您好奇的話,跟我一起測試吧!
這樣來建立ArrayAdapter對象:
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
運行,沒有任何資訊出現。說明此時沒有觸發上述的任何監聽器設定的監聽器。
注意:此時 spinner 中沒有任何預設顯示值。
再做一個測試,修改代碼如下:
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);for(int i = 0; i<5; i++) {adapter.add("mark" + i);}
運行:
D/mark ( 5890): onItemSelected() is invoked!
呵呵,OnItemSelectedListener 監聽事件 onItemSelected 被調用。
當我們點擊 Spinner 的下拉式清單時,一定會觸發 OnTouchListener的onTouch 事件。但是不一定會觸發 OnItemSelectedListener的onItemSelected 事件。
如果,當前 Spinner 的預設顯示是 mark0,那麼再次點擊 mark0 的話,列印結果:
D/mark ( 5890): onTouch() is invoked!D/mark ( 5890): onTouch() is invoked!
可以看出,OnItemSelectedListener 的 onItemSelected 事件沒有被觸發,但是 OnTouchListener的onTouch 事件被觸發兩次。
如果,你點擊選項列表的其它值如 mark1,列印結果:
D/mark ( 5890): onTouch() is invoked!D/mark ( 5890): onTouch() is invoked!D/mark ( 5890): onItemSelected() is invoked!
呵呵,很戲劇化!
最後一個問題,何時觸發 OnFocusChangeListener 事件,很簡單,運行 App 之後,隨便改變當前焦點,就會觸發該事件。
知道這樣的結果之後,很無語!但是知道總比不知道好,至少您可以採取一點措施來避免一些不必要的麻煩。
比如,每次都想擷取 spinner 的值,就可以為其綁定 onTouch 事件(因為該事件每次點擊都會被觸發),但是注意,點擊 spinner 一次,會觸發該事件很多次(touch 包括很多動作如 down、up、move),那麽我們就在 event 事件的 down 事件裡面寫我們的代碼。即按下有效,up、move 等無效即可。