iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 25
1

  今天開始的課程為資料清單,建立一個新的專案,專案的選擇與先前課程相同,並新增三類 Package 資料夾,分別命名為:ControllersModelsServices,在 Models 中建立 Class 檔案 (可命名為 FoodGroup),其中宣告資料類別 FoodGroup 如下,存放群組名稱與圖檔名稱:

data class FoodGroup(val name: String, val image: String)

  另外於 Services 新增一個 Object 類型,命名為 DataService,用來當作資料來源,內容如下:

https://ithelp.ithome.com.tw/upload/images/20181108/20111944xMNcfV0Xxy.png

object DataService {
   val groups = listOf(
       FoodGroup("五穀", "img_various_grains"),
       FoodGroup("蔬菜", "img_vegetables"),
       FoodGroup("水果", "img_fruits")
   )
}

  下一步,切換至 activity_main.xml,在 Legacy 中將 ListView 加入到版面上。

https://ithelp.ithome.com.tw/upload/images/20181108/20111944VmkY76ajdJ.png

  回到 MainActivity 首先加入全域變數 adapter,這裡的 lateinit 關鍵字代表宣告時不先初始化 ,若沒有這個關鍵字就必須要實作或給予預設值。

lateinit var adapter: ArrayAdapter<FoodGroup>

   接著實作 ArrayAdapter,前兩個參數都是固定值,第三個參數用上面設計的 DataService.groups 當作資料來源,再將整個 adapter 指定到版面上的 ListView

fun generateListView() {
   adapter = ArrayAdapter(this,
       android.R.layout.simple_list_item_1,
       DataService.groups)
   groupListView.adapter = adapter
}

  最後在 onCreate 呼叫上面設計的函式。

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)
   // 產生資料清單
   generateListView()
}

  實際執行的效果,雖然還不是最終想要的,不過雛型有成功的列出資料清單:

https://ithelp.ithome.com.tw/upload/images/20181108/20111944tIFGTFFZ90.png


  接著處理清單顯示的樣式,先在專案總管 res 中新增一個版面資源檔,命名為 group_list_item.xml,在此設計要顯示在清單的個別項目樣式,由於清單是由多個項目組成,所以只要設計單一樣式讓所有項目共用即可,版面配置使用 ImageView 顯示圖檔、TextView 顯示名稱。

https://ithelp.ithome.com.tw/upload/images/20181108/20111944zUk0xWNz5W.png

  為了後續使用方便,請將 imageViewtextView 更改獨特的識別 Id,可以命為 groupImage、groupName。緊接著在專案新增 Adapter (轉接器) 資料夾,加入一個 Kotlin Class: GroupAdapter 並且使用 BaseAdapter() 介面,這時將游標移動到紅底部分,按下 Alt + Enter 選擇實作成員。

https://ithelp.ithome.com.tw/upload/images/20181108/20111944w1Es57u3nM.png

  此時會跳出一個視窗,使用鍵盤 Shift 將所有成員全選 (或直接按 Ctrl + A),再點選 OK 即可。

https://ithelp.ithome.com.tw/upload/images/20181108/20111944kbVicxrqpl.png

  若操作正確就會顯示以下畫面:

https://ithelp.ithome.com.tw/upload/images/20181108/20111944I6cDXWHJSC.png


  這裡建立一個自訂的轉接器 (Adapter) 目的是在取代剛才使用的 ArrayAdapter,藉由自訂轉接器可以彈性調整設計清單的呈現方式。轉接器是 Data (DB) - Adapter - View 中,擔任資料與 View 之間的轉接角色。

  因為最終我們要取代下面這段程式:

   adapter = ArrayAdapter(this,
       android.R.layout.simple_list_item_1,
       DataService.groups)

  所以要在 GroupAdapter 中實作相同工作,須於建構子上加入兩個參數接收,分別是 ContextList

class GroupAdapter(var context: Context, var groups: List<FoodGroup>): BaseAdapter()

  實作成員後會產生四個方法,目前都還是 TODO 尚未實際實作的狀態,讓我們先從簡單的部分 getItem、getItemId、getCount 下手。

  getItem() 是在傳入索引位置時,希望回傳清單內的項目,所以很簡單的以下列方式實作,並將原本預設的 Any 回傳型態改成 FoodGroup

override fun getItem(position: Int): FoodGroup{
   return groups[position]
}

  getItemId() 我們用不到,可以直接回傳 0

override fun getItemId(position: Int): Long {
   return 0
}

  getCount() 要取得清單的項目數,以 count() 方式取得並回傳即可。

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

  最複雜的地方在第一個 getView,這裡要加入大量程式。使用 LayoutInflater 取得先前建立好的個別項目 layout,記得在下 R 時要選擇自己專案的,才能夠繼續往下找到 group_list_item.xml

https://ithelp.ithome.com.tw/upload/images/20181108/201119447plsnNSRij.png

  接著完成下列程式碼,為了避免版面雜亂,請參考註解的說明。

// 首先取出剛剛設計的個別項目 layout,參數 null 是為了指定根目錄
val groupView = LayoutInflater
               .from(context)
               .inflate(R.layout.group_list_item, null)

// 取得項目樣式中的兩個元件,若有紅字可用 Alt + Enter > Import
var groupImage: ImageView = groupView.findViewById(R.id.groupImage)
var groupText: TextView = groupView.findViewById(R.id.groupName)

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

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

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

// 回傳 View
return groupView

  完成自訂的轉接器後,就能回到 MainActivity,將有使用到 ArrayAdapter 的部分取代掉:

lateinit var adapter: GroupAdapter

   adapter = GroupAdapter(this, DataService.groups)

   groupListView.adapter = adapter

  搞定一切,可以執行模擬機看看效果,版面的呈現可能會很奇怪,下一章節會來處理排版的設計,我們明天見!


上一篇
Day 24. Android Activity 物件傳遞 - 6/6
下一篇
Day 26. Android ListView - 2/2
系列文
Kotlin for Android30

尚未有邦友留言

立即登入留言