找回密码
 立即注册
首页 业界区 业界 多类型适配器

多类型适配器

诉称 2025-7-1 20:51:34
优势:
1、适配器通用,无论针对什么列表样式
2、viewholder分离,业务逻辑拆分到具体的item
3、复用性扩展性更强
首先看viewholder,没有复杂的业务逻辑
1.gif
2.gif
  1. open class BaseViewHolder(val mBinding: ViewBinding) : RecyclerView.ViewHolder(mBinding.root) {
  2.     fun setClick(clickRoot: View, clickListener: ((Int) -> Unit)?) {
  3.         AnimatorUtil.pressView(
  4.             clickRoot, Runnable { clickListener?.invoke(bindingAdapterPosition) }
  5.         )
  6.         clickRoot.setOnClickListener { clickListener?.invoke(bindingAdapterPosition) }
  7.     }
  8. }
复制代码
View Code适配器想要通用,就不能有业务逻辑,需要解耦
3.gif
4.gif
  1. import android.view.ViewGroup
  2. import androidx.recyclerview.widget.RecyclerView
  3. import com.zeekr.screensaver.home.holder.ScreenMainHolderFactory
  4. /**
  5. * @author liuzhen
  6. * 多类型适配器
  7. * */
  8. open class BaseAdapter : RecyclerView.Adapter<BaseViewHolder>() {
  9.     var itemClickListener: ((Int) -> Unit)? = null
  10.     private val list = mutableListOf<IBaseItem>()
  11.     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
  12.         ScreenMainHolderFactory.onCreateViewHolder(parent, viewType, itemClickListener)
  13.     override fun getItemCount() = list.size
  14.     fun getItem(position: Int) = list[position]
  15.     fun getItems() = list
  16.     override fun getItemViewType(position: Int) = getItem(position).itemType.value
  17.     override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
  18.         getItem(position).bind(holder, position)
  19.     }
  20.     override fun onBindViewHolder(holder: BaseViewHolder, position: Int, payloads: List) {
  21.         getItem(position).bind(holder, position, payloads)
  22.     }
  23.     fun setItems(newList: MutableList<IBaseItem>) {
  24.         list.clear()
  25.         list.addAll(newList)
  26.     }
  27. }
复制代码
View Code可以看到,简化了viewholder跟adapter,那么逻辑去哪了,在bean的上面加了一层item,可以把这个bean看成是item
首先需要定义一个接口,从adapter中看到所有数据类型都是 IBaseItem
5.gif
6.gif
  1. import com.zeekr.screensaver.home.holder.ViewType
  2. interface IBaseItem {
  3.     val itemType: ViewType
  4.     var isShowShimmer: Boolean
  5.     fun bind(holder: BaseViewHolder, position: Int, payloads: List? = null)
  6. }
复制代码
View Code多类型安全,最好使用枚举
7.gif
8.gif
  1. enum class ViewType(val value: Int) {
  2.     TITLE(1), ITEM(2), BANNER(3), ME_ADD(4), ME_ITEM(5);
  3.     companion object {
  4.         fun fromValue(value: Int) = values().firstOrNull { it.value == value }
  5.     }
  6. }
复制代码
View Code统一管理ViewHolder
9.gif
10.gif
  1. object ScreenMainHolderFactory {
  2.     @JvmStatic
  3.     fun onCreateViewHolder(
  4.         parent: ViewGroup,
  5.         viewType: Int,
  6.         itemClickListener: ((Int) -> Unit)?
  7.     ): BaseViewHolder {
  8.         val inflater = LayoutInflater.from(parent.context)
  9.         return when (ViewType.fromValue(viewType)) {
  10.             ViewType.TITLE -> BaseViewHolder(
  11.                 ItemMainSubTitleBinding.inflate(inflater, parent, false)
  12.             )
  13.             ViewType.BANNER -> BaseViewHolder(
  14.                 ItemMainBannerBinding.inflate(inflater, parent, false)
  15.             )
  16.             ViewType.ME_ADD -> {
  17.                 val binding = ItemMeAddBinding.inflate(inflater, parent, false)
  18.                 BaseViewHolder(binding).also {
  19.                     it.setClick(binding.root, itemClickListener)
  20.                 }
  21.             }
  22.             ViewType.ME_ITEM -> {
  23.                 val binding = ItemMePhotoCardBinding.inflate(inflater, parent, false)
  24.                 BaseViewHolder(binding).also {
  25.                     it.setClick(binding.clRoot, itemClickListener)
  26.                 }
  27.             }
  28.             else -> {
  29.                 val binding = ItemMainPhotoCardBinding.inflate(inflater, parent, false)
  30.                 BaseViewHolder(binding).also {
  31.                     it.setClick(binding.clRoot, itemClickListener)
  32.                 }
  33.             }
  34.         }
  35.     }
  36. }
复制代码
View Codeviewholder中的逻辑解耦到了item类中,先定义接口IBaseItem 
11.gif
12.gif
  1. import com.zeekr.screensaver.home.holder.ViewType
  2. interface IBaseItem {
  3.     val itemType: ViewType
  4.     var isShowShimmer: Boolean
  5.     fun bind(holder: BaseViewHolder, position: Int, payloads: List? = null)
  6. }
复制代码
View Code结合viewbinding,实现接口
13.gif
14.gif
  1. import androidx.viewbinding.ViewBinding
  2. import com.zeekr.screensaver.home.holder.ViewType
  3. abstract class BaseBindItem<V : ViewBinding>(val viewType: ViewType) : IBaseItem {
  4.     override val itemType = viewType
  5.     override var isShowShimmer = true
  6.     abstract fun onBindViewHolder(position: Int, mBinding: V)
  7.     open fun onBindViewHolder(position: Int, mBinding: V, payloads: List) {}
  8.     override fun bind(holder: BaseViewHolder, position: Int, payloads: List?) {
  9.         @Suppress("UNCHECKED_CAST")
  10.         val binding = holder.mBinding as V
  11.         if (payloads.isNullOrEmpty()) {
  12.             onBindViewHolder(position, binding)
  13.         } else {
  14.             onBindViewHolder(position, binding, payloads)
  15.         }
  16.     }
  17. }
复制代码
View Code这样,已经根据多类型封装好了,只要根据视图,创建类型item,直接将viewholder的业务转移到了item中
比如新建一个banner类型
15.gif
16.gif
  1. class MainBannerItem(
  2.     private val list: List<ScreenItemBean>
  3. ) : BaseBindItem<ItemMainBannerBinding>(ViewType.BANNER) {
  4.     override fun onBindViewHolder(position: Int, mBinding: ItemMainBannerBinding) {
  5.         mBinding.apply {
  6.             if (isShowShimmer) bannerPage.onClear()
  7.             bannerPage.start(list, bannerCarousel)
  8.             groupContent.isInvisible = isShowShimmer
  9.             shimmerView.isVisible = isShowShimmer
  10.             shimmerView.setImageResource(R.drawable.icon_main_banner_loading)
  11.             if (isShowShimmer) shimmerView.startShimmer() else shimmerView.stopShimmer()
  12.         }
  13.     }
  14. }
复制代码
View Code在新建一个卡片类型
17.gif
18.gif
  1. class MePhotoCardItem(var bean: ScreenItemBean, private val currentId: Int) :
  2.     BaseBindItem<ItemMePhotoCardBinding>(ViewType.ME_ITEM) {
  3.     override fun onBindViewHolder(position: Int, mBinding: ItemMePhotoCardBinding) {
  4.         mBinding.apply {
  5.             tvTitle.text = bean.getTitle()
  6.             tvTitle.setPXTextSize(R.dimen.common_sp_32)
  7.             tvTitle.setExtTextColor(R.color.main_card_title_color)
  8.             if (bean.isCustom()) {
  9.                 GlideCacheUtils.getInstance(root.context).glideLoadPicturePath(
  10.                     bean.customBitmap, ivPhoto
  11.                 )
  12.             } else {
  13.                 GlideCacheUtils.getInstance(root.context).loadHomeItemUrl(bean.getUrl(), ivPhoto)
  14.             }
  15.             linSuite.isVisible = bean.isCabin()
  16.             linSuite.setExtBackground(R.drawable.shape_item_main_card_suite)
  17.             ivPhotoSuite.setExtSrc(R.drawable.icon_main_card_photo_suite)
  18.             tvSuiteTitle.setPXTextSize(R.dimen.common_sp_20)
  19.             tvSuiteTitle.setExtTextColor(R.color.main_card_title_suite_color)
  20.             groupMask.isInvisible = bean.getTitle()?.isEmpty() == true
  21.             ivCheck.isVisible = bean.isCheck(currentId)
  22.             clRoot.isInvisible = isShowShimmer
  23.             shimmerView.isVisible = isShowShimmer
  24.             shimmerView.setImageResource(R.drawable.icon_main_photo_card_loading)
  25.             if (isShowShimmer) shimmerView.startShimmer() else shimmerView.stopShimmer()
  26.         }
  27.     }
  28. }
复制代码
View Code可以观察到,它其实充当bean的角色,又是独立的item
在创建一个特殊的自定义功能卡片类型
19.gif
20.gif
  1. class MeAddItem(@MeAddItemType val type: Int) : BaseBindItem<ItemMeAddBinding>(ViewType.ME_ADD) {
  2.     companion object {
  3.         const val TYPE_AI = 0
  4.         const val TYPE_PHOTO = 1
  5.         @IntDef(TYPE_AI, TYPE_PHOTO)
  6.         @Retention(AnnotationRetention.SOURCE)
  7.         annotation class MeAddItemType
  8.     }
  9.     override fun onBindViewHolder(position: Int, mBinding: ItemMeAddBinding) {
  10.         mBinding.apply {
  11.             when (type) {
  12.                 TYPE_AI -> ivPhoto.setImageResource(R.drawable.icon_me_card_ai)
  13.                 else -> ivPhoto.setImageResource(R.drawable.icon_me_card_photo)
  14.             }
  15.         }
  16.     }
  17. }
复制代码
View Code随意扩展
而adapter的使用更加简单
21.gif
22.gif
  1. private val mAdapter = BaseAdapter()
  2. init {
  3.         val inflater = LayoutInflater.from(context)
  4.         mBinding = LayoutScreenRecyclerBinding.inflate(inflater, this, true).apply {
  5.             recyclerView.adapter = mAdapter
  6.             recyclerView.layoutManager = ScreenMainGridManager(mAdapter, context)
  7.             recyclerView.addItemDecoration(ScreenMainItemDecoration())
  8.         }
  9. }
  10.     private fun loadData() {
  11.         LogUtil.d(tag, "loadData")
  12.         lifecycleScope.launch(Dispatchers.Main) {
  13.             val items = withContext(Dispatchers.IO) {
  14.                 val data = LocalResourceManager.getHistorySuits()
  15.                 val items = mutableListOf<IBaseItem>()
  16.                 items.add(MeAddItem(MeAddItem.TYPE_AI))
  17.                 items.add(MeAddItem(MeAddItem.TYPE_PHOTO))
  18.                 items.add(MainSubTitleItem(MainSubTitleItem.HISTORY))
  19.                 data.map { items.add(MePhotoCardItem(ScreenItemBean(suit = it), currentId)) }
  20.                 items
  21.             }
  22.             setItems(items)
  23.         }
  24.     }
  25.     private fun loadData(list: List<TestBean>) {
  26.         mBinding.root.isVisible = true
  27.         val items = mutableListOf<IBaseItem>()
  28.         list.forEach {
  29.             items.addAll(it.map { MainPhotoCardItem(it) })
  30.         }
  31.         mAdapter.setItems(items)
  32.     }
复制代码
View Code只要是基于RecyclerView,都不需要另外创建adapter,只需要新建你的类型视图,而adapter跟viewholder完全不用修改,一站式复用
局部刷新
23.gif
24.gif
  1. override fun onBindViewHolder(position: Int, mBinding: ItemMainPhotoCardBinding) {
  2.         mBinding.apply {
  3.             tvTitle.text = bean.getTitle()
  4.             updateProgress(this)
  5.         }
  6.     }
  7.     private fun updateProgress(mBinding: ItemMainPhotoCardBinding) {
  8.         mBinding.apply {
  9.             ivDown.isVisible = !bean.isLocal && bean.progress <= 0
  10.             progress.isVisible = bean.progress > 0
  11.             progress.setProgressValue(bean.progress)
  12.         }
  13.     }
  14.     override fun onBindViewHolder(
  15.         position: Int,
  16.         mBinding: ItemMainPhotoCardBinding,
  17.         payloads: List
  18.     ) {
  19.         when (payloads[0]) {
  20.             PAYLOAD_PROGRESS_TYPE -> updateProgress(mBinding)
  21.         }
  22.     }
复制代码
View Code自定义Decoration
25.gif
26.gif
  1. class ScreenMainItemDecoration : RecyclerView.ItemDecoration() {
  2.     private val bottomSideMargin =
  3.         Utils.getApp().resources.getDimensionPixelOffset(R.dimen.common_dp_128)
  4.     override fun getItemOffsets(
  5.         outRect: Rect,
  6.         view: View,
  7.         parent: RecyclerView,
  8.         state: RecyclerView.State
  9.     ) {
  10.         val position = parent.getChildAdapterPosition(view)
  11.         val count = parent.adapter?.itemCount ?: 0
  12.         val isLastItem = position == count - 1
  13.         outRect.bottom = if (isLastItem) bottomSideMargin else 0
  14.     }
  15. }
复制代码
View Code 

来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除

相关推荐

您需要登录后才可以回帖 登录 | 立即注册