【问题标题】:Issue on implementing ViewPager2 with FragmentStateAdapter使用 FragmentStateAdapter 实现 ViewPager2 的问题
【发布时间】:2021-04-02 12:01:40
【问题描述】:

我来自 ViewPager 和 FragmentPagerAdapter,它有一个非常简单的实现,像这样。

public class FragmentAdapters extends FragmentPagerAdapter {

    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public FragmentAdapters(@NonNull FragmentManager fm, int behavior) {
        super(fm, behavior);
    }

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

}

父片段

adapter = new FragmentAdapters(getChildFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);

        CoinsFragment coinsFragment = new AssetFragment();
        NewsFragment newsFragment = new NewsFragment();
        VideoFragment videoFragment = new VideoFragment();

        adapter.addFragment(coinsFragment, getString(R.string.asset));
        adapter.addFragment(newsFragment, getString(R.string.news));
        adapter.addFragment(videoFragment, getString(R.string.videos));

        mViewPager.setAdapter(adapter);
        mViewPager.setOffscreenPageLimit(2);

Android 建议远离 ViewPager 并弃用心爱的 FragmentPagerAdapter,现在我正在尝试将 ViewPager2 与 FragmentStateAdapter 一起使用,但在其工作方式方面存在很多困惑和困难。

这是我的实现

class AppFragmentAdapter(private val fragmentList: MutableList<Pair<String, Fragment>>, fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {

private val pageIds = fragmentList.map { fragmentList.hashCode().toLong() }

override fun getItemCount(): Int = fragmentList.size

override fun createFragment(position: Int): Fragment = when (position) {
    0 -> {
        Log.wtf("WTF", fragmentList[position].first + " " + position)
        fragmentList[position].second
    }
    1 -> {
        Log.wtf("WTF", fragmentList[position].first + " " + position)
        fragmentList[position].second
    }
    2 -> {
        Log.wtf("WTF", fragmentList[position].first + " " + position)
        fragmentList[position].second
    }
    else -> throw IllegalStateException("Invalid adapter position")
}

fun getFragmentName(position: Int) = fragmentList[position].first

//    fun addFragment(fragment: Pair<String, Fragment>) {
//        fragmentList.add(fragment)
//        notifyItemInserted(fragmentList.size)
//        notifyItemRangeChanged(fragmentList.size, fragmentList.size)
//        notifyDataSetChanged()
//    }
//
//    fun removeFragment(position: Int) {
//        fragmentList.removeAt(position)
//        notifyItemRemoved(position)
//        notifyItemRangeChanged(fragmentList.size, fragmentList.size)
//        notifyDataSetChanged()
//    }

    override fun getItemId(position: Int): Long {
        return pageIds[position] // Make sure notifyDataSetChanged() works
    }

    override fun containsItem(itemId: Long): Boolean {
        return pageIds.contains(itemId)
    }

}

通常我们可以在createFragment 方法中立即从列表中返回片段,但存在巨大的混乱,所以我尝试扩展它以查看发生了什么。令我惊讶的是,当createFragment 被调用一 (1) 次时,而不是由getItemCount 返回的可用片段数量,因此只显示了一个片段,这让我所谓的第一个片段 (AssetFragment) 更加混乱被放在最后一个位置,前两个片段是空屏幕,我不知道这两个片段是从哪里来的。

父片段

val fragmentList : MutableList<Pair<String,Fragment>> = ArrayList()

        fragmentList.add(Pair(getString(R.string.assets), AssetFragment.newInstance()))
        fragmentList.add(Pair(getString(R.string.news), NewsFragment.newInstance()))
        fragmentList.add(Pair(getString(R.string.videos), VideosFragment.newInstance()))

        val adapter = AppFragmentAdapter(fragmentList, requireActivity())
        viewPager.adapter = adapter
        viewPager.offscreenPageLimit = 2

这就是我的 Fragment 的样子,基本上没什么特别的

class AssetFragment : BaseFragment() {

    companion object {
        fun newInstance() = AssetFragment()
    }

    private lateinit var viewModel: AssetViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.asset_fragment, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProvider(this).get(AssetViewModel::class.java)
        // TODO: Use the ViewModel
    }

}

有人可以告诉我这种荒谬的行为是什么吗? 附言我试图用getItemCount 做一些日志,它被调用了 23 次只是为了一个 3 Fragment?

【问题讨论】:

    标签: java android kotlin android-viewpager2 fragmentstateadapter


    【解决方案1】:

    这很奇怪,因为覆盖

    getItemId()
    containsItem()
    

    在使用我拥有的不同类型的 Fragments 类时只会产生这种不良行为。

    最后我只需要一个像这样的简单FragmentStateAdapter

    class AppFragmentAdapter(private val fragmentList: MutableList<Pair<String, Fragment>>, fragment: Fragment) : FragmentStateAdapter(fragment) {
    
    //    private var pageIds = fragmentList.map { fragmentList.hashCode().toLong() }
    
        override fun getItemCount(): Int = fragmentList.size
    
        override fun createFragment(position: Int): Fragment {
            return fragmentList[position].second
        }
    
    //    override fun getItemId(position: Int): Long = pageIds[position] // Make sure notifyDataSetChanged() works
    
    //    override fun containsItem(itemId: Long): Boolean = pageIds.contains(itemId)
    
        fun getFragmentName(position: Int) = fragmentList[position].first
    
        fun addFragment(fragment: Pair<String, Fragment>) {
            fragmentList.add(fragment)
            notifyDataSetChanged()
        }
    
        fun removeFragment(position: Int) {
            fragmentList.removeAt(position)
            notifyDataSetChanged()
        }
    
    }
    

    太糟糕了,我正在寻找一个关于如何使 ViewPager2 动态化的直接答案,而没有先尝试我能想到的最简单的方法。 SO上的许多回答指出,在ViewPager2上添加或删除片段时需要覆盖getItemId()containsItem(),这让人头疼了将近2天。感觉被背叛了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-16
      • 2020-06-12
      • 1970-01-01
      • 1970-01-01
      • 2019-08-03
      • 1970-01-01
      相关资源
      最近更新 更多