EDIT: Wow, couldn't fix the issue all day, but moments after submitting, and trying to find some more code to place in the question, I found the issue, and fixed it. I will change the question.
FIX: viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
New Question: With the ViewPager working correctly with the tabs, I am having issues with it displaying the same content that was displayed before. The Content in Tabs A, B, C are displayed in Tab X, Y, Z, but I want it to be different content. Take note that all the Tabs use new Instances of the Same Fragment.
Old Question:
I have a support library TabLayout
that seems to work fairly good. On App load, it will load the tabs I want, allow scrolling, and changes to the correct Fragment.
I was placed under a restriction and need to modify my current implementation to switch out tabs and replace them with new tabs based on user interactions. When I did this, I started to run into issues.
On Start up Three tabs (A, B, C) are set to load with a new instance of the same Fragment (Just a list). They are displayed, and all three tabs are scrollable and display the correct information.
On User swap-tabs interaction - ISSUE The three tabs are removed and replaced with Two tabs (X, Y). They are set to new instances of the same Fragment from above. They are scrollable, but this is where the issues start.
- There are 3 tabs still displayed (A, B, C)
- I can only scroll between the first 2 tabs (A -> X, B -> Y).
- If I had added 4+ tabs (W, X, Y, Z), then I would be displayed with 3 tabs, but I would get an app crash on scroll to the last tab.
On user clicks support library's SearchView Here can happen anytime in my app. It will add an addition tab to the already displayed tabs. This always works and adds a new instance of the above Fragment.
Normal flow: 1. On SearchView click, it will add a new tab (Search) to the end of the current tabs. All previous tabs remain the same. 2. On SearchView close, it will remove all the tabs, and then add only the previous tabs. This works as expected.
If user performed swap-tabs interaction then clicked SearchView flow 1. The previous tabs (ie A, B, C) are removed and replaced with the new tabs (ie, X, Y) 2. A new tab will be added to the end of the new tabs (Search). 3. On SearchView close, it will remove all the tabs, and then add only the new Tabs (ie X, Y). This works as expected.
NOTE only when I click on the SearchView do my tabs display correctly. Otherwise, the wrong tabs are displayed on user swap-tabs interaction.
When debugging, I found out that this happens because ONLY when I click on the SearchView does that somehow trigger my Adapter's getPageTitle()
method. When the user performs a swap-tabs interaction, the getPageTitle()
method is NOT called, and that leds to the issues.
My only issue is that I hae not be able to find a solution to this issue. There are a lot of questions on here about similar issues, but none of them seem to work.
What I tried
adapter.notifyDataSetChanged();
after swap-tabs interactionsetAdapter(null); setAdapter(adapter);
return POSITION_NONE;
forceLayout()
,invalidate()
, etc...
Nothing seems to work right now, but the solution seems to have to getgetPageTitle()
called. Do that, and I should be good. The only issue is that I have failed everytime so far
Code
FragmentPagerAdapter
public class ViewPagerFragmentAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragments = new ArrayList<>(App.getNumberOfApiCalls());
private final List<String> tabTitles = new ArrayList<>(App.getNumberOfApiCalls());
public ViewPagerFragmentAdapter(final FragmentManager manager) { super(manager); }
public void addFragment(final Fragment fragment, final Downloadable tab) {
fragments.add(fragment);
tabTitles.add(tab.toString());
}
public void clearTabs() {
fragments.clear();
tabTitles.clear();
}
@Override
public int getItemPosition(Object item) {
int index = fragments.indexOf(item);
if (index == -1) return POSITION_NONE;
return index;
}
@Override
public Fragment getItem(final int position) { return fragments.get(position); }
@Override
public int getCount() { return fragments.size(); }
@Override
public CharSequence getPageTitle(final int position) {
return tabTitles.get(position);
}
}