【问题标题】:Android: ViewPager2 setting the starting page on creation not workingAndroid:ViewPager2 在创建时设置起始页不起作用
【发布时间】:2026-01-25 17:10:02
【问题描述】:

我有一个包含两个片段的 viewpager,以及一个 viewModel(存储在父活动中),它保存了当前可见页面索引的记录。

这里是父片段的设置:

 override fun setUp() {
    super.setUp()
    titles = arrayOf(R.string.providers, R.string.create_provider)
    fragments = arrayOf(ProvidersListFragment(), CreateProviderFragment())
    pagerAdapter = BaseFragmentAdapter(this, fragments = fragments)
}

override fun setUpViews() {
    super.setUpViews()
    binding.page.adapter = pagerAdapter
    TabLayoutMediator(binding.tabs, binding.page) { tab, position ->
        tab.text = getString(titles[position])
    }.attach()
    binding.page.currentItem = viewModel.currentPage.value!!
}

override fun setUpObservers() {
    super.setUpObservers()
    viewModel.currentPage.observe(viewLifecycleOwner, {
        Log.d(TAG, "setUpObservers: it = $it")
        if (it != binding.page.currentItem)
            binding.page.currentItem = it
    })
}

上面的3个方法在onResume()内部调用。

ViewModel 将记录保存到当前索引,如下所示: var currentPage = MutableLiveData<Int>().apply { value = 1 }

从技术上讲,起始页应该是索引 1,我的情况是 TabMediator 显示为好像选择了第 1 页,但布局显示第 0 页的内容(甚至没有完全加载)。

这就是它所显示的:

这就是它应该显示的内容:

这是布局 0:

关于这种行为的任何想法以及如何避免它?

【问题讨论】:

    标签: android android-fragments android-viewpager2


    【解决方案1】:

    我遇到了同样的问题,并注意到它与设置页面太早(在创建任何片段之前)有关。所以我需要等待适配器完成创建片段。不幸的是,适配器完成加载或创建片段时似乎没有回调方法,所以我创建了这个子类

    inner class TabAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
    
        private var finished = false
    
        // other stuff
    
        override fun onBindViewHolder(holder: FragmentViewHolder, position: Int, payloads: MutableList<Any>) {
            super.onBindViewHolder(holder, position, payloads)
            if (!finished) {
                finished = true
                // TODO set starting page
            }
        }
    }
    

    这不是一个真正干净的解决方案,但它为我完成了工作。

    【讨论】:

    • 我会对其进行测试,并尝试使其更通用和可重用!谢谢!
    【解决方案2】:

    我通过创建导航操作将我直接带到所需的片段页面来解决此问题。而且由于这是一种解决方法而不是解决方案,因此它不能 100% 符合我的需要,当我导航到片段时,它被创建为单个片段而不是页面。

    我还在具有图像选择器功能的片段中做了其他事情。 问题是当我在第 2 页(创建片段)并尝试选择图像时,当我完成选择时,我会发现自己在第 1 页。 我所做的如下:

    在持有寻呼机的片段上:

        override fun setUpObservers() {
            // this method is called inside onResume()
        super.setUpObservers()
        if (binding.page.currentItem != viewModel.page)
            binding.page.currentItem = viewModel.page
        }
    

    关于其他片段:

        override fun onResume() {
        super.onResume()
        productsViewModel.page = 0 //the other fragment set this to 1
         }
    

    viewmodel 是使用主 Activity 的商店创建的:

    private val productsViewModel: ProductsViewModel by viewModels(this::requireActivity)
    

    希望这可以帮助任何有同样问题的人。

    【讨论】: