iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 27
2
Software Development

Kotlin for Android系列 第 27

Day 27. Android RecyclerView - 1/2

  今天要來應用新的元件 RecyclerView

https://ithelp.ithome.com.tw/upload/images/20181110/20111944aJqokbA8gA.png

  使用之前必須到 Gradle Scripts > build.gradle (Module: app) > dependencies 加入使用相關 API,在新的一行按 Alt + Enter > 選擇圖二的 recyclerview

https://ithelp.ithome.com.tw/upload/images/20181110/20111944lK52iOuAMd.png
https://ithelp.ithome.com.tw/upload/images/20181110/201119446Tl4IRYJT5.png

  接著請確定是否有產生如下的片段,若前方非 implementaion 請修正如下:

implementation 'com.android.support:recyclerview-v7:28.0.0'

  此時畫面右上方會出現 Sync Now 字樣,請點選讓專案重新同步,稍待片刻後就完成了加入參照 API。


  接續至專案的 Adapters 資料夾底下再新增一個 GroupRecycleAdapter Class

https://ithelp.ithome.com.tw/upload/images/20181110/20111944tmIeuItF8a.png

  在 GroupRecycleAdapter 中,編寫以下程式,接收的參數與先前的設計相同,不過因為這些參數其實都不會被更動到,所以依據 IDE 建議都修改宣告為 val。完成建構子後,於此類別內建立一個 inner class,名為 Holder (類別的命名需首字大寫)。這個內部類別要接收 itemView,並將值傳送到 RecyclerView.ViewHolder,詳細撰寫方式如下:

class GroupRecycleAdapter(val context: Context, val groups: List<FoodGroup>) {
   inner class Holder(itemView: View): RecyclerView.ViewHolder(itemView)
}

  完成內部類別 Holder 後,接著在上層的 GroupRecycleAdapter 後方加入繼承 : RecyclerView.Adapter 抽象類別,繼承時需要指定上方建立的內部類別 Holder,程式如下:

class GroupRecycleAdapter(val context: Context, val groups: List<FoodGroup>): RecyclerView.Adapter<GroupRecycleAdapter.Holder>()

  繼承抽象方法後,我們必須實作成員,如同 Day 25 章節,透過 Alt + Enter > Implement members,選取所有成員,產生如下三段方法:

https://ithelp.ithome.com.tw/upload/images/20181110/20111944EJfh0MoMTj.png

  先從簡單的部分下手,將 getItemCount 實作出來:

override fun getItemCount(): Int {
   return groups.count()
}

  內部類別 Holder 加入兩個屬性來做之前 findView 的工作,另外建立一個 bindGroup() 方法,此方法負責將清單項目的圖片及文字指定到兩個屬性物件上。

inner class Holder(itemView: View): RecyclerView.ViewHolder(itemView) {
val groupImage: ImageView = itemView.findViewById(R.id.groupImage)
val groupName: TextView = itemView.findViewById(R.id.groupName)

   fun bindGroup(group: FoodGroup, context: Context) {
       val resourceId = context.resources.getIdentifier(group.image, "drawable", context.packageName)
       groupImage.setImageResource(resourceId)
       groupName.text = group.name
       // 可多加此段程式以便追蹤
       Log.v("Test", group.name)
   }
}

  回到三個需要實作的成員,剛已解決了一個,剩下的 onBindViewHolder 呼叫剛才設計的內部 bindGroup 方法,將指定的清單項目及 context 傳入。

override fun onBindViewHolder(holder: Holder, position: Int) {
   holder.bindGroup(groups[position], context)
}

  第三個成員 onCreateViewHolder 要做的工作,是最早在普通版 Adapter 負責將自訂樣式讀取出來所使用的方法:

override fun onCreateViewHolder(parent: ViewGroup, position: Int): Holder {
   val view = LayoutInflater
       .from(context)
       .inflate(R.layout.group_list_item, parent, false)
  
   return Holder(view)
}

  完成了 Adapter 的設計後,需要返回至 MainActivity 修改一下,可以看到 Line: 27 已經變成錯誤狀態,原因是在 View 版面上我們還沒變更成新的 RecyclerView

https://ithelp.ithome.com.tw/upload/images/20181110/20111944Jn4qkenJfm.png

  切換到 activity_main.xml 中,將原本的 ListView 改成 android.support.v7.widget.RecyclerView ,如下圖所示:

https://ithelp.ithome.com.tw/upload/images/20181110/201119448EkHkDpiC4.png

  同時也能調整一下排版方式,將 layout 都設為依照約束條件,ID 的部分也能重新命名。

https://ithelp.ithome.com.tw/upload/images/20181110/20111944HCg5gFUoS6.png

  重新命名編輯後按下 Enter 會出現以下視窗,可以將所有用到此 ID 的參考同步變更為新的名稱。

https://ithelp.ithome.com.tw/upload/images/20181110/20111944JsfDcq9c9p.png


  還沒完成,最後一個步驟需要到 MainActivity,在指定 adapter 之後,要多加一行指定 layoutMagager,決定 View 的排列方式:

fun generateListView() {
   adapter = GroupRecycleAdapter(this, DataService.groups)
   groupRecyclerView.adapter = adapter
   groupRecyclerView.layoutManager = LinearLayoutManager(this)
}

  執行模擬機檢查一下!會發現小小的瑕疵,清單項目間格不見了,之前的設計方式失去效用,要修正這個問題須回到 group_list_item.xmlConstraintLayout 高度設為 160dpgroupImage 在之前的版面設計步驟已經設定過 150dp,所以相差的 10dp 就會成為間格距離。

https://ithelp.ithome.com.tw/upload/images/20181110/2011194477pX7lpE6v.png

  再次執行!讀者可以觀察 Logcat,會發現所有項目只會各執行一次讀取圖檔/名稱,捲軸的滑動效果也較順暢。下一章節會繼續介紹項目清單的功能,讓我們明天見。

https://ithelp.ithome.com.tw/upload/images/20181110/20111944rWWrL61Ccr.png


上一篇
Day 26. Android ListView - 2/2
下一篇
Day 28. Android RecyclerView - 2/2
系列文
Kotlin for Android30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言