[android] How to programmatically set style attribute in a view

I'm getting a view from the XML with the code below:

Button view = (Button) LayoutInflater.from(this).inflate(R.layout.section_button, null);

I would like to set a "style" for the button how can I do that in java since a want to use several style for each button I will use.

This question is related to android styles

The answer is


I made a helper interface for this using the holder pattern.

public interface StyleHolder<V extends View> {
    void applyStyle(V view);
}

Now for every style you want to use pragmatically just implement the interface, for example:

public class ButtonStyleHolder implements StyleHolder<Button> {

    private final Drawable background;
    private final ColorStateList textColor;
    private final int textSize;

    public ButtonStyleHolder(Context context) {
        TypedArray ta = context.obtainStyledAttributes(R.style.button, R.styleable.ButtonStyleHolder);

        Resources resources = context.getResources();

        background = ta.getDrawable(ta.getIndex(R.styleable.ButtonStyleHolder_android_background));

        textColor = ta.getColorStateList(ta.getIndex(R.styleable.ButtonStyleHolder_android_textColor));

        textSize = ta.getDimensionPixelSize(
                ta.getIndex(R.styleable.ButtonStyleHolder_android_textSize),
                resources.getDimensionPixelSize(R.dimen.standard_text_size)
        );

        // Don't forget to recycle!
        ta.recycle();
    }

    @Override
    public void applyStyle(Button btn) {
        btn.setBackground(background);
        btn.setTextColor(textColor);
        btn.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
    }
}

Declare a stylable in your attrs.xml, the styleable for this example is:

<declare-styleable name="ButtonStyleHolder">
    <attr name="android:background" />
    <attr name="android:textSize" />
    <attr name="android:textColor" />
</declare-styleable>

Here is the style declared in styles.xml:

<style name="button">
    <item name="android:background">@drawable/button</item>
    <item name="android:textColor">@color/light_text_color</item>
    <item name="android:textSize">@dimen/standard_text_size</item>
</style>

And finally the implementation of the style holder:

Button btn = new Button(context);    
StyleHolder<Button> styleHolder = new ButtonStyleHolder(context);
styleHolder.applyStyle(btn);

I found this very helpful as it can be easily reused and keeps the code clean and verbose, i would recommend using this only as a local variable so we can allow the garbage collector to do its job once we're done with setting all the styles.


For anyone looking for a Material answer see this SO post: Coloring Buttons in Android with Material Design and AppCompat

I used a combination of this answer to set the default text color of the button to white for my button: https://stackoverflow.com/a/32238489/3075340

Then this answer https://stackoverflow.com/a/34355919/3075340 to programmatically set the background color. The code for that is:

ViewCompat.setBackgroundTintList(your_colored_button,
 ContextCompat.getColorStateList(getContext(),R.color.your_custom_color));

your_colored_button can be just a regular Button or a AppCompat button if you wish - I tested the above code with both types of buttons and it works.

EDIT: I found that pre-lollipop devices do not work with the above code. See this post on how to add support for pre-lollipop devices: https://stackoverflow.com/a/30277424/3075340

Basically do this:

Button b = (Button) findViewById(R.id.button);
ColorStateList c = ContextCompat.getColorStateList(mContext, R.color.your_custom_color;
Drawable d = b.getBackground();
if (b instanceof AppCompatButton) {
    // appcompat button replaces tint of its drawable background
    ((AppCompatButton)b).setSupportBackgroundTintList(c);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // Lollipop button replaces tint of its drawable background
    // however it is not equal to d.setTintList(c)
    b.setBackgroundTintList(c);
} else {
    // this should only happen if 
    // * manually creating a Button instead of AppCompatButton
    // * LayoutInflater did not translate a Button to AppCompatButton
    d = DrawableCompat.wrap(d);
    DrawableCompat.setTintList(d, c);
    b.setBackgroundDrawable(d);
}

At runtime, you know what style you want your button to have. So beforehand, in xml in the layout folder, you can have all ready to go buttons with the styles you need. So in the layout folder, you might have a file named: button_style_1.xml. The contents of that file might look like:

<?xml version="1.0" encoding="utf-8"?>
<Button
    android:id="@+id/styleOneButton"
    style="@style/FirstStyle" />

If you are working with fragments, then in onCreateView you inflate that button, like:

Button firstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);

where container is the ViewGroup container associated with the onCreateView method you override when creating your fragment.

Need two more such buttons? You create them like this:

Button secondFirstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);
Button thirdFirstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);

You can customize those buttons:

secondFirstStyleBtn.setText("My Second");
thirdFirstStyleBtn.setText("My Third");

Then you add your customized, stylized buttons to the layout container you also inflated in the onCreateView method:

_stylizedButtonsContainer = (LinearLayout) rootView.findViewById(R.id.stylizedButtonsContainer);

_stylizedButtonsContainer.addView(firstStyleBtn);
_stylizedButtonsContainer.addView(secondFirstStyleBtn);
_stylizedButtonsContainer.addView(thirdFirstStyleBtn);

And that's how you can dynamically work with stylized buttons.


Depending on what style attributes you'd like to change you may be able to use the Paris library:

Button view = (Button) LayoutInflater.from(this).inflate(R.layout.section_button, null);
Paris.style(view).apply(R.style.YourStyle);

Many attributes like background, padding, textSize, textColor, etc. are supported.

Disclaimer: I authored the library.


First of all, you don't need to use a layout inflater to create a simple Button. You can just use:

button = new Button(context);

If you want to style the button you have 2 choices: the simplest one is to just specify all the elements in code, like many of the other answers suggest:

button.setTextColor(Color.RED);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);

The other option is to define the style in XML, and apply it to the button. In the general case, you can use a ContextThemeWrapper for this:

ContextThemeWrapper newContext = new ContextThemeWrapper(baseContext, R.style.MyStyle);
button = new Button(newContext);

To change the text-related attributes on a TextView (or its subclasses like Button) there is a special method:

button.setTextAppearance(R.style.MyTextStyle);

Or, if you need to support devices pre API-23 (Android 6.0)

button.setTextAppearance(context, R.style.MyTextStyle);

This method cannot be used to change all attributes; for example to change padding you need to use a ContextThemeWrapper. But for text color, size, etc. you can use setTextAppearance.


Yes, you can use for example in a button

Button b = new Button(this);
b.setBackgroundResource(R.drawable.selector_test);

The answer by @Dayerman and @h_rules is right. To give an elaborated example with code, In drawable folder, create an xml file called button_disabled.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" android:padding="10dp">   
 <solid android:color="@color/silver"/>
<corners
   android:bottomRightRadius="20dp"
   android:bottomLeftRadius="20dp"
   android:topLeftRadius="20dp"
   android:topRightRadius="20dp"/>
</shape>

Then in Java,

((Button) findViewById(R.id.my_button)).setEnabled(false);
((Button) findViewById(R.id.my_button)).setBackgroundResource(R.drawable.button_disabled);

This will set the button's property to disabled and sets the color to silver.

[The color is defined in color.xml as:

<resources>

    <color name="silver">#C0C0C0</color>

</resources>

If you are using the Support library, you could simply use

TextViewCompat.setTextAppearance(textView, R.style.AppTheme_TextStyle_ButtonDefault_Whatever);

for TextViews and Buttons. There are similar classes for the rest of Views :-)


I faced the same problem recently. here is how i solved it.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <!-- This is the special two colors background START , after this LinearLayout, you can add all view that have it for main background-->
    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:weightSum="2"

    android:background="#FFFFFF"
    android:orientation="horizontal"
    >

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#0000FF" />

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#F000F0" />
    </LinearLayout>
    <!-- This is the special two colors background END-->

   <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:text="This Text is centered with a special backgound,
    You can add as much elements as you want as child of this RelativeLayout"
    android:textColor="#FFFFFF"
    android:textSize="20sp" />
</RelativeLayout>
  • I used a LinearLayout with android:weightSum="2"
  • I gave to the two child elements android:layout_weight="1" (I gave each 50% of the parent space(width & height))
  • And finally, i gave the two child element different background colors to have the final effect.

Thanks !


You can do style attributes like so:

Button myButton = new Button(this, null,android.R.attr.buttonBarButtonStyle);

in place of:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn"
    style="?android:attr/buttonBarButtonStyle"

    />