這篇來聊關於Spinner 下拉式清單(下拉式選單)的使用之2
我之前在這篇網誌有曾寫過Spinner的簡用法(´・з・)
如果僅需了解最基本用法以及想知道如何動態增減選單內容的朋友,請往這邊
->碼農日常-『Android studio』如何使用Spinner下拉式清單
上篇主要描述如何設置Spinner,並動態更新選單內容
這次要講的是客製化下拉式選單內的選單顯示
看不懂文字敘述的話看圖比較快d(>_・ )
仔細看圖中,下拉後的選單右邊有顯示資料人物的年齡
以及點選後,它會顯示該人物所綁定的資料
OK,那就開始今天的內容(`・ω・´)+
1.確認需要的內容以及畫介面
首先先描述一下有哪些東西要載入
1.客製Spinner的內容介面
2.Spinner的背景圖片
3.綁定的封裝資料(Getter-Setter)
啊...看不懂ㄇ
正常啦因為如果我還不會使用的話我大概也看不懂(´・_・`)
直接看圖吧
總之就是要新增以上四個東西~
喔關於那張圖片可以在這邊下載
在GitHub的圖片上點右鍵可以儲存放到自己的專案哦(¬_¬)ノ
首先來弄Spinner的背景
如果你是使用原廠的Spinner元件,那你應該會注意到原廠的Spinner在背景空白的情況下會與背景融為一體
什麼意思?(゚д゚;)
我拿上次的範例
打圈的地方就是原廠的Spinner
會發現說如果背景是白色,那整個Spinner將會只剩一個箭頭
那我這次提供的Spinner是這樣
我不知道你會怎麼想啦~但是我覺得好多了(・ω・)b
總之就是要弄這麼一個東西
那麼首先把剛才提供的圖片加入drawable內
然後再新建一個圖片資源檔
建立方法:drawable上點右鍵->New->Drawable Resource File
最後把以下代碼複製進去(注意:箭頭圖片要先加入喔)
<?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>
就完成囉(`Д´)ゞ
再來是畫介面..一樣直接給最快了
<?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>
粉色背景的部分進得要加入,效果才會顯示呦!(・ωー)~☆
最後效果會像這樣↓
再來下一步要畫一個給Spinner本身使用的View介面
首先請新增一個Layout檔案
新增方法:layout資料夾點右鍵->New->Layout Resource File
然後這是Spinner的Layout源碼
<?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>
最後結果則會是這樣↓
到這邊可以先執行一下看看( ・ω・)ノ有時候介面會在你意想不到的地方出錯哦XD
2.建立封裝資料(Getter-Setter)
接著是建立Getter-Setter的封裝資料,請先建立一個類別
新增方法:java資料夾的下一個資料夾->右鍵->New->Java Class
然後加入想要的資料型態,我的內容為
1.name->String
2.age->int
3.student->Boolean
然後按下control+↩︎(Enter),會看到這個畫面
然後選擇藍底的部分Getter,最後把三個都選起來,按下OK
接著加入Constructor(建構子)
一樣按下control+↩︎(Enter),這次選擇Constructor
並且加入全部
即完成囉(´υ`),最後程式會長這樣
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
像這樣↓
PS. 紅線是正常的,因為沒加入建構子
再來是加入建構子,這個建構子跟編輯器建議的有點不一樣,直接複製我的好了
public MySpinnerAdapter(@NonNull Context context, @NonNull List<Data> mData) { super(context, 0, mData); }
再來按下control+O,加入繼承
這邊我們需要繼承兩個,分別為getView以及getDropDownView
(請選藍底那兩個...)
這時候程式長這樣
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(>_・ )
這時候程式都完成了,實行起來應該就會像畫面中那樣囉
結語
之前還是蔡逼八的時候,我腦袋很死,只能用最簡單的Spinner去處理資料
後來回頭看那時候的程式碼...真的是神聖的大*啊(Holy sh*t)
(對不起我知道這是"很糟糕"的意思,只是我真心覺得以前寫的程式像一坨大*...)
其實工作雖然是壓榨你的大腦,但是腦子就是要用才會靈活(•ө•)♡
慢慢地在我工作的快一年裡,對於Java也好Android也罷甚至kotlin
有了很多不同層面的認識(゚д゚;)
甚至使用Kotlin後回頭Java Coding
發現自己漸漸擺脫了老是想用全域變數偷懶的習慣
也慢慢地程式碼越來越簡潔、越來越好懂(・ωー)~☆
對我而言當時學習Spinner 的複寫ArrayAdapter就是個好例子
那這次的介紹到這,希望能夠解決你的問題
喜歡我的文章並有痞客邦帳號的話歡迎收藏我的文章哦~
留言列表