Search code examples
androidandroid-layoutandroid-tabhostdrawableshapes

How to change shapedrawable color dynamically for TabHost background?


I have a TabHost, where I use a shape xml to make it looks like this:

enter image description here

I define the TabHost background this way:

private void setTabColor(TabHost tabHost) {
    try {

        for (int i = 0; i < tabHost.getTabWidget().getChildCount(); i++) {
            tabHost.getTabWidget().getChildAt(i).setBackgroundResource(R.drawable.strib_tab);
        }

    } catch (ClassCastException e) {
    }
}

where strib_tab is:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/line_pressed" android:state_selected="true"/>
<item android:drawable="@drawable/line"/>
</selector>

and line_pressed is:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item>
        <shape android:shape="rectangle" >
            <stroke
                android:width="5dip"
                android:color="@color/blue_bg" />

            <padding
                android:bottom="0dip"
                android:left="0dip"
                android:right="0dip"
                android:top="0dip" />
        </shape>
    </item>
    <item
        android:bottom="5dp"
        android:top="0dp">
            <shape android:shape="rectangle" >
            <solid android:color="#FFFFFF" />
        </shape>
    </item>

</layer-list>

and line is:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="@android:color/transparent" />
        </shape>
    </item>
</selector>

How can I change dynamically the color of the shape where the color is blue_bg in line_pressed ?


Solution

  • It seems you can't modify a StateListDrawable, however you can easily create a new one.

    As for the LayerDrawable, it can be manipulated pretty easily.

    Code speaks better, so here it is:

    Resources r = getResources();
    
    // Modify the LayerDrawable (line_pressed)
    LayerDrawable ld = (LayerDrawable) r.getDrawable(R.drawable.line_pressed);
    GradientDrawable gradient = (GradientDrawable) ld
                .findDrawableByLayerId(R.id.stroke);
    // Set a custom stroke (width in pixels)
    gradient.setStroke(5, Color.RED);
    
    // Create a new StateListDrawable
    StateListDrawable newStripTab = new StateListDrawable();
    newStripTab.addState(new int[] { android.R.attr.state_selected }, ld);
    newStripTab.addState(new int[0], r.getDrawable(R.drawable.line));
    
    tabHost.getTabWidget().getChildAt(i).setBackgroundResource(newStripTab);
    

    Notes:

    • I used a custom line_pressed, so could find the specific layer easily:

      <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
          <item android:id="@+id/stroke">
              <shape android:shape="rectangle" >
                  <stroke
                      android:width="5dip"
                      android:color="#000" />
                  ...
              </shape>
          </item>
          ...     
      </layer-list>
      
    • This code is untested practically but should work or at least provide some insight in how to accomplish this.