這篇來聊關於Spinner 下拉式清單(下拉式選單)的使用之2

我之前在這篇網誌有曾寫過Spinner的簡用法(´・з・)

如果僅需了解最基本用法以及想知道如何動態增減選單內容的朋友,請往這邊

->碼農日常-『Android studio』如何使用Spinner下拉式清單

上篇主要描述如何設置Spinner,並動態更新選單內容

這次要講的是客製化下拉式選單內的選單顯示

看不懂文字敘述的話看圖比較快d(>_・ )

Gif_20200425184355468_by_gifguru

 

仔細看圖中,下拉後的選單右邊有顯示資料人物的年齡

以及點選後,它會顯示該人物所綁定的資料

OK,那就開始今天的內容(`・ω・´)+


 

1.確認需要的內容以及畫介面

首先先描述一下有哪些東西要載入

1.客製Spinner的內容介面

2.Spinner的背景圖片

3.綁定的封裝資料(Getter-Setter)

啊...看不懂ㄇ 

正常啦因為如果我還不會使用的話我大概也看不懂(´・_・`)

直接看圖吧

截圖 2020-04-25 下午7.48.30

總之就是要新增以上四個東西~

喔關於那張圖片可以在這邊下載

->https://github.com/thumbb13555/CustomSpinnerExample/blob/master/app/src/main/res/drawable-v24/down.png

GitHub的圖片上點右鍵可以儲存放到自己的專案哦(¬_¬)ノ

 

首先來弄Spinner的背景

如果你是使用原廠的Spinner元件,那你應該會注意到原廠的Spinner在背景空白的情況下會與背景融為一體

什麼意思?(゚д゚;)

我拿上次的範例

Screenshot_20200426-005844_SpinnerExample

打圈的地方就是原廠的Spinner

會發現說如果背景是白色,那整個Spinner將會只剩一個箭頭

那我這次提供的Spinner是這樣

Screenshot_20200426-005928_SpinnerExample2

我不知道你會怎麼想啦~但是我覺得好多了(・ω・)b

總之就是要弄這麼一個東西

那麼首先把剛才提供的圖片加入drawable內

然後再新建一個圖片資源檔

建立方法:drawable上點右鍵->New->Drawable Resource File

最後把以下代碼複製進去(注意:箭頭圖片要先加入喔)

 

spinner_back.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    //第一組item 圓角邊框。
    <item>
        <shape>
            <stroke
                android:width="1dp"
                android:color="#B6B4B4"
                />    //邊框線顏色
            <corners android:radius="5dp" />      //圓角度數
            <solid android:color="#ffffff" >      //背景顏色
            </solid>
            <padding android:right="5dp" />       //邊距
            <size
                android:width="300dp"
                android:height="30dp"
                />
        </shape>
    </item>
    //第二組item 插入圖片(spinner箭頭)
    <item>
        <bitmap
            android:gravity="end"
            android:src="@drawable/down"
            android:antialias="true"
            />
    </item>

就完成囉(`Д´)ゞ

 

再來是畫介面..一樣直接給最快了

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="32dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:background="@drawable/spinner_back"/>

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Infor Display"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintBottom_toTopOf="@+id/spinner"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

粉色背景的部分進得要加入,效果才會顯示呦!(・ωー)~☆

最後效果會像這樣↓

截圖 2020-04-26 上午1.20.03

 

再來下一步要畫一個給Spinner本身使用的View介面

首先請新增一個Layout檔案

新增方法:layout資料夾點右鍵->New->Layout Resource File

然後這是Spinner的Layout源碼

 

spinner_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/textViewTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:text="TextView"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textViewAge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:text="TextView"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

最後結果則會是這樣↓

截圖 2020-04-26 上午1.25.11

到這邊可以先執行一下看看( ・ω・)ノ有時候介面會在你意想不到的地方出錯哦XD

2.建立封裝資料(Getter-Setter)

接著是建立Getter-Setter的封裝資料,請先建立一個類別

新增方法:java資料夾的下一個資料夾->右鍵->New->Java Class 

然後加入想要的資料型態,我的內容為

1.name->String

2.age->int

3.student->Boolean

然後按下control+↩︎(Enter),會看到這個畫面

截圖 2020-04-26 上午1.32.38

然後選擇藍底的部分Getter,最後把三個都選起來,按下OK

截圖 2020-04-26 上午1.33.22

 

接著加入Constructor(建構子)

一樣按下control+↩︎(Enter),這次選擇Constructor

截圖 2020-04-26 上午1.34.54

 

並且加入全部

截圖 2020-04-26 上午1.35.12

 

即完成囉(´υ`),最後程式會長這樣

Data.java

public class Data {

    private String name;
    private int age;
    private Boolean student;

    public Data(String name, int age, Boolean student) {
        this.name = name;
        this.age = age;
        this.student = student;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Boolean getStudent() {
        return student;
    }
}

其實相關用法我之前有在本網誌寫過,有興趣看我怎麼做可以點開來看哦(*゚ー゚)ゞ

在這裡->碼農日常-『Java』List<GetterSetter> 如何在陣列中使用Getter Setter

3.撰寫主程式

3-1 建立屬於自己的ArrayAdapter

以下程式碼之源碼都在這邊->MainActivity.java

 

在連接介面前,首先要先建立好ArrayAdapter的部分o(メ・・)=日☆

ArrayAdapter是什麼?簡單來說就像是RecyclerView會有RecyclerView.Adapter適配器一樣,Spinner也有他的御用適配器

而他就是ArrayAdapter

如果是了解Spinner基本用法的朋友,可以發現Spinner都會綁定一個ArrayAdapter的東西

然後裡面要輸入context,介面檔,還有陣列,是吧?

不知道我在說啥的請回頭看我之前的文章XD

->碼農日常-『Android studio』如何使用Spinner下拉式清單

去找找ArrayAdapter這個關鍵字在哪邊,就知道了(´・з・)

沒錯,這時候我們就要運用java中的繼承特性,來改寫原先的ArrayAdapter

首先請在onCreate外面新增一個私用類別,名字自己取

再來使他extends ArrayAdapter

像這樣↓

截圖 2020-04-26 上午1.51.41

PS. 紅線是正常的,因為沒加入建構子

 

再來是加入建構子,這個建構子跟編輯器建議的有點不一樣,直接複製我的好了

public MySpinnerAdapter(@NonNull Context context, @NonNull List<Data> mData) {
    super(context, 0, mData);
}

再來按下control+O,加入繼承

這邊我們需要繼承兩個,分別為getView以及getDropDownView

(請選藍底那兩個...)

截圖 2020-04-26 上午1.56.06

 

這時候程式長這樣

class MySpinnerAdapter extends ArrayAdapter {


    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        return super.getView(position, convertView, parent);
    }

    @Override
    public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        return super.getDropDownView(position, convertView, parent);
    }

    public MySpinnerAdapter(@NonNull Context context, @NonNull List<Data> mData) {
        super(context, 0, mData);
    }


}

簡單聊一下,我查過部分的說法會建議繼承BaseAdapter

但經實測,功能性不會比繼承ArrayAdapter好,畢竟大家都習慣ArrayAdapter的操作了

不信自己去實測一下,你就會知道差在哪裡了(・∀・)

 

那麼這個要怎麼玩呢?簡單來說

getView就是還沒選擇時所出現的介面

getDropDownView就是選擇後下拉展開時所出現的介面

 

簡單言之就是這樣而已( ´_ゝ`)

 

那麼重點是在這兩個而已,具體要怎麼實現看源碼最快

private class MySpinnerAdapter extends ArrayAdapter {

    //建構子
    public MySpinnerAdapter(@NonNull Context context, @NonNull List<Data> mData) {
        super(context, 0, mData);
    }
    //getView為設置未點開時的Spinner畫面
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        return createView(position, convertView, parent,false);
    }
    //getDropDownView為設置點開後的畫面
    @Override
    public View getDropDownView(int position, @Nullable View convertView, @NonNull
            ViewGroup parent) {
        return createView(position, convertView, parent,true);
    }

    //因為兩個介面通常都長差不多...所以新增介面的我把它寫在一起,差別只在最後的true/false
    @SuppressLint("SetTextI18n")
    private View createView(int position, View convertView
            , ViewGroup parent,Boolean ageDisplay){
        convertView = LayoutInflater.from(getContext()).inflate(//綁定介面
                R.layout.spinner_item, parent, false);
        TextView tvName = convertView.findViewById(R.id.textViewTitle);//控制介面元件
        TextView tvAge = convertView.findViewById(R.id.textViewAge);
        Data item = (Data) getItem(position);//取得每一筆的資料內容
        if (item != null) {
            tvName.setText(item.getName());
            tvAge.setText(item.getAge()+"y");
            if (ageDisplay) tvAge.setVisibility(View.VISIBLE);
            else tvAge.setVisibility(View.GONE);

        }
        return convertView;
    }//複寫介面

}//class MySpinnerAdapter

 

如果你覺得程式碼像是黑魔法的話~沒關係直接複製就好XD慢慢就會懂了

 

3-2 撰寫顯示資料

把焦點移回onCreate內,並加入以下程式

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

    /**=======================================================================================*/
    /**手動製造資料*/
    ArrayList<Data> mData = new ArrayList<>();
    mData.add(new Data("Sam",19,true));
    mData.add(new Data("Eddies",25,false));
    mData.add(new Data("Sally",17,true));
    mData.add(new Data("Noah",25,false));
    mData.add(new Data("Tina",30,false));
    /**=======================================================================================*/
    /**設置Spinner*/
    Spinner spList = findViewById(R.id.spinner);
    MySpinnerAdapter mAdapter = new MySpinnerAdapter(this,mData);//使用自定義的ArrayAdapter
    spList.setAdapter(mAdapter);
    /**=======================================================================================*/
   
}

加入後,這時候可以試著執行看看,應該就會顯示資料囉~

 

3-3 加入點擊事件

在功能圖的Gif內,點選完資料後會顯示該筆資料的內容(´・_・`)

不是我在自賣自誇..用我的方法有個絕大的好處,那就是

 

你點選的內容,這項內容背後所一並攜帶的資料都會被一起叫出

這次的網誌就是個好例子,我點了第一個名字Sam後

他名字所攜帶的資料19歲,是學生等資料也會一並被抓出來

那是不宜遲就來看看點擊事件

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

    /**=======================================================================================*/
    /**手動製造資料*/
    ArrayList<Data> mData = new ArrayList<>();
    mData.add(new Data("Sam",19,true));
    mData.add(new Data("Eddies",25,false));
    mData.add(new Data("Sally",17,true));
    mData.add(new Data("Noah",25,false));
    mData.add(new Data("Tina",30,false));
    /**=======================================================================================*/
    /**設置Spinner*/
    Spinner spList = findViewById(R.id.spinner);
    MySpinnerAdapter mAdapter = new MySpinnerAdapter(this,mData);//使用自定義的ArrayAdapter
    spList.setAdapter(mAdapter);
    /**=======================================================================================*/
    /**設置Spinner點擊事件*/
    spList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {//Spinner點擊後
        @SuppressLint("SetTextI18n")
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            TextView tvInfo = findViewById(R.id.textView);
            Data mData = (Data) parent.getItemAtPosition(position);
            tvInfo.setText("名字:\t"+mData.getName()+"\n"
                    +"年齡:\t"+mData.getAge() +"\n"
                    +"是否為學生?\t"+mData.getStudent());
        }
        @Override
        public void onNothingSelected(AdapterView<?> parent) {}
    });//點擊事件

 

底線處就是將資料抓出來的方法,而將這些資料抓出來後,就可以一並顯示在畫面中囉~

是不是很方便呢?d(>_・ )

 

這時候程式都完成了,實行起來應該就會像畫面中那樣囉

Gif_20200425184355468_by_gifguru

 


 

結語

之前還是蔡逼八的時候,我腦袋很死,只能用最簡單的Spinner去處理資料

後來回頭看那時候的程式碼...真的是神聖的大*啊(Holy sh*t)

(對不起我知道這是"很糟糕"的意思,只是我真心覺得以前寫的程式像一坨大*...)

 

其實工作雖然是壓榨你的大腦,但是腦子就是要用才會靈活(•ө•)♡

慢慢地在我工作的快一年裡,對於Java也好Android也罷甚至kotlin

有了很多不同層面的認識(゚д゚;)

甚至使用Kotlin後回頭Java Coding

發現自己漸漸擺脫了老是想用全域變數偷懶的習慣

也慢慢地程式碼越來越簡潔、越來越好懂(・ωー)~☆

對我而言當時學習Spinner 的複寫ArrayAdapter就是個好例子

 

那這次的介紹到這,希望能夠解決你的問題

喜歡我的文章並有痞客邦帳號的話歡迎收藏我的文章哦~

下載

arrow
arrow

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