iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 26
0

  清單的排版會受到主版與子版兩個 xml 的排版影響,在 group_list_item.xml 中可以設計成左右滿版貼齊邊緣,並將高度固定,此外若需要各項目之間留有間隔,可以設定 MargnBottom,如下圖所示:

https://ithelp.ithome.com.tw/upload/images/20181109/20111944XyDfz7xV9U.png

  主版的設計也提供參考圖一,另外 ListView 預設會有外框線,如果不需要外框可以在 ListView 設定屬性 divider,指定 @Null 值,如圖二。

https://ithelp.ithome.com.tw/upload/images/20181109/20111944iiW78eETCR.png
https://ithelp.ithome.com.tw/upload/images/20181109/201119449H7PeYib9W.png

  搞定!執行模擬查看辛苦的成果吧,作者有將資料來源多增加幾筆,超出高度後會有捲軸出現。

https://ithelp.ithome.com.tw/upload/images/20181109/20111944hgJrICD8OF.png


  雖然達成了目標,但是回頭看看程式其實隱藏著一個問題,回到 GroupAdapter 可以看到這一段程式被 IDE 提醒,建議要使用 Holder 設計模式,否則每次呼叫 getView() 方法的時候都要重複執行不必要的部分,會影響到介面操作順暢度,讀者應該也可以感受到在滾動捲軸時會卡頓,可以試著在 Line: 35 加入 Log 查看程式如何運作。

https://ithelp.ithome.com.tw/upload/images/20181109/201119444aKhFTmpCk.png

  從記錄中發現每次滾動捲軸都會重複進入 getView(),接著我們著手將程式碼調整一下,看是否能減少效能負荷,在 GroupAdapter 下方加入 ViewHolder 類別,並宣告可為空值的屬性承接兩個元件。

private class ViewHolder{
   var groupImage: ImageView? = null
   var groupText: TextView? = null
}

  在 getView() 一開始的地方,將原本的 groupView 物件變數抽離出來,同時也新增一個 holder 的物件變數,型態為剛剛新增的 ViewHolder,如下所示。

val groupView: View
val holder: ViewHolder

  接著使用 getView() 函式上接收的 convertView 物件參數,進行重複利用判斷,該參數初始值會是 null,因此透過這個判斷條件,可加上條件判斷後是否要產生 groupView 物件實作。

  到這邊順手將 .inflate() 的參數調整成傳入三個變數,第一個不變,第二個由於原本使用 null,IDE 會建議不要這樣使用,因此改傳入第二及第三 parent, false 兩個參數)。

  再來輪到實作 holder = ViewHolder(),將原本的 .findViewById() 結果交給 hodler 的屬性,接著將 holder 交給 groupView.tag 屬性。另一方面設計 else 程式段將 holdergroupView 進行重複利用 (Recycle)

if (convertView == null) {
   groupView = LayoutInflater
               .from(context)
               .inflate(R.layout.group_list_item, parent, false)
   holder = ViewHolder()
   holder.groupImage = groupView.findViewById(R.id.groupImage)
   holder.groupText = groupView.findViewById(R.id.groupName)
   groupView.tag = holder
} else {
   holder = convertView.tag as ViewHolder
   groupView = convertView
}

  接續在下方的程式碼,原本的 groupImagegroupText 前方加入 hodler.(因為我們已經將兩個元件移到 holder 物件內),再來處理 Nullable 安全性問題,後方需多加上 ? 符號,完成如下:

// 取得資料
var group = getItem(position)

// 變更圖片
var imgRid = context.resources
           .getIdentifier(group.image, "drawable", context.packageName)
holder.groupImage?.setImageResource(imgRid)

// 變更文字
holder.groupText?.text = group.name

return groupView

  完整的程式段:

https://ithelp.ithome.com.tw/upload/images/20181109/20111944v0YV4uSn8F.png

  最後就可以執行程式看看結果,順暢程度有改善嗎?讀者可以加入三段 Log,分別在 if、else 及 return 之前,這時回到 Studio 上觀察 Logcat,會發現雖然 if...else 這段有效能上的改善,但程式還是不斷的在 setImage 與更新 text,應該有更好的方法來處理,下一章節要示範使用 RecyclerView 來解決這個問題,我們明天見!


上一篇
Day 25. Android ListView - 1/2
下一篇
Day 27. Android RecyclerView - 1/2
系列文
Kotlin for Android30

尚未有邦友留言

立即登入留言