14

I have been looking to see if there is any information on how to always display the ActionBar tabs below the ActionBar even when the phone is orientated to landscape. I know that automatically it places the tabs in the ActionBar depending on whether there is enough room on the screen to fit them, but I want them to always be fixed underneath the ActionBar even in landscape. I found a similar question which didn't have a definitive answer: How to display tabs below action bar. I also know that many Google applications, such as; Google Play, Google Music etc implement this type of design pattern, so it is obviously achievable and acceptable as a design pattern.

I am currently using the ActionBarSherlock library to create my sliding tabs navigation and I would really appreciate it if anyone has figured out how to do this themselves. Thanks in advance.

Here is my activity code:

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    viewPager = new ViewPager(this);
    viewPager.setId(R.id.pager);
    setContentView(viewPager);

    tabsAdapter = new TabsAdapter(this, viewPager); // Declares the tabs adapter class with the view pager view

    actionBarTabs = getSupportActionBar();
    actionBarTabs.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    actionBarTabs.setCustomView(spinnerView);
    actionBarTabs.setDisplayShowCustomEnabled(true);    

    /* Adds fragments to the tabs adapter */
    tabsAdapter.addTab(actionBarTabs.newTab().setText("FRAG1"), Fragment_1.class, null);
    tabsAdapter.addTab(actionBarTabs.newTab().setText("FRAG2"), Fragment_2.class, null);
    tabsAdapter.addTab(actionBarTabs.newTab().setText("FRAG3"), Fragment_3.class, null);
}

And here is my TabsAdapter code:

public class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener , ViewPager.OnPageChangeListener 
{
private final Context context;
private final ActionBar actionBar;
private final ViewPager viewPager;
private final ArrayList<TabInfo> tabsList = new ArrayList<TabInfo>();

/**
 * TabInfo class
 * 
 * Static class containing the tab information.
 * 
 * @since 1.0
 */
static final class TabInfo
{
    private final Class<?> clss;
    private final Bundle args;

    TabInfo(Class<?> _class, Bundle _args)
    {
        clss = _class;
        args = _args;
    }
}

/**
 * Tabs adapter overload constructor.
 * 
 * @param fragmentActivity sets the fragment activity to the adapter.
 * @param refViewPager sets the viewPager variable.
 * @see
 * @since 1.0
 */
public TabsAdapter(SherlockFragmentActivity fragmentActivity, ViewPager refViewPager) 
{
    super(fragmentActivity.getSupportFragmentManager());
    context = fragmentActivity;
    actionBar = fragmentActivity.getSupportActionBar();
    viewPager = refViewPager;
    viewPager.setAdapter(this);
    viewPager.setOnPageChangeListener(this);
}

/**
 * Add tab method to add a tab to the list.
 * 
 * @param tab sets the tab to be added to the tabs in the action bar.
 * @param clss sets the class variable in the TabInfo class.
 * @param args sets the bundle variable in the TabInfo class.
 * @see
 * @since 1.0
 */
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args)
{
    TabInfo info = new TabInfo(clss, args);
    tab.setTag(info);
    tab.setTabListener(this);
    tabsList.add(info);
    actionBar.addTab(tab);
    notifyDataSetChanged();
}

@Override
public void onPageScrollStateChanged(int state) 
{

}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) 
{

}

@Override
public void onPageSelected(int position) 
{
    actionBar.setSelectedNavigationItem(position);
}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) 
{
    viewPager.setCurrentItem(tab.getPosition());
    Object tag = tab.getTag();
    for (int i = 0; i<tabsList.size(); i++)
    {
        if (tabsList.get(i) == tag)
        {
            viewPager.setCurrentItem(i);
        }
    }

}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) 
{

}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) 
{

}

@Override
public Fragment getItem(int position) 
{
    TabInfo info = tabsList.get(position);
    return Fragment.instantiate(context, info.clss.getName(), info.args);
}

@Override
public int getCount() 
{
    return tabsList.size();
}
}
Community
  • 1
  • 1
James Meade
  • 1,147
  • 5
  • 22
  • 46

3 Answers3

12

I had same issues with landscape mode and I found the solution here: http://andreimihu.com/blog/2013/10/17/android-always-embed-tabs-in-actionbar/

Basically, the writer wants the tab inside actionbar while you and I wants it outside. So, just change the method call to false (code from the above link, but a bit modified):

// This is where the magic happens!
public void forceTabs() {
    try {
        final ActionBar actionBar = getActionBar();
        final Method setHasEmbeddedTabsMethod = actionBar.getClass()
            .getDeclaredMethod("setHasEmbeddedTabs", boolean.class);
        setHasEmbeddedTabsMethod.setAccessible(true);
        setHasEmbeddedTabsMethod.invoke(actionBar, false);
    }
    catch(final Exception e) {
        // Handle issues as needed: log, warn user, fallback etc
        // This error is safe to ignore, standard tabs will appear.
    }
}
John Pang
  • 2,403
  • 25
  • 25
  • I've had the same issue and the function is working as it's supposed to be, but the other issue is that I have only 2 tabs and they are pushed to the left, is there any way to make them stay in center ? – arash moeen Oct 18 '14 at 07:56
  • It is not working in case of ActionBarSherlock . Do you have any idea about that ??? – Amit Jayaswal Nov 05 '14 at 06:52
  • @arashmoeen The tabs are usually pushed to the left and center if in landscape mode. I don't have answer for that now. – John Pang Nov 05 '14 at 18:26
  • @AmitJayaswal The code is for use with Google's ActionBar, I didn't test it with ActionBarSherlock. – John Pang Nov 05 '14 at 18:27
  • Works great with Holo theme. With Material theme, the tab view is somewhat offset, resulting in the bottom being cut off and as a result, there is no indication of the currently selected tab. Will need to do some research myself... – user149408 Apr 12 '16 at 08:03
3

First of all, what you are describing as "many Google applications, such as; Google Play, Google Music etc implement this type of design pattern" are not necessarily navigation tabs related to the ActionBar.

There are a lot of implementations that use a viewPager with a title indicator. Refer to the PagerSlidingTabStrip library for a good implementation.

Also, you should check the official android documentation where it talks in depth about navigation with tabs and shows different ways to obtain it. Check these pages in the documentation: Providing Descendant and Lateral Navigation and Creating Swipe Views with Tabs

Also, there are a lot of answers on this topic on stackoverflow.com. The library I suggested was already mentioned in this answer: https://stackoverflow.com/a/16544501/529138.

Check this question and the related answers as well: Tabs below action bar

These resources should be enough to help you with the desired functionality :)

Community
  • 1
  • 1
Bandreid
  • 2,727
  • 28
  • 47
  • Thank you very much. I have come across these answers before. I also came across Android's own class [PagerTabStrip](http://developer.android.com/reference/android/support/v4/view/PagerTabStrip.html) which I think can be used in this way. Is it possible to create a sliding tabs navigation using this in conjunction with ViewPager? – James Meade Feb 24 '14 at 14:29
  • Yes, it's possible. PagerTabStrip was created to work with ViewPager. Personally, I never used it. I have been using ViewPagerIndicator library by JakeWharton but I'll test out PagerTabStrip when I have some spare time. Anyway, I think this link will help you: http://blog.pboos.ch/post/40575809334/android-pagertabstrip-viewpager – Bandreid Feb 24 '14 at 14:45
  • Thank you very much for your help. I will try it out at some point and please let me know how it goes when you try it. – James Meade Feb 25 '14 at 09:26
1
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME);

actionBar.setLogo(null);

    View homeIcon = findViewById(
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? 
                    android.R.id.home : android.support.v7.appcompat.R.id.home);
    ((View) homeIcon.getParent()).setVisibility(View.GONE);
    ((View) homeIcon).setVisibility(View.GONE);