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