ViewPager2+TabLayout点击序号>3的Tab时跳转到最后一页问题求助
ViewPager2 + TabLayout 点击跳转异常问题
我在实现ViewPager2 + TabLayout组合功能时遇到异常:相同逻辑的Java代码运行正常,但Kotlin代码中,点击序号大于3的Tab时,ViewPager2会直接跳转到最后一页;滑动ViewPager2可正常显示对应页面,点击第1、2、3个Tab也能正常跳转。在Adapter中添加日志后,发现点击时会依次打印所有位置的信息。
Adapter类代码
class ViewPager2Adapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) { private val fragmentList: ArrayList<Fragment> = ArrayList<Fragment>() override fun createFragment(position: Int): Fragment { Log.e("TAG",position.toString() ) return fragmentList[position] } fun addFragment(fragment: Fragment) { fragmentList.add(fragment) } override fun getItemCount(): Int { return fragmentList.size } override fun getItemViewType(position: Int): Int { return position } fun add(s: Fragment) { fragmentList.add(s) } }
ViewPager初始化代码
fun setupTabLayout() { val home = activity as HomeDash val myAdapter = ViewPager2Adapter(this.getChildFragmentManager() , this.lifecycle) var FragmentNameList:Array<String> myAdapter.addFragment(StatisticsFragment()) myAdapter.addFragment(ApprovalFragment()) myAdapter.addFragment(ProfessionalDetailsFragment()) myAdapter.addFragment(PersonalDetailsFragment()) myAdapter.addFragment(EducationalDetailsFragment()) myAdapter.addFragment(BankDetailsFragmnt()) myAdapter.addFragment(SalaryDetailsFragment()) myAdapter.addFragment(LoanFragment()) FragmentNameList = arrayOf( "Statistics", "Approval", "Professional Details", "Personal Details", "Educational Details", "Bank Details", "Salary Details", "Loan Details", ) viewbinding.tabPager.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL) viewbinding.tabPager.setAdapter(myAdapter) TabLayoutMediator(viewbinding.fragmentTabLayout, viewbinding.tabPager) { tab, position -> tab.text = FragmentNameList[position] //viewbinding.tabPager.setCurrentItem(position, false) }.attach() }
日志输出
2023-10-23 17:00:01.125 3752-3752 TAG gen.reporting_mvvm E 0 2023-10-23 17:00:02.534 3752-3752 TAG gen.reporting_mvvm E 1 2023-10-23 17:00:02.550 3752-3752 TAG gen.reporting_mvvm E On create 2023-10-23 17:00:02.876 3752-3764 System gen.reporting_mvvm W A resource failed to call close. 2023-10-23 17:00:02.916 3752-3752 RecyclerView gen.reporting_mvvm W No adapter attached; skipping layout 2023-10-23 17:00:03.183 3752-3752 RecyclerView gen.reporting_mvvm W No adapter attached; skipping layout 2023-10-23 17:00:03.187 3752-3752 View gen.reporting_mvvm D [ANR Warning]onLayout time too long, this =androidx.recyclerview.widget.RecyclerView{9f12e4b VFED..... ......ID 54,48-1026,1579 #7f0a00a1 app:id/RecyclerApproval}time =629 ms 2023-10-23 17:00:03.187 3752-3752 View gen.reporting_mvvm D [ANR Warning]onLayout time too long, this =androidx.constraintlayout.widget.ConstraintLayout{cdc028 V.E...... ......ID 0,0-1080,1611}time =630 ms 2023-10-23 17:00:03.187 3752-3752 View gen.reporting_mvvm D [ANR Warning]onLayout time too long, this =android.widget.FrameLayout{f173141 V.E...... ......ID 1080,0-2160,1611 #3}time =630 ms 2023-10-23 17:00:03.189 3752-3752 TAG gen.reporting_mvvm E 2 2023-10-23 17:00:04.067 3752-3752 Looper gen.reporting_mvvm W PerfMonitor longMsg : seq=1367 plan=17:00:02.518 late=12ms wall=1533ms h=android.view.Choreographer$FrameHandler c=android.view.Choreographer$FrameDisplayEventReceiver procState=-1 2023-10-23 17:00:04.067 3752-3752 Looper gen.reporting_mvvm W PerfMonitor doFrame : time=1533ms vsyncFrame=0 latency=12ms procState=-1 historyMsgCount=2 2023-10-23 17:00:04.071 3752-3752 Choreographer gen.reporting_mvvm I Skipped 138 frames! The application may be doing too much work on its main thread. 2023-10-23 17:00:04.158 3752-3752 TAG gen.reporting_mvvm E 3 2023-10-23 17:00:04.620 3752-3752 TAG gen.reporting_mvvm E 4 2023-10-23 17:00:05.554 3752-3752 TAG gen.reporting_mvvm E 5 2023-10-23 17:00:06.027 3752-3752 TAG gen.reporting_mvvm E 6 2023-10-23 17:00:06.872 3752-3752 TAG gen.reporting_mvvm E 7
问题原因与解决方法
原因
问题出在重写的getItemViewType方法:返回position作为ViewType后,FragmentStateAdapter的内部回收重建逻辑被打乱,当页面数量超过ViewPager2默认的预加载阈值后,TabLayoutMediator的位置映射关系出现异常,导致点击后跳转错误。
解决步骤
- 删除
getItemViewType重写代码:FragmentStateAdapter默认已实现合适的ViewType管理逻辑,无需手动返回position。 - 清理Adapter冗余代码:移除重复的
add方法,统一使用addFragment。
修改后的Adapter代码:
class ViewPager2Adapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) { private val fragmentList = ArrayList<Fragment>() override fun createFragment(position: Int): Fragment { Log.e("TAG", position.toString()) return fragmentList[position] } fun addFragment(fragment: Fragment) { fragmentList.add(fragment) } override fun getItemCount(): Int { return fragmentList.size } }
- 额外优化建议:日志显示主线程存在卡顿和ANR警告,建议给Fragment添加懒加载逻辑,避免一次性在主线程创建大量Fragment导致性能问题。
内容的提问来源于stack exchange,提问作者Paras Rajora
相关产品推荐
相关产品推荐

