4

Is it possible to have a tablayout inside a tab of another tablayout? I have created the following image for a better explanation. The slide movement desired is as it is described in the image.

enter image description here

My main activity

Xml

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabMode="fixed"
            app:tabGravity="fill"/>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"  />

</android.support.design.widget.CoordinatorLayout>

Code

public class MainActivity extends AppCompatActivity {

    private TabLayout tabLayout;

    private final static int[] tabIcons = {
            R.drawable.ic_tab_1,
            R.drawable.ic_tab_2,
            R.drawable.ic_tab_3,
            R.drawable.ic_tab_4
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(viewPager);

        tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(viewPager);
        setupTabIcons();
    }

    private void setupTabIcons() {
        tabLayout.getTabAt(0).setIcon(tabIcons[0]);
        tabLayout.getTabAt(1).setIcon(tabIcons[1]);
        tabLayout.getTabAt(2).setIcon(tabIcons[2]);
        tabLayout.getTabAt(3).setIcon(tabIcons[3]);
    }

    private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFrag(new Fragment1());
        adapter.addFrag(new Fragment2());
        adapter.addFrag(new Fragment3());
        adapter.addFrag(new Fragment4());
        viewPager.setAdapter(adapter);
    }

    class ViewPagerAdapter extends FragmentPagerAdapter {

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

        ViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

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

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

        void addFrag(Fragment fragment) {
            mFragmentList.add(fragment);
        }
    }
}

Fragments

Xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@android:color/holo_blue_light"
    android:id="@+id/fragment_1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="myContext">

    <TextView
        android:text="It is just a text."
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

Code

public class Fragment1 extends Fragment {

    public Fragment1() { }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment.
        return inflater.inflate(R.layout.fragment_1, container, false);
    }
}

How should Fragment2_A and Fragment2_B XML and Java code be?

Santiago Gil
  • 1,292
  • 7
  • 21
  • 52
  • why not possible? I don't get it or what? – M. Erfan Mowlaei Aug 18 '16 at 14:49
  • and what is the problem? as far as I know there is no problem with keeping `ViewPager` inside `Fragment` inside another `ViewPager`. and default behaviour is like you wish - when inside `Fragment` another `ViewPager` is placed then it "swallow" touch events till border, then when it cant slide it pass `MotionEvent` to parent. Can you show your `R.layout.fragment_1` ? your `R.layout.fragment_2` should contain another `TabLayout` with own id – snachmsm Aug 18 '16 at 14:50
  • @snachmsm question edited with `R.layout.fragment_1`. Sorry, I'm just an Android beginner, there is no problem ^^ Only that I didn't find a direct solution. My problem is that first layout is declared in an activity, but the second one i don't know where to declare it, because I have 2 fragments `Fragment2_A` and `Fragment2_B`, not an activity. – Santiago Gil Aug 18 '16 at 14:56

3 Answers3

6

ok, so inside your fragment you have only TextView. Now for fragment_2 put another TabLayout and ViewPager (you don't need AppBar, and Coordinator, they will be already there from parent layout of Activity)

frag2.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <android.support.design.widget.TabLayout
        android:id="@+id/frag2_tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="fixed"
        app:tabGravity="fill"/>
    <android.support.v4.view.ViewPager
        android:id="@+id/frag2_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"  />
</LinearLayout>

you have to create Frag2 Fragment , init with above layout inside OnCreateView and then for frag2_viewpager ViewPager class set another adapter for frag2a.xml and frag2b.xml Fragments only, they may have lets assume only TextViews or whatever. TabLayout will be placed above, inside Frag2 (and one in Activity as on pic)

snachmsm
  • 17,866
  • 3
  • 32
  • 74
  • And I have to put the `TabLayout` in the two Fragments `Fragment2_A` and `Fragment2_B`? – Santiago Gil Aug 18 '16 at 15:17
  • see the edit. in short: just use `Frag2`, inside it create another adapter for another fragments. `TabBar` will be only one (another) from `Frag2`, `Frag2a` and `Frag2b` initialize as you wish. swiping functionality (touch event passing in fact) as on your picture will work out-of-the-box – snachmsm Aug 18 '16 at 15:22
  • Ok, if I have correct understood, I have 3 fragments for this tab. `RootFrag2`, `Frag2_A` and `Frag2_B`. These two last are normal fragments. And in the root one, I have created the other adapter for these two fragments (I have just adapted the main acitivity as a fragment). However I get an error, in `setupViewPager` method declaration, by using `getSupportFragmentManager()`. `Cannot resolve method 'getSupportFragmentManager()'`. – Santiago Gil Aug 18 '16 at 15:51
  • 1
    [How can I access getSupportFragmentManager() in a fragment?](http://stackoverflow.com/questions/20237531/how-can-i-access-getsupportfragmentmanager-in-a-fragment) note you have always `getActivity()` method inside `Fragment`, may be helpfull (`((MainActivity) getActivity()).methodInsideMainActivity()`) – snachmsm Aug 18 '16 at 15:55
  • That solved the error! It is fast totally working as desired. The slide movement works correct, but when I reach `Fragment4`, the TabLayout inside `Tab2` breaks, and `Frag2_A` & `Frag2_B` happen that disappear. I can create a public repo with current code if desired. – Santiago Gil Aug 18 '16 at 16:09
  • 1
    not needed. `RecyclerView` have own "memory" for carried `Fragments`, by default its set to 1. it means that recycler keeps one view/fragment to left and right (and current of course) for possibility of smooth swiping without "lag" for draw another whole screen. you may increase this value using [setOffscreenPageLimit](https://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)). BUT if your app is crashing it means that you have bug probably inside Frag2 or any of Frag2children which occurs when `Fragment` is removed (detached) – snachmsm Aug 18 '16 at 16:16
  • Worked! I used viewPager.setOffscreenPageLimit(3), in my `TabLayout` with 4 tabs. – Santiago Gil Aug 18 '16 at 16:23
  • nice, but note that there might be bug in one of your `Fragment`s and they "by-design" should be easy-detachable. just investigate this :) good luck! – snachmsm Aug 18 '16 at 16:30
6

I know that this is not a direct answer to the question and that I might get penalized for this, but you should not nest tabs in tabs. Google uses design concepts called material design. One of the rules for tabs is not to nest them. Here is a link to the page: https://material.google.com/components/tabs.html#tabs-usage. I think that it is really important that we as developers follow this to make the Android platform as universal and as amazing as it can be.

Thanks, Oak

Oak
  • 498
  • 1
  • 5
  • 19
2

Simple

Everything will remain same like you set ViewPager in Activity. Just you need to use getChildFragmentManager() in Fragment instead of getFragmentManager().

From getChildFragmentManager() documentation

Return a private FragmentManager for placing and managing Fragments inside of this Fragment.

From getFragmentManager() documentation

Return the FragmentManager for interacting with fragments associated with this fragment's activity.

You can see @this answer for complete code.

Community
  • 1
  • 1
Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212