简单列表实现
在app开发中列表肯定是最常见的样式,这里记录一下Android是如何使用RecyclerView创建动态列表的
类比一下 RecyclerView 相当于 iOS 中的 UITableView和UICollectionView
RecyclerView
RecyclerView 可以让您轻松高效地显示大量数据。您提供数据并定义每个列表项的外观,而 RecyclerView 库会根据需要动态创建元素。
顾名思义,RecyclerView 会回收这些单个的元素。当列表项滚动出屏幕时,RecyclerView 不会销毁其视图。相反,RecyclerView 会对屏幕上滚动的新列表项重用该视图。这种重用可以显著提高性能,改善应用响应能力并降低功耗。
RecyclerView 总的来说是列表元素的容器,然后复用View节省内容,提高性能。
RecyclerView 想要显示内容需要设置两个关键属性 layoutManager
和 adapter
// 获取 recyclerView
recyclerView = findViewById(R.id.content_recycleview)
// 设置布局方式
recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, true)
// 绑定 adapter
recyclerView.adapter = textAdapeter
LayoutManager
- LinearLayoutManager 线性布局,支持横向和纵向滑动,还可以翻转布局,翻转真的是适合做聊天室,因为翻转后布局的最后一条显示在屏幕的最下方。这一点iOS望尘莫及啊!
- GridLayoutManager 二维网格排列,这个和 iOS 的 UICollectionView 的排列就很像了,没啥可说的。
- StaggeredGridLayoutManager 和上面类似,但是同一列元素的高度可以不一样,不知道这个可不可以做瀑布流。
Mac Android Studio 连接 mumu 模拟器
RecyclerView.Adapter 和 RecyclerView.ViewHolder
Adapter 用 iOS 的话说就是 UITableView 的 dataSource 了
ViewHolder 持有 itemView, 也就是相当于给 Cell 包装了一层
public abstract static class Adapter<VH extends ViewHolder> {
...
}
public abstract static class ViewHolder {
@NonNull
public final View itemView;
...
public ViewHolder(@NonNull View itemView) {
if (itemView == null) {
throw new IllegalArgumentException("itemView may not be null");
}
this.itemView = itemView;
}
...
}
- 一个 RecyclerView 同时只对应一个 Adapter
- 自定义的 Adapter 继承的时候需要指定一个 ViewHolder
- ViewHolder 初始化需要传入 itemView
在看一下继承 Adapter 需要实现的方法
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
// 定义MyAdapter
class MyAdapter: RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
// 定义 ViewHolder
class MyViewHolder(view: View): RecyclerView.ViewHolder(view) {
}
// 需要在这里对ViewHolder实例化
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
// 先实例化一个 itemView
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.cell_text, parent, false)
// 在实例化 ViewHolder
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
// 这里就是可以根据 holder 获取 itemView
holder.itemView
// 然后就可以嘿嘿嘿,不用说了吧
}
override fun getItemCount(): Int {
// 返回显示的个数,这个不用说了吧
}
}
然后给 recyclerView 设置下布局,绑定下adapter OK了。
// 设置布局方式
recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, true)
// 绑定 adapter
recyclerView.adapter = MyAdapeter()
实现多种样式
实际应用中,列表中显示的内容不可能永远都是一种样式,那么多样式是怎么实现的那这里记录一下
方法1
根据 viewType 在 onCreateViewHolder 中返回不同的 View, 复用规则是根据 viewType 的值来的(盲猜一下应该是这样)
abstract class MyViewHolder(view: View): RecyclerView.ViewHolder(view) {
...
}
class MyTextViewHolder(view: View): MyViewHolder(view) {
...
}
class MyImageViewHolder(view: View): MyViewHolder(view) {
...
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = ...
val itemView2 = ...
// plan 1
if (viewType == 1) {
return MyTextViewHolder(itemView)
} else {
return MyImageViewHolder(itemView2)
}
// plan 2
if (viewType == 1) {
return MyTextViewHolder(itemView)
} else {
return MyTextViewHolder(itemView2)
}
}
override fun getItemViewType(position: Int): Int {
if (position < 10)
return 1
return 2
}
方法2 ConcatAdapter
implementation 'androidx.recyclerview:recyclerview:1.2.1'
ConcatAdapter 像iOS里面的 Section 概念
ConcatAdapter 可以将多个不同的 Adapter 当作一个个单独的 Section 处理
// 初始化adapter
val textAdapeter = MyAdapter()
val imageAdapter = MyAdapter2()
// 绑定 adapter
val dAdapter = ConcatAdapter(textAdapeter, imageAdapter)
recyclerView.adapter = dAdapter