Force stacked tabs
Asked Answered
T

4

5

Is there any way to force stacked tabs? I want tabs separate of action bar (in a second row), even when landscape mode.

I am trying to force it but I can´t. For example, Twitter app in Android, when change to lanscape mode, continue showing two rows (tabs in a separate rows, which are known as stacked tabs).

Thanks!

Thinner answered 19/11, 2012 at 18:31 Comment(0)
O
8

Not only can you not force stacked tabs, you can't even force tabs -- Android can and will replace them with a drop-down list for navigation in some screen sizes and orientations.

Your only solution is to move away from action bar tabs, such as by using ViewPager and PagerTabStrip.

Obligor answered 19/11, 2012 at 18:33 Comment(0)
L
5

I had luck using the following reflection 'hack':

private void forceStackedTabs() {
    ActionBar ab = getSupportActionBar();
    if ( ab instanceof ActionBarImpl ) {
        // Pre-ICS
        disableEmbeddedTabs( ab );
    } else if ( ab instanceof ActionBarWrapper ) {
        // ICS
        try {
            Field abField = ab.getClass().getDeclaredField( "mActionBar" );
            abField.setAccessible( true );
            disableEmbeddedTabs( abField.get( ab ) );
        } catch (NoSuchFieldException e) {
            Log.e( TAG, "Error disabling actionbar embedded", e );
        } catch (IllegalArgumentException e) {
            Log.e( TAG, "Error disabling actionbar embedded", e );
        } catch (IllegalAccessException e) {
            Log.e( TAG, "Error disabling actionbar embedded", e );
        }
    }
}
private void disableEmbeddedTabs(Object ab) {
    try {
        Method setHasEmbeddedTabsMethod = ab.getClass().getDeclaredMethod("setHasEmbeddedTabs", boolean.class);
        setHasEmbeddedTabsMethod.setAccessible(true);
        setHasEmbeddedTabsMethod.invoke(ab, false);
    } catch (Exception e) {
        Log.e( TAG, "Error disabling actionbar embedded", e );
    }
}

Please note that I didn't think of this myself, but simply rewrote the code given in this answer: replicate ActionBar Tab(s) with custom view

Lois answered 8/4, 2013 at 9:12 Comment(1)
This doesn't appear to work while compiling for Kitkat and Lollipop. I can't find the ActionBarImpl class.Keyte
H
2

I used this to force ActionBar stacked or unstacked tabs from Gingerbread to KitKat.

Modded From: http://www.blogc.at/2014/01/23/android-tabs-appear-above-or-below-actionbar/

enter image description here

setHasEmbeddedTabs(mActionbar,false);

    public static void setHasEmbeddedTabs(Object inActionBar, final boolean inHasEmbeddedTabs)
    {
        // get the ActionBar class
        Class<?> actionBarClass = inActionBar.getClass();

        // if it is a Jelly Bean implementation (ActionBarImplJB), get the super class (ActionBarImplICS)
        if ("android.support.v7.app.ActionBarImplJB".equals(actionBarClass.getName()))
        {
            actionBarClass = actionBarClass.getSuperclass();
        }

        // if Android 4.3 >
        if ("android.support.v7.app.ActionBarImplJBMR2".equals(actionBarClass.getName())){
            actionBarClass = actionBarClass.getSuperclass().getSuperclass();
        }

        try
        {
            // try to get the mActionBar field, because the current ActionBar is probably just a wrapper Class
            // if this fails, no worries, this will be an instance of the native ActionBar class or from the ActionBarImplBase class
            final Field actionBarField = actionBarClass.getDeclaredField("mActionBar");
            actionBarField.setAccessible(true);
            inActionBar = actionBarField.get(inActionBar);
            actionBarClass = inActionBar.getClass();
        }
        catch (IllegalAccessException e) {}
        catch (IllegalArgumentException e) {}
        catch (NoSuchFieldException e) {}

        try
        {
            // now call the method setHasEmbeddedTabs, this will put the tabs inside the ActionBar
            // if this fails, you're on you own <img class="wp-smiley" alt=";-)" src="http://www.blogc.at/wp-includes/images/smilies/icon_wink.gif">
            final Method method = actionBarClass.getDeclaredMethod("setHasEmbeddedTabs", new Class[] { Boolean.TYPE });
            method.setAccessible(true);
            method.invoke(inActionBar, new Object[]{ inHasEmbeddedTabs });
        }
        catch (NoSuchMethodException e)        {}
        catch (InvocationTargetException e) {}
        catch (IllegalAccessException e) {}
        catch (IllegalArgumentException e) {}
    }
Hesiod answered 16/5, 2014 at 13:24 Comment(2)
This works, though the tab indicator is clipped on the leftmost and rightmost tabs.Keyte
It works good on Gingerbread, but on KitKat (Galaxy Tab Pro) and Lollipop (Nexus5) in portrait mode, tabs is placed a bit lower then where they should be (not centered), so the (blue) selection line is not visible.Preferential
S
1

If you need to support phones and tablets and don't want to use separate implementation you can put this in your activity:

@Override
public Resources getResources() {
    if (mResourcesImpl == null) {
        mResourcesImpl = new ResourcesImpl(super.getResources());
    }
    return mResourcesImpl;
}

class ResourcesImpl extends Resources {
    private Resources mResources;
    private Set<Integer> mActionBarEmbedTabsIds = new HashSet<Integer>();

    ResourcesImpl(Resources resources) {
        super(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration());

        mResources = resources;

        String packageName = getPackageName();
        mActionBarEmbedTabsIds.add(mResources.getIdentifier("abc_action_bar_embed_tabs", "bool", packageName));
        mActionBarEmbedTabsIds.add(mResources.getIdentifier("abc_action_bar_embed_tabs_pre_jb", "bool", packageName));
        mActionBarEmbedTabsIds.add(mResources.getIdentifier("action_bar_embed_tabs", "bool", "android"));
        mActionBarEmbedTabsIds.add(mResources.getIdentifier("action_bar_embed_tabs_pre_jb", "bool", "android"));
        mActionBarEmbedTabsIds.remove(0);
    }

    @Override
    public boolean getBoolean(int id) throws NotFoundException {
        if (mActionBarEmbedTabsIds.contains(id)) {
            return areActionBarTabsEmbed(); // stacked ot embed goes here
        }
        return super.getBoolean(id);
    }
}
Similitude answered 14/2, 2014 at 12:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.