美文网首页Android开发
RecyclerView: 忘掉Adapter, LayoutM

RecyclerView: 忘掉Adapter, LayoutM

作者: DoKar | 来源:发表于2021-03-04 12:17 被阅读0次
LazyRecycler Demo

传统的RecyclerView用法:

  • 继承RecyclerView.Adapter实现getItemCount()createViewHolder(), onBindViewHolder()等方法。
  • 继承RecyclerView.ViewHolder实现数据绑定等。
  • 添加点击事件的接口。
  • 如果需要DiffUtil,还得实现自己的ItemCallback,然后整合进Adapter。
  • 选择LayoutManger,并调用recyclerView.setLayoutManager
  • 实例化Adapter,并调用recyclerView.setAdapter
  • 实现点击事件的接口。
  • 更新数据时调用adapter.notifyDataChanged()等方法,使用ListAdapter时调用submitList

这个过程相比于要被替代的ListView来说不仅没有简化,还变得更复杂了。猜测这也是RecylerView虽然强大,但却一直没有彻底代替ListView等老组件的原因之一。

后来Jetpack Compose出来后,看到LazyColumn的写法如此简洁:

LazyColumn {
    items(itemsList) {
        Text("Item is $it")
    }

    item {
        Text("Single item")
    }

    itemsIndexed(itemsIndexedList) { index, item ->
        Text("Item at index $index is $item")
    }
}

当时也并没有什么想法。。。后来看到了sqaure/recycler库配置RecyclerView的方式:

val recycler = Recycler.create<ItemType>(context, id = R.id.myrecycler) {
    ...
    row<I, S, V> {
      forItemsWhere { subitem -> ...boolean... }
      create(R.layout.my_layout) {
        // you can get references to sub-elements inside view
        val subView = view.findViewById(...)
        bind { subItem ->
          // assign values from subItem to view or sub-elements
        }
      }
      ...more row options...
    }
}

完全省略了定义Adapter的步骤,但感觉仍然还是有些复杂。那时萌生了一个想法:能不能把LazyColumn那套定义方式带给RecyclerView呢?于是就有了下面这部分。

LazyRecycler

LazyRecycler使用和LazyColumn相似的方式来写RecylcerView,把AdapterLayoutManagerDiffUtil点击事件等定义全部放到一个代码块中:

LazyRecycler(recyclerView, spanCount = 3) {
    // 多种view type支持
    item(R.layout.header, Unit) {}

    items(listOfNews) { binding: ItemNewsBinding, news ->
        // 绑定
    }.clicks { view, item ->
        // 点击事件
    }.spanSize { position ->
        if (position % 3 == 0) 3 else 1
    }.differ {
        areItemsTheSame { oldItem, newItem ->
            oldItem.id == newItem.id
        }
        areContentsTheSame { oldItem, newItem ->
            oldItem.title == newItem.title && ...
        }
    }
    
    item(R.layout.footer, Unit) {}
}

相比cycler的layout id还支持ViewBinding,不用在bind外边findViewById了。
为了体验更加接近Compose的LazyColumn,还支持Flow, LiveData, RxJava的Observable作为数据源:

val source: Flow<List<Item>> = ...
...
items(source) { ... }

调用recycler.observeChanges()观察数据变化,自动更新Adapter。

使用

implementation 'io.github.dokar3:lazyrecycler:0.1.1'

// Flow支持
implementation 'io.github.dokar3:lazyrecycler-flow:0.1.1'
// LiveData支持
implementation 'io.github.dokar3:lazyrecycler-livedata:0.1.1'
// RxJava支持
implementation 'io.github.dokar3:lazyrecycler-rxjava3:0.1.1'

创建LazyRecycler

// 传入RecyclerView
LazyRecycler(recyclerView) {
    ...
}

// attachTo()
val lazyRecycler = LazyRecycler {
    ...
}
lazyRecycler.attachTo(recyclerView)

创建item / items:

item(R.layout.header, Unit) { view -> 
    val title: TextView = view.findViewById(...)
    bind { 
        title.text = ...
    }
}

item<HeaderBinding> { ... }

items(R.layout.item_news, newsList) { view ->
    val title: TextView = view.findViewById(...)
    val cover: ImageView = view.findViewById(...)
    ...
    bind { news ->
        title.text = news.title
        cover.load(news.cover)
        ...
    }
}

items(newsList) { binding: ItemNewsBinding, news -> 
    binding.title.text = news.title
    binding.cover.load(news.cover)
    ...
}

各类配置:

items(...) {
    ...
}.clicks { view, news ->
    // 点击事件
}.longClicks { view, news ->
    // 长按事件
    true
}.spanSize { position
    // SpanSizeLookup.getSpanSize的映射
    1
}.differ {
    // DiffUtil.ItemCallback的映射
    areItemsTheSame { old, new -> ... }
    areContentsTheSame { old, new -> ... }
}.subSection(sectionBreakingNews) { news, position ->
    // 同数据源不同item type
    news.priority == ...
}
...

更多使用请查看Github:
https://github.com/dokar3/LazyRecycler

相关链接:

相关文章

网友评论

    本文标题:RecyclerView: 忘掉Adapter, LayoutM

    本文链接:https://www.haomeiwen.com/subject/wtnhqltx.html