I tried many of the suggestions posted here and other places with no luck. But I think I managed to piece together a (albeit not perfect) solution.
The TabWidget is using a selector. Essentially it is showing a different 9 patch image depending on the state of the tab (selected, pressed, etc.). I finally figured out that you could generate a selector programmatically. I started with generated 9 patches from http://android-holo-colors.com/ (color: #727272, TabWidget: Yes).
The biggest issue was setting the color. Setting the color filter did nothing. So, I ended up changing the colors of each of the pixels of the 9 patch image inside a loop.
...
/**
* <code>NinePatchDrawableUtility</code> utility class for manipulating nine patch resources.
*
* @author amossman
*
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class NinePatchDrawableUtility {
// Matches the colors in the supported drawables
private static final int TAB_UNDERLINE_HIGHLIGHT_COLOR = 1417247097;
private static final int TAB_UNDERLINE_COLOR = -8882056;
private static final int TAB_PRESSED_COLOR = -2122745479;
private Resources resources;
public NinePatchDrawableUtility(Resources resources) {
this.resources = resources;
}
/**
* Create a <code>StateListDrawable</code> that can be used as a background for the {@link android.widget.TabWidget}</br></br>
*
* <code>
* FragmentTabHost tabHost = ...</br>
* NinePatchUtility ninePatchUtility = new NinePatchUtility(getResources());</br>
* TabWidget tabWidget = tabHost.getTabWidget();</br>
* for (int i = 0; i < tabWidget.getChildCount(); i++) {</br>
* tabWidget.getChildAt(i).setBackground(ninePatchUtility.getTabStateListDrawable(titleColor));</br>
* }
* </code>
*
* @param tintColor The color to tint the <code>StateListDrawable</code>
* @return A new <code>StateListDrawable</code> that has been tinted to the given color
*/
public StateListDrawable getTabStateListDrawable(int tintColor) {
StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed},
changeTabNinePatchColor(resources, R.drawable.cc_tab_selected_pressed_holo, tintColor));
states.addState(new int[] {android.R.attr.state_focused},
changeTabNinePatchColor(resources, R.drawable.cc_tab_selected_focused_holo, tintColor));
states.addState(new int[] {android.R.attr.state_selected},
changeTabNinePatchColor(resources, R.drawable.cc_tab_selected_holo, tintColor));
states.addState(new int[] { },
changeTabNinePatchColor(resources, R.drawable.cc_tab_unselected_holo, tintColor));
return states;
}
/**
* Change the color of the tab indicator.</br></br>
*
* Supports only the following drawables:</br></br>
*
* R.drawable.cc_tab_selected_pressed_holo</br>
* R.drawable.cc_tab_selected_focused_holo</br>
* R.drawable.cc_tab_selected_holo</br>
* R.drawable.cc_tab_unselected_holo</br></br>
*
* Note: This method is not efficient for large <code>Drawable</code> sizes.
*
* @param resources Contains display metrics and image data
* @param drawable The nine patch <code>Drawable</code> for the tab
* @param tintColor The color to tint the <code>Drawable</code>
* @return A new <code>NinePatchDrawable</code> tinted to the given color
*/
public NinePatchDrawable changeTabNinePatchColor(Resources resources, int drawable, int tintColor) {
int a = Color.alpha(tintColor);
int r = Color.red(tintColor);
int g = Color.green(tintColor);
int b = Color.blue(tintColor);
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap bitmap = BitmapFactory.decodeResource(resources, drawable, opt);
for (int x = 0; x < bitmap.getWidth(); x++) {
for (int y = 0; y < bitmap.getHeight(); y++) {
int color = bitmap.getPixel(x, y);
if (color == TAB_PRESSED_COLOR) {
bitmap.setPixel(x, y, Color.argb((int)(a * 0.5), r, g, b));
} else if (color == TAB_UNDERLINE_HIGHLIGHT_COLOR) {
bitmap.setPixel(x, y, Color.argb((int)(a * 0.9), r, g, b));
} else if (color == TAB_UNDERLINE_COLOR) {
bitmap.setPixel(x, y, tintColor);
}
}
}
return new NinePatchDrawable(resources, bitmap, bitmap.getNinePatchChunk(), new Rect(), null);
}
}
Example of usage:
/**
* Theme the tab widget with the defined background color and title color set
* in the TabManager
* @param tabWidget
*/
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
public void theme(TabWidget tabWidget) {
ColorDrawable backgroundDrawable = new ColorDrawable(backgroundColor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
tabWidget.setBackground(backgroundDrawable);
tabWidget.setAlpha(0.95f);
} else {
backgroundDrawable.setAlpha(242);
tabWidget.setBackgroundDrawable(backgroundDrawable);
}
NinePatchDrawableUtility ninePatchUtility = new NinePatchDrawableUtility(resources);
for (int i = 0; i < tabWidget.getChildCount(); i++) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
tabWidget.getChildAt(i).setBackground(ninePatchUtility.getTabStateListDrawable(titleColor));
} else {
tabWidget.getChildAt(i).setBackgroundDrawable(ninePatchUtility.getTabStateListDrawable(titleColor));
}
View tabView = tabWidget.getChildTabViewAt(i);
tabView.setPadding(0, 0, 0, 0);
TextView tv = (TextView) tabView.findViewById(android.R.id.title);
tv.setSingleLine(); // set the texts on the tabs to be single line
tv.setTextColor(titleColor);
}
}