Among most of the TabLayout examples I’ve seen, all tabs had one class for all tabs. How to technically create TabLayout with tabs, each with its own separate class?

I also ask you to make a comment to the decision, because in all the lessons that I saw, there is a catastrophic lack of clarification, and in the documentation, I feel there are many unnecessary details that are completely incomprehensible how to apply in practice (and here is an example from the documentation, where the integration of TabLayout and ViewPager mockingly written 2 short paragraphs).

Base code:

MainActivity.java

 public class MainActivity extends AppCompatActivity { private Toolbar toolbar; private ViewPager viewPager; @Override protected void onCreate(Bundle savedInstanceState) { setTheme(R.style.AppDefault); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initToolbar(); initTabs(); } protected void initToolbar() { ... } protected void initTabs(){ viewPager = (ViewPager) findViewById(R.id.viewPager); TabsFragmentAdapter adapter = new TabsFragmentAdapter(getSupportFragmentManager()); viewPager.setAdapter(adapter); TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout); tabLayout.setupWithViewPager(viewPager); // Здесь показвыает предупреждение о возможном вылете // Method Invocation SetIcon can produce NullPointerException // tabLayout.getTabAt(0).setIcon(R.drawable.ic_menu_tabone); // tabLayout.getTabAt(1).setIcon(R.drawable.ic_menu_tabtwo); // ... } } 

Adapter

 public class TabsFragmentAdapter extends FragmentPagerAdapter { private Map<Integer, Fragment> tabs; // Ключ - номер вкладки, значение - экземпляр фрагмента. // Конкретно в данной задаче в табах только иконки. public TabsFragmentAdapter(FragmentManager fm) { super(fm); } @Override public CharSequence getPageTitle(int position){ return fragmentTitles.get(position); } 

From now on, I don’t know what to do (the task is to display 4 tabs with icons without text). I used to do it as shown below and it worked, but in this question the getInstance() method, which was previously declared in the tab class, was rejected (I don’t argue that there were grounds for that).

  public CharSequence getPageTitle(int position){ return tabs.get(position).getTitle(); } @Override public Fragment getItem(int position) { return tabs.get(position); } @Override public int getCount() { return tabs.size(); } private void initTabsMap(Context context){ tabs = new HashMap<>(); tabs.put(0, TabOneFragment.getInstance(context)); tabs.put(1, TabTwoFragment.getInstance(context)); tabs.put(2, TabThreeFragment.getInstance(context)); tabs.put(3, TabFourFragment.getInstance(context)); } } 

Tab example

 public class TabOne extends Fragment { private static final int LAYOUT = R.layout.tab_one; public static OneTabFragment newInstance(int page){ Bundle args = new Bundle(); OneTabFragment fragment = new OneTabFragment(); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(LAYOUT, container, false); dBHandler = new dBHandler(getActivity()); BasicActivity activity = (BasicActivity)getActivity(); return view; } @Override public void onResume() { super.onResume(); // формирую отображение на основе данных из БД именно здесь, т. к. после первого прохода onCreate() // идёт onResume() } } 

By the way, I pointed out that in tabs there are images without captions only so that you do not create extra arrays in the answer if they are not needed, and of course pictures instead of captions are not the main thing in this matter.

  • I read your question a couple of times and I still don’t understand what you want, what your problem is and what your code is about. Try to identify the problem more clearly and briefly - YuriySPb
  • The problem is that I could not make a tabbed application, with a separate class for each tab. The reason is the lack of understanding of the concept of software binding of TabLayout, Fragment and ViewPager. I want to show me the technically correct way to do this, but not so that all tabs have the same class. I gave the code so that the respondents did not have to write it from scratch (although it may be easier for someone from scratch, but not for everyone). - Gleb
  • The most incomprehensible thing in your question: “for each tab is a separate class” - this is absolutely incomprehensible. Try to clarify - YuriySPb
  • Suppose we have the classes FragmentOne , FragmentTwo , FragmentThree and so on; each of which displays the contents of the fragment (as shown in the last block of code). Then according to the plan, when you click on the first tab, the contents of FragmentOne should be displayed, on the second - FragmentTwo and so on. - Bokov Gleb
  • Those. All week while your question remains unanswered under the classes, did you mean only fragments? And in fact, you already have a separate fragment for each tab in a separate class? And the question is actually how to remove the argument from the method? Especially because you were told a week ago how to do this in the previous question? - Yuriy SPb

2 answers 2

If you know in advance that you will have only 4 tabs and you have ready-made fragments for them, then inherit your adapter from the FragmentStatePagerAdapter , that is, do something like this in the adapter:

 public class MyPageAdapter extends FragmentStatePagerAdapter { public MyPageAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int pos) { Fragment fragment = null; switch (pos) { case 0: fragment = new TabOneFragment(); break; case 1: fragment = new TabTwoFragment(); break; case 2: fragment = new TabThreeFragment(); break; case 3: fragment = new TabFourFragment(); break; } return fragment; } @Override public int getCount() { return 4; } } 

Well, in your activity:

 protected void initTabs(){ viewPager = (ViewPager) findViewById(R.id.viewPager); MyPageAdapter adapter = new MyPageAdapter(getSupportFragmentManager()); viewPager.setAdapter(adapter); TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout); tabLayout.setupWithViewPager(viewPager); // установите иконки на табы tabLayout.getTabAt(0).setIcon(R.drawable.first_tab_icon); tabLayout.getTabAt(1).setIcon(R.drawable.second_tab_icon); tabLayout.getTabAt(2).setIcon(R.drawable.three_tab_icon); tabLayout.getTabAt(3).setIcon(R.drawable.four_tab_icon); // Здесь показвыает предупреждение о возможном вылете // Method Invocation SetIcon can produce NullPointerException // tabLayout.getTabAt(0).setIcon(R.drawable.ic_menu_tabone); // tabLayout.getTabAt(1).setIcon(R.drawable.ic_menu_tabtwo); // ... } 
  • Thank you for your decision! In my opinion, a very simple solution came out. - Gleb
  • Gave you a prize for a simpler solution. - Bokov Gleb

Do you need each tab to have its own class?

Declare TabLayout and ViewPager which respectively is in your layout markup.

 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); ViewPager viewPager = (ViewPager) findViewById(R.id.pager); setupViewPager(viewPager); tabLayout.setupWithViewPager(viewPager); private void setupViewPager(ViewPager viewPager) { Adapter adapter = new Adapter(getSupportFragmentManager()); adapter.addFragment(new menuFragment1(),"Вкладка 1"); adapter.addFragment(new menuFragment2(),"Вкладка 2"); viewPager.setAdapter(adapter); } 

Where menuFragment1 and menuFragment2 are your Fragment classes.

example:

 public class menuFragment1 extends Fragment { @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.menu_fragment_1, container, false); TextView tv = (TextView) view.findViewById(R.id.textview); return view; } 

And icons can be put like this:

insert after:

 mTabLayout.setupWithViewPager(mViewPager); for (int i = 0; i < mTabLayout.getTabCount(); i++) { mTabLayout.getTabAt(i).setIcon(R.drawable.your_icon); } 

and the fragment adapter itself:

 static class Adapter extends FragmentPagerAdapter { private final List<Fragment> mFragments = new ArrayList<>(); private final List<String> mFragmentTitles = new ArrayList<>(); Adapter(FragmentManager fm) { super(fm); } void addFragment(Fragment fragment, String title) { mFragments.add(fragment); mFragmentTitles.add(title); } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount() { return mFragments.size(); } @Override public CharSequence getPageTitle(int position) { return mFragmentTitles.get(position); } } 
  • Thank you for your decision! Unfortunately, I can not give a prize to two participants at once. - Bokov Gleb