为啥 ViewPager 无限循环不起作用?

Posted

技术标签:

【中文标题】为啥 ViewPager 无限循环不起作用?【英文标题】:Why isn't the ViewPager infinite loop not working?为什么 ViewPager 无限循环不起作用? 【发布时间】:2021-10-28 05:48:47 【问题描述】:

所以我有这个轮播项目,它通过 ViewPager 以轮播方式显示一组图片。在达到这一点之前,我已经通过手动将图片和信息放入可变列表来测试 ViewPager 的功能,并且它有效。现在使用来自 API 的信息来做这件事,它似乎不再起作用了。对于控制循环的实际功能,我也没有改变任何东西。

适配器

class CarouselItemAdapter internal constructor (info: MutableList<CarouselItem>,viewPager2: ViewPager2) : ListAdapter<CarouselItem,CarouselItemAdapter.CarouselViewHolder>(DiffCallback) 
    private val viewPager2: ViewPager2
    private var info: MutableList<CarouselItem>

    companion object DiffCallback : DiffUtil.ItemCallback<CarouselItem>() 
        override fun areItemsTheSame(oldItem: CarouselItem, newItem: CarouselItem): Boolean 
            return oldItem.id == newItem.id
        

        override fun areContentsTheSame(oldItem: CarouselItem, newItem: CarouselItem): Boolean 
            return oldItem == newItem
        

    

    init 
        this.viewPager2 = viewPager2
        this.info = info

    

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): CarouselViewHolder 
       return CarouselViewHolder(CustomContainerBinding.inflate(
           LayoutInflater.from(parent.context),
           parent, false))
    

    override fun onBindViewHolder(holder: CarouselViewHolder, position: Int) 
        holder.bind(getItem(position))
        if (position == info.size - 2) 
            viewPager2.post(runnable)
        
    


    class CarouselViewHolder(private val binding: CustomContainerBinding) : RecyclerView.ViewHolder(binding.root)
        fun bind(item: CarouselItem)
            binding.parts = item
            binding.executePendingBindings()
        
    


    private val runnable = Runnable 
        info.addAll(info)
        notifyDataSetChanged()
    

    fun addAll(items: MutableList<CarouselItem>) 
        info = items
        notifyDataSetChanged()
    



片段

class MainFragment: Fragment() 

//    private lateinit var manager: RecyclerView.LayoutManager

    private lateinit var viewModel: MainFragmentViewModel
    private lateinit var viewPager: ViewPager2
    private var counter: Int = 0
    private var pageChangeCallback: ViewPager2.OnPageChangeCallback? = null


    var data: MutableList<CarouselItem> = ArrayList()


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 
        val binding: MainFragmentBinding = DataBindingUtil.inflate(
            inflater,
            R.layout.main_fragment,
            container, false)

        val mainViewModelFactory = MainFragmentViewModelFactory(requireActivity().application)
        viewModel = ViewModelProvider(this, mainViewModelFactory).get(MainFragmentViewModel::class.java)

        binding.viewModel = viewModel

        viewPager = binding.imageSlider

//
//        val data: MutableList<CarouselItem> = ArrayList()
//        data.add(CarouselItem(1, "bcw_65", "First"))
//        data.add(CarouselItem(2, "bcw_66", "Second"))
//        data.add(CarouselItem(3, "bcw_67", "Third"))
//        data.add(CarouselItem(4, "bcw_68", "Fourth"))
//        data.add(CarouselItem(5, "bcw_69", "Fifth"))
//        data.add(CarouselItem(6, "bcw_70", "Sixth"))
//        data.add(CarouselItem(2, "bcw_71", "Seventh"))

        val adapter = CarouselItemAdapter(data, viewPager)

        viewPager.adapter = adapter

        viewModel.picInfo.observe(viewLifecycleOwner, Observer 
            adapter.addAll(data)
            adapter.submitList(it)
        )




        viewPager.clipToPadding = false
        viewPager.clipChildren = false
        viewPager.offscreenPageLimit = 3
        viewPager.getChildAt(0).overScrollMode = RecyclerView.OVER_SCROLL_NEVER

        val compositePageTransformer = CompositePageTransformer()
        compositePageTransformer.addTransformer(MarginPageTransformer(30))
        compositePageTransformer.addTransformer  page, position ->
            val r = 1 - abs(position)
            page.scaleY = 0.85f + r * 0.25f
        

        viewPager.setPageTransformer(compositePageTransformer)

        createChannel(
            getString(R.string.carousel_notification_id),
            getString(R.string.app_name)

        )


        val notificationManager = ContextCompat.getSystemService(
            requireContext(),
            NotificationManager::class.java,
        ) as NotificationManager




        //Used to count the number of swipes bing called
        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() 
            override fun onPageSelected(position: Int) 
                counter++
                binding.counterView.text = counter.toString()
                if((counter % 20) == 0) 
                    notificationManager.sendNotification(
                        requireContext().getText(R.string.swipe_description).toString(), requireContext())
                
            
        .also  pageChangeCallback = it )



        return binding.root
    

    //Needed to destroy the pageChangeCallback
    override fun onDestroyView() 
        super.onDestroyView()
        viewPager.unregisterOnPageChangeCallback(pageChangeCallback!!)
        pageChangeCallback = null
    

    private fun createChannel (channelID: String, channelName: String)
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
            val notificationChannel = NotificationChannel(
                channelID,
                channelName,
                NotificationManager.IMPORTANCE_HIGH
            )

            notificationChannel.enableLights(true)
            notificationChannel.lightColor = Color.WHITE
            notificationChannel.enableVibration(true)
            notificationChannel.description = getString(R.string.swipe_description)

            val notificationManager = requireActivity().getSystemService(
                NotificationManager::class.java
            )

            notificationManager.createNotificationChannel(notificationChannel)
        
    



我很确定这是一个简单的原因,我只是没有看到它。任何想法都将受到欢迎。

【问题讨论】:

“它似乎不再起作用”,你能说得更具体一点吗?它会使您的应用程序崩溃吗?它不显示任何图像吗?图像是否以错误的顺序显示? 该应用程序确实运行并且它也显示图像。它只是不像我最初做的那样循环为轮播。只显示我请求的 X 张图片。 【参考方案1】:

您使用空的Arraylist 初始化适配器并且适配器中的 Runnable 始终使用空列表 info 最好使用适配器内的项目列表作为单一事实来源:

viewModel.picInfo.observe(viewLifecycleOwner, Observer 
            // dont need to call notifyDatasetChanges() as diffutil will do the work
            val newList = adapter.info.plus(it)
            adapter.submitList(newList)  adapter.info = newList 
        )

【讨论】:

我可能会误解您所解释的内容。我创建了一个 items 变量,它被分配为 MutableList。然后我能够以与上面相同的方式对其进行编码,并让它通过图片轮播两次(两次查看 15 张图片)。我的做法是你说的吗? 我写错了,你可以在适配器内部使用变量info(通过改变它的可见性)。我更正了答案。 好的。我仍然得到与我之前所说的相同的结果,并且轮播不是从一开始就开始,而是在中间的某个地方。

以上是关于为啥 ViewPager 无限循环不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

骑士之旅 - 导致无限循环,我不知道为啥

Android无限循环与自动播放ViewPager的简单实现(广告栏)

自定义完美的ViewPager 真正无限循环的轮播图

ViewPager,实现真正的无限循环(定时+手动)

Android 一个无限循环滚动的卡片式ViewPager

CSS3 无限动画循环在谷歌浏览器 31.0.1650.57 中不起作用