优势:
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) {
- 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? = 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 Codeviewholder中的逻辑解耦到了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? = 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) {}
- override fun bind(holder: BaseViewHolder, position: Int, payloads: List?) {
- @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
- ) {
- 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
来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除 |