今天做一個這樣的練習,可以通過畫面滾動的方式來瀏覽 15 張圖片以及對應的描述。
類似 iOS 開發中會用到的 UITableView / UICollectionView。
類似於 UICollectionView,只是使用起來不太一樣。
我們需要為 RecyclerView 提供一個 Adapter,並且給他設定一個 layoutManager。
在 MainActivity 中,看起來就是下面這樣而已,而像是多少數量、將資料呈現在 View 上等動作,都是交給 Adapter。
這裡的 Adapter 有點像 UICollectionView 的 Datasource & Delegate 方法提供者。
imageListRecyclerView.layoutManager = LinearLayoutManager(this)
val adapter = ImageListAdapter(imageList)
imageListRecyclerView.adapter = adapter
我們建立了一個 ImageListAdapter ,定義 ImageListAdapter 可以:
在 Android 中,各種資源的都會有一個對應的 ID 來進行存取,比如 R.drawable.img_1 這不像 iOS 中可以直接根據圖片名稱來進行存取。
下面在 Adapter 中,我們通過圖片名稱轉換成對應的 Resource ID (這樣做是因為一開始沒注意到 R.drawable.img_1 是 Int)
class ImageListAdapter(val feedModelItems: List<ImageModel>) : RecyclerView.Adapter<ImageListAdapter.ViewHolder>() {
// 入口
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// 指定了 layout
val view = LayoutInflater.from(parent.context).inflate(R.layout.layout_image_list_item, parent, false)
return ViewHolder(view)
}
// 綁定資料
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
holder?.bindImageModel( feedModelItems[position] )
}
// 返回數目
override fun getItemCount(): Int {
return feedModelItems.size
}
// view
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
fun bindImageModel(imageModel: ImageModel){
// set description
itemView.descriptionTextView.text = imageModel.description
// set image
when(imageModel.imageName){
"img_1" -> itemView.imageView.setImageResource(R.drawable.img_1)
"img_2" -> itemView.imageView.setImageResource(R.drawable.img_2)
"img_3" -> itemView.imageView.setImageResource(R.drawable.img_3)
"img_4" -> itemView.imageView.setImageResource(R.drawable.img_4)
"img_5" -> itemView.imageView.setImageResource(R.drawable.img_5)
"img_6" -> itemView.imageView.setImageResource(R.drawable.img_6)
"img_7" -> itemView.imageView.setImageResource(R.drawable.img_7)
"img_8" -> itemView.imageView.setImageResource(R.drawable.img_8)
"img_9" -> itemView.imageView.setImageResource(R.drawable.img_9)
"img_10" -> itemView.imageView.setImageResource(R.drawable.img_10)
"img_11" -> itemView.imageView.setImageResource(R.drawable.img_11)
"img_12" -> itemView.imageView.setImageResource(R.drawable.img_12)
"img_13" -> itemView.imageView.setImageResource(R.drawable.img_13)
"img_14" -> itemView.imageView.setImageResource(R.drawable.img_14)
"img_15" -> itemView.imageView.setImageResource(R.drawable.img_15)
}
}
}
}
就像 iOS 的 UICollectionViewCell 一樣,我們想要為 RecyclerView 的 Item 定義自己想要的 Layout。
比如說,我們想要每一個 item 上面是一張長條的圖片,下面是一些描述。
我們在 Layout 中建立一個 layout_image_list_item.xml 的檔案,用來定義上面的 Layout。
這裡和 iOS 中的 Storyboard 很不一樣的是,
雖然我們定義了一個 item 設定圖片高度 220dp 描述背景 40dp ,合起來260dp。
但實際上在 Design 介面中看到的還是一個完整的手機樣式,不像 iOS 的 Storyboard 只會顯示 cell 的大小。
我一開始以為這樣就可以了,但結果到手機上跑的時候,一開始只有看到一個 Item,
結果發現一個 Item 就像 Design 介面一樣占滿了整個畫面。
後來就去 Text 下手動修改了高度。
<android.support.constraint.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="160dp">
// ...
</android.support.constraint.ConstraintLayout>
這次我想要為資料建立兩個 Model。
ImageModel 用來定義一張圖片資料會有圖片名、描述兩個字段。
ImageListModel 用來定義一個 list 當中存的會是 ImageModel類型的資料。
在 Android Studio 中,在 Project 中建立 Folder 會有分類,我這裡為 Model 建立了一個叫做 Package 的 Folder
在 Android Studio 中,在 Project 中建立 Folder 會有分類,我這裡為 Model 建立了一個叫做 Package 的 Folder
在 iOS 開發過程中,我通常用 Struct 來定義 Model,但 Github 上逛了一下,看到通常用 data class 來定義
ImageModel
data class ImageModel ( val imageName: String, val description: String)
ImageListModel
data class ImageListModel(val data: List<ImageModel>)
通過 model 封裝數據後傳值
fun bindImageModel(imageModel: ImageModel){
itemView.descriptionTextView.text = imageModel.description
}
這邊用 Adapter 舉一個例子,這邊定義了 ListAdapter() 並且會回傳一個 ViewHolder。
class ListAdapter(): RecyclerView.Adapter<ImageListAdapter.ViewHolder>() { ... }
然後我們在 ListAdapter() 這邊按下,Option + Enter(Mac 系統),就會看到 Implement Members 的選項。
接著就可以選擇想要補全的方法。
Android Studio 就會幫我們都補上了。
class ListAdapter(): RecyclerView.Adapter<ImageListAdapter.ViewHolder>() {
override fun onBindViewHolder(holder: ImageListAdapter.ViewHolder?, position: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ImageListAdapter.ViewHolder {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getItemCount(): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}