美文网首页
简单使用ConcatAdapter实现自定义Banner

简单使用ConcatAdapter实现自定义Banner

作者: 梧叶已秋声 | 来源:发表于2022-11-10 12:52 被阅读0次

banner部分的实现,主要参考这篇:
ConcatAdapter

使用ConcatAdapter可以使recyclerview具有多个adapter。在HeaderAdapter中添加Banner。HeaderAdapter里面再嵌套一个BannerAdapter。
最终结果如下所示


新建HeaderAdapter。

class HeaderAdapter(private var adapter: BannerAdapter) :
    RecyclerView.Adapter<HeaderAdapter.ViewHolder>() {

    class ViewHolder(private val binding: ItemHeaderBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(adapter: BannerAdapter) {
            val context = binding.root.context
            binding.headerList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
            binding.headerList.adapter = adapter
        }
    }

    private lateinit var binding: ItemHeaderBinding

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        binding = ItemHeaderBinding.inflate(layoutInflater, parent, false)
        isAbleScroll = true
        // 确保一次只能滑动一个数据,停止的时候图片的位置正确
        val snapHelper = PagerSnapHelper()
        snapHelper.attachToRecyclerView(binding.headerList)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(adapter)
    }

    override fun getItemCount(): Int = 1

    var isAbleScroll: Boolean = false
    fun smoothScrollToPosition(position: Int){
        if (isAbleScroll){
            binding.headerList.smoothScrollToPosition(position)
        }
    }
}

新建BannerAdapter和BannerViewHolder。

class BannerAdapter(var bannerList: List<Banner>): RecyclerView.Adapter< BannerViewHolder> () {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BannerViewHolder {
        return BannerViewHolder(
            ItemImageBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false,
            )
        )
    }

    override fun onBindViewHolder(holder: BannerViewHolder, position: Int) {
        // 通过 getItem 获取数据
        if (bannerList.size == 0){
            return
        }
        val banner = bannerList.get(position % bannerList.size)
        banner.let { holder.bind(it) }

    }


    override fun getItemCount(): Int {
        // return Int.MAX_VALUE
        if (bannerList.size == 0){
            return 0
        }
        return  Integer.MAX_VALUE
    }
}
class BannerViewHolder(private val binding: ItemImageBinding)
    : RecyclerView.ViewHolder(binding.root){

    fun bind(banner: Banner) {
        Glide.with(itemView)
            .load(banner.imagePath)
            .into(binding.itemImage)
    }
}

初始化adapter,然后配置为RecyclerView的adapter,使用协程实现滑动的定时任务。

// WanAndroidViewModel
    private val _bannerListStateFlow = MutableStateFlow<List<Banner>>(ArrayList())

    val bannerListStateFlow: StateFlow<List<Banner>> = _bannerListStateFlow

    fun updateBannerList() {
        // 更新  value 数据
        viewModelScope.launch {
            _bannerListStateFlow.value = repository.getBannerFlow()
                .catch { throwable ->
                    // Catch exceptions in all down stream flow
                    // Any error occurs after this catch operator
                    // will not be caught here
                    println(throwable)
                }
                .stateIn(viewModelScope)
                .value
        }
    }
// MainActivity

    private val bannerAdapter = BannerAdapter(ArrayList<Banner>())
    private val headerAdapter = HeaderAdapter(bannerAdapter)
    private val concatAdapter = ConcatAdapter(headerAdapter,articleAdapter)

        // 为RecyclerView配置adapter
        binding.recyclerview.adapter = concatAdapter
        viewModel.updateBannerList()
...

        lifecycleScope.launch {
            // We repeat on the STARTED lifecycle because an Activity may be PAUSED
            // but still visible on the screen, for example in a multi window app
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.bannerListStateFlow.collect{ value ->
                    // 更新 list
                    bannerAdapter.bannerList = value
                    Log.d(TAG," bannerList size = ${bannerAdapter.bannerList.size}")
                    //数据改变刷新视图
                    bannerAdapter.notifyDataSetChanged()

                }
            }
        }

        // 设置 banner 无限循环滑动
        // 使用 launchWhenResumed 能保证 使得息屏后 不执行定时任务
        lifecycleScope.launchWhenResumed {  //onPause 的时候会暂停.
            Log.d(TAG,"inner launchWhenResumed")
            var counter = 0
            repeat(Int.MAX_VALUE){
                delay(3000L)
                if (bannerAdapter.bannerList.size > 0){
                    val position = ++counter % bannerAdapter.bannerList.size
                    Log.d(TAG,"currentIndex = $counter bannerListSize = ${bannerAdapter.bannerList.size} position = $position")
                    headerAdapter.smoothScrollToPosition(position)
                }

            }
        }

本文代码地址:
https://github.com/VIVILL/SimpleDemo/tree/main/RecyclerviewDemo

参考链接:
RecyclerView ConcatAdapter
ConcatAdapter
WanJetpack

相关文章

网友评论

      本文标题:简单使用ConcatAdapter实现自定义Banner

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