FragmentPagerAdapter is not removing items (Fragments) correctly

前端 未结 9 1211
别跟我提以往
别跟我提以往 2021-01-30 01:30

I have implemented the FragmentPagerAdapter and and using a List to hold all fragments for my ViewPager to display. On

9条回答
  •  礼貌的吻别
    2021-01-30 02:12

    I had a situation similar to yours. I recently needed to add and remove Fragments from the ViewPager. In the first mode, I have Fragments 0, 1, and 2 and in the second mode I have Fragments 0 and 3. I want Fragment 0 to be same for both modes and hold over information.

    All I needed to do was override FragmentPagerAdapter.getItemId to make sure that I returned a unique number for each different Fragment - the default is to return "position". I also had to set the adapter in the ViewPager again - a new instance will work but I set it back to the same instance. Setting the adapter results in the ViewPager removing all the views and trying to add them again.

    However, the trick is that the adapter only calls getItem when it wants to instantiate the Fragment - not every time it shows it. This is because they are cached and looks them up by the "position" returned by getItemId.

    Imagine you have three Fragments (0, 1 and 2) and you want to remove "1". If you return "position" for getItemId then removing Fragment 1 will not work because when you try to show Fragment 2 after deleting Fragment 1 the pager/adapter will think it's already got the Fragment for that "position" and will continue to display Fragment 1.

    FYI: I tried notifyDataSetChanged instead of setting the adapter but it didn't work for me.

    First, the getItemId override example and what I did for my getItem:

    public class SectionsPagerAdapter extends FragmentPagerAdapter
    {
        ...
    
        @Override
        public long getItemId(int position)
        {
            // Mode 1 uses Fragments 0, 1 and 2. Mode 2 uses Fragments 0 and 3
            if ( mode == 2 && position == 1 )
                return 3;
            return position;
        }
    
        @Override
        public Fragment getItem(int position)
        {
            if ( mode == 1 )
            {
                switch (position)
                {
                    case 0:
                        return <>;
                    case 1:
                        return <>;
                    case 2:
                        return <>;
                }
            }
            else    // Mode 2
            {
                switch (position)
                {
                    case 0:
                        return <>;
                    case 1:
                        return <>;
                }
            }
            return null;
        }
    }
    

    Now the change of mode:

    private void modeChanged(int newMode)
    {
        if ( newMode == mode )
            return;
    
        mode = newMode;
    
        // Calling mSectionsPagerAdapter.notifyDataSetChanged() is not enough here
        mViewPager.setAdapter(mSectionsPagerAdapter);
    }
    

提交回复
热议问题