Android: tabs appear above (or below) ActionBar *UPDATED*

On Android 3.0 and above, while using the ActionBar tabbed navigation style, the tabs sometimes appear above (or below) the action bar. This strange UX behaviour doesn’t seem to make sense, especially on devices with larger screens like tablets. The issue seems te be fixed since API level 19 (Android KitKat 4.4), but it still affects the majority of Android devices.

screenshot

This issue was already reported in 2012, but since then nobody came up with any foolproof solution for this problem. After looking into the source code of the ActionBar class, I came up with an elegant solution to finally get rid of this UX flaw. You can use this helper method with the native ActionBar as well as the Android App Compat library (android-support-v7).

/**
 * On Android 3.0 and above, while using the ActionBar tabbed navigation style, the tabs sometimes appear above the action bar.
 * This helper method allows you to control the 'hasEmbeddedTabs' behaviour.
 * A value of true will put the tabs inside the ActionBar, a value of false will put it above or below the ActionBar.
 *
 * You should call this method while initialising your ActionBar tabs.
 * Don't forget to also call this method during orientation changes (in the onConfigurationChanged() method).
 *
 * @param inActionBar
 * @param inHasEmbeddedTabs
 */
public static void setHasEmbeddedTabs(Object inActionBar, final boolean inHasEmbeddedTabs)
{
		// get the ActionBar class
		Class<?> actionBarClass = inActionBar.getClass();

		// if it is a Jelly Bean implementation (ActionBarImplJBMR2), get the super super class (ActionBarImplICS)
		if ("android.support.v7.app.ActionBarImplJBMR2".equals(actionBarClass.getName()))
		{
				actionBarClass = actionBarClass.getSuperclass().getSuperclass();
		}
		// if it is a Jelly Bean implementation (ActionBarImplJB), get the super class (ActionBarImplICS)
		else if ("android.support.v7.app.ActionBarImplJB".equals(actionBarClass.getName()))
		{
				actionBarClass = actionBarClass.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 😉
				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) {}
}

Using this helper method is easy:

// a value of true will put the tabs inside the ActionBar
ActionBarUtils.setHasEmbeddedTabs(actionBar, true);

If you think this implementation isn’t completely foolproof yet, I’m always open to suggestions and improvements. You can find the helper class source code on my Github account.