使用Kotlin實作RecyclerView及RecyclerView的優點
前言:
說起RecyclerView,其實他已經出生很久,在2014的I/O大會就推出了,我認為google有意要讓他取代傳統的ListView,而這裡要跟大家介紹他的實作方法,以及和ListView不同的優勢。
內文:
在iOS必學元件列表裡面,有一個叫做UITableView,與其在Android相對應的就是ListView了,但其實UITableView有容易實作的reuse cell機制,而ListView沒有。不過現在有能自動回收,並且實作起來更方便的RecyclerView,而且基礎的寫法跟ListView很像,以下是RecyclerView的基本架構:
1.先拉個RecyclerView進來,並賦予他id
2.RecyclerView也是使用Adapter來串接資料,所以要新增一個繼承RecyclerView.Adapter<ViewHolder>的類別
另外,需要新增一個類別繼承RecyclerView.ViewHolder,其內部需定義Cell內用到的元件
class TestAdaper : RecyclerView.Adapter<TestAdaper.ViewHolder> {
private var context:Context
constructor(context: Context) : super() {
this.context = context
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
}
override fun getItemCount(): Int {
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
}
class ViewHolder : RecyclerView.ViewHolder {
constructor(itemView: View) : super(itemView)
}
}
3. 新增一個Layout來定義Cell的長相
4.將需要用的元件都定義在ViewHolder內,並請在變數前面加上lateinit,否則沒有初始化會出現編譯錯誤
class ViewHolder : RecyclerView.ViewHolder {
lateinit var nameTextView:TextView
lateinit var imageView:ImageView
lateinit var videoBtn:ImageView
constructor(itemView: View) : super(itemView)
}
5. 新增一個簡單的Model來定義資料內容
class TestModel {
var name:String
var imageUrl:String
var videoUrl:String
constructor(name: String, imageUrl: String, videoUrl: String) {
this.name = name
this.imageUrl = imageUrl
this.videoUrl = videoUrl
}
}
6.有了Cell跟Model,就可以在Adapter內做對應的顯示,另外,我這裡使用Glide來處理圖片,詳細請到他的網站看看
private var data:Array<TestModel>
constructor(context: Context, data: Array<TestModel>) : super() {
this.context = context
this.data = data
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val cell = LayoutInflater.from(context).inflate(R.layout.view_cell, parent, false)
val viewHolder = ViewHolder(cell)
cell.layoutParams.height = 300
viewHolder.imageView = cell.findViewById(R.id.imageView)
viewHolder.nameTextView = cell.findViewById(R.id.nameTextView)
viewHolder.videoBtn = cell.findViewById(R.id.videoBtn)
return viewHolder
}
override fun getItemCount(): Int {
return data.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val model = data[position]
Glide.with(context).load(model.imageUrl).into(holder.imageView)
holder.nameTextView.setText(model.name)
holder.videoBtn.setOnClickListener {
AlertDialog.Builder(context).setMessage(model.videoUrl).setCancelable(true).create().show()
}
}
7.在Activity將Adapter初始化,並且放進資料,再指定給RecyclerView,
而這裡有個與ListView不同的地方是,RecyclerView需要一個LayoutManager來定義有關排版方面的需求,
若有特別需要也可以寫一個繼承LayoutManager的類別來實作,這裡用最基本的LinearLayoutManager來示範
private fun initView(){
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
val linearLayoutManager = LinearLayoutManager(this)
val testAdapter = TestAdaper(this, array)
recyclerView.layoutManager = linearLayoutManager
recyclerView.adapter = testAdapter
}
畫面結果就會這樣呈現
RecyclerView的優點:
1.可以利用LayoutManager輕鬆地處理排版,例如需要將表格的滾動方式改成橫向,只需要加入一行程式
linearLayoutManager.orientation = RecyclerView.HORIZONTAL
2.在ListView中,資料有更新之後,可以呼叫一個方法來更新版面,而RecyclerView除了這點,還支援部份更新
findViewById<Button>(R.id.updateButton).setOnClickListener({
updateLastModel()
testAdapter.notifyItemChanged(array.size - 1)
})
private fun updateLastModel(){
val model = array.last()
model.name = "UNO"
model.imageUrl = "https://store-images.s-microsoft.com/image/apps.64833.67582047191807640.1f6942f5-d7bc-46df-a9db-2fa15b28dfdf.7d799b05-0ec4-4758-92ac-c4152b49db91"
model.videoUrl = "UNO的教學影片"
}
按下按鈕就可以達到部分更新的效果
3. RecyclerView會自動 Reuse Cell,如果在Adapter內Create跟Bind的地方加上Log,可以發現上下滾動之後,都不會進去Create的方法了
另外還有內建簡單的動畫,加入HeaderView&FooterView,OnItemTouchListener等等許多優點,這裡就不一一說明
總結:
RecyclerView 比起ListView定義了更嚴謹的ViewHolder,也需要另外用 LayoutManager來定義其版面種類,
但也更方便實作較複雜的排版,SDK也內建Grid、StaggeredGrid等LayoutManager,這些常見的版面,
效能上也提升不少,對大量資料呈現的App會是很好用的元件。