哈~~囉~~

今天要來講講關於下拉式選單(清單)(spinner)

對我而言這是個在實戰中蠻常用的元件

而且每次遇到的狀況又特別雞歪_(:3」∠)_

之前找關於這方面的資料時,頭真的很痛

因為當時第一次使用這個元件、找資料時

找到的資料都是固定內容的選單...連官網也不例外(´・_・`)

附上官網連結,去參考一下就知道啦

這裏->https://developer.android.com/guide/topics/ui/controls/spinner

但當時還是蔡逼八時的專案又是要求選單內容要隨著內容改變,最好要能擴充的

有鑒於中文資料偏少,故寫下一篇文章作紀錄

那本篇文章中,將會示範官網的這種固定式的做法以及以ArrayList做出可變動的選單兩種

以及也會示範動態變更選單內容的做法~(・ωー)~☆

那就上功能吧!

spinner範例

以及Github

https://github.com/thumbb13555/SpinnerExample


 

1.拉介面

上圖示範中我放兩個spinner,上方的是完全仿照官網的做法處理

下方的是使用ArrayList完成動態陣列,而下方兩個按鈕分別可以針對此陣列(選單內容)做增減

拉介面並不是什麼很困難的事...所以我直接放吧(`・ω・´)+

activity_main.xml

這時候可以執行一下,看看介面的程式碼有沒有錯哦(•ө•)♡

2.加入array.xml的陣列資料

前面也說了,這篇文章中將會示範兩種設置Spinner的作法

那首先從官網示範的來吧~

 

簡單說明一下,官網的作法是

1.在資源檔中建立一個放陣列的資源

2.呼叫陣列適配器(ArrayAdapter)

3.將資料以資源檔的形式放入ArrayAdapter內

那我們就按照官網的作法來一次吧~

2-1載入介面資源檔

首先在資源檔資料夾

路徑: res/values/之下建立一個新的資源檔,我取名叫array.xml

截圖 2020-04-02 下午3.13.52

新增方法:

在values資料夾上點右鍵->New->Values Resourece File即可

截圖 2020-04-02 下午3.16.24

 

接著把資料放進去~點開這個檔案然後把以下內容放入o(メ・・)=日☆

array.xml

就完成設置囉(・ω・)b

 

3.設置第一個spinner(綁定資源檔陣列)

把焦點切到MainActivity.java這邊

要設置一個Spinner的具體作法如下

1.連結介面實體

2.宣吿ArrayAdapter

3.將資源檔(陣列)嵌入ArrayAdapter

4.用Spinner的setAdapter方法載入ArrayAdapter內

了解後實際來操作吧

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Spinner spinner1 = findViewById(R.id.spinnerEX1);
        Spinner spinner2 = findViewById(R.id.spinnerEX2);
        Button btAdd = findViewById(R.id.buttonADD);
        Button btRemove = findViewById(R.id.buttonRemove);

        ArrayAdapter adapter1 = ArrayAdapter.createFromResource(this
                ,R.array.planets_array,android.R.layout.simple_dropdown_item_1line);
        spinner1.setAdapter(adapter1);

      
    }
}

ArrayAdapter.createFromResoure中,要丟給它的基本上就是

1.context(上下文)

2.資源檔陣列

3.下拉介面樣式(一般使用android提供的單行下拉就可以囉)

 

Okay,做到這邊可以先執行看看,陣列應該會成功載入到Spinner囉

 

4.設置第二個spinner(動態陣列&點擊事件)

4-1 陣列載入至Spinner

接著要設置第二個spinner-以ArrayList完成的陣列

基本上邏輯也是一樣,但是ArrayAdapter有稍微改了一點點

我直接Po並標明重點吧

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Spinner spinner1 = findViewById(R.id.spinnerEX1);
        Spinner spinner2 = findViewById(R.id.spinnerEX2);
        Button btAdd = findViewById(R.id.buttonADD);
        Button btRemove = findViewById(R.id.buttonRemove);

        ArrayAdapter adapter1 = ArrayAdapter.createFromResource(this
                ,R.array.planets_array,android.R.layout.simple_dropdown_item_1line);
        spinner1.setAdapter(adapter1);


        ArrayList arrayList = new ArrayList<Integer>();
        for (int i = 0;i<5;i++){
            arrayList.add(i);
        }//製作陣列

        ArrayAdapter adapter2 = new  ArrayAdapter(this
                ,android.R.layout.simple_dropdown_item_1line,arrayList);
        spinner2.setAdapter(adapter2);
        
    }
}

可以看到兩者之間有點差異性

ArrayAdapter.createFromResoure需要載入

1.context(上下文)

2.資源檔陣列

3.下拉介面樣式

 

而 new ArrayAdapter則是載入

1.context(上下文)

2.下拉介面樣式

3.要呈現的陣列(僅可ArrayList)

 

然後做到這邊可以再執行一次,看看效果如何(・∀・)

 

4-2 加入點擊事件

Spinner的點擊事件,是使用setOnItemSelectedListener並配合AdapterView.OnItemSelectedListener完成

一樣直接上程式

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Spinner spinner1 = findViewById(R.id.spinnerEX1);
        Spinner spinner2 = findViewById(R.id.spinnerEX2);
        Button btAdd = findViewById(R.id.buttonADD);
        Button btRemove = findViewById(R.id.buttonRemove);

        ArrayAdapter adapter1 = ArrayAdapter.createFromResource(this
                ,R.array.planets_array,android.R.layout.simple_dropdown_item_1line);
        spinner1.setAdapter(adapter1);


        ArrayList arrayList = new ArrayList<Integer>();
        for (int i = 0;i<5;i++){
            arrayList.add(i);
        }//製作陣列

        ArrayAdapter adapter2 = new  ArrayAdapter(this
                ,android.R.layout.simple_dropdown_item_1line,arrayList);
        spinner2.setAdapter(adapter2);
        spinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
     
                 Toast.makeText(view.getContext(),parent.getSelectedItem().toString()/*這行可直接取得選中內容*/,Toast.LENGTH_SHORT).show();
                
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {}
        });
        
    }
}

4-3 修正spinner的自動預設事件

寫到這邊,建議讀者再Run一次程式,基本上大體上是沒有問題的

但是如果仔細看會發現...為何每次一重新執行,Toast就會直接彈出了呢?

原因是出在於,setOnItemSelectedListener本身在開啟時,會直接先把第一個選項載入

這時候如果你的選項一有連帶動作,恐怕就會誤觸發,造成一些問題(´・_・`)

因此我這樣做

public class MainActivity extends AppCompatActivity {
    Boolean firstTime = true;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Spinner spinner1 = findViewById(R.id.spinnerEX1);
        Spinner spinner2 = findViewById(R.id.spinnerEX2);
        Button btAdd = findViewById(R.id.buttonADD);
        Button btRemove = findViewById(R.id.buttonRemove);

        ArrayAdapter adapter1 = ArrayAdapter.createFromResource(this
                ,R.array.planets_array,android.R.layout.simple_dropdown_item_1line);
        spinner1.setAdapter(adapter1);


        ArrayList arrayList = new ArrayList<Integer>();
        for (int i = 0;i<5;i++){
            arrayList.add(i);
        }//製作陣列

        ArrayAdapter adapter2 = new  ArrayAdapter(this
                ,android.R.layout.simple_dropdown_item_1line,arrayList);
        spinner2.setAdapter(adapter2);
        spinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
     
                if (firstTime){firstTime = false;}
                else{
                    Toast.makeText(view.getContext(),parent.getSelectedItem().toString(),Toast.LENGTH_SHORT).show();
                }
                
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {}
        });
        
    }
}

 

就能防止誤動作囉~(看不懂我在幹嘛的...小力去撞豆腐)

 

5.加入按鈕使選項內容能自由刪減

關於spinner內容動態刪減的這個問題,我曾經花了一點時間去方法

後來我發現...

只要修改上面被適配器(ArrayAdapter)所綁定的陣列就可以了

什麼notifyChange啊什麼的...完全無需處理

直接Po...

public class MainActivity extends AppCompatActivity {
    Boolean firstTime = true;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Spinner spinner1 = findViewById(R.id.spinnerEX1);
        Spinner spinner2 = findViewById(R.id.spinnerEX2);
        Button btAdd = findViewById(R.id.buttonADD);
        Button btRemove = findViewById(R.id.buttonRemove);

        ArrayAdapter adapter1 = ArrayAdapter.createFromResource(this
                ,R.array.planets_array,android.R.layout.simple_dropdown_item_1line);
        spinner1.setAdapter(adapter1);


        ArrayList arrayList = new ArrayList<Integer>();
        for (int i = 0;i<5;i++){
            arrayList.add(i);
        }//製作陣列

        ArrayAdapter adapter2 = new  ArrayAdapter(this
                ,android.R.layout.simple_dropdown_item_1line,arrayList);
        spinner2.setAdapter(adapter2);
        spinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
     
                if (firstTime){firstTime = false;}
                else{
                    Toast.makeText(view.getContext(),parent.getSelectedItem().toString(),Toast.LENGTH_SHORT).show();
                }
                
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {}
        });
        btAdd.setOnClickListener((v)->{
            arrayList.add(arrayList.size());
        });
        btRemove.setOnClickListener((v -> {
            if (arrayList.size()!=0){
                arrayList.remove(arrayList.size()-1);
            }
        }));
    }
}

 


 

結語

前文也有說...spinner我也算是搞了一小段時間

有時候越簡單的元件喔,因為常見,所以來自客戶或老闆他們的想像力就多

我這個還沒有把樣式包上去....不然一般而言Spinner都會放個樣式吧~

然後動態更新Spinner內容也是找了好多文章才發現根本就是自己把他想像得太難了

畢竟大家都會覺得...應該就跟RecyclerView的notifyDataSetChanged()一樣吧..的想法

哎,也算是繞了一大圈啦XD

 

另外,最近我偶爾會收到來自讀者的反饋,有些人也會寄Mail問我問題

我這裡強調

我非常歡迎這種行為

沒看清楚嗎?

非常歡迎這種行為

非常歡迎這種行為

非常歡迎這種行為(・ωー)~☆

 

而且我發現寄mail來問的比較多XD 大家都很低調

感謝大家的鼓勵,我會再努力發各種Android的大小事的

希望大家都可以在我這憋學到一點東西

那文章到此,感謝各位~

下載

 

 
arrow
arrow
    創作者介紹
    創作者 碼農日常 的頭像
    碼農日常

    碼農日常大小事

    碼農日常 發表在 痞客邦 留言(2) 人氣()