Programmatically created button doesn't follow theme's button style
Asked Answered
E

3

6

The buttons created programmatically don't follow the buttonStyle defined in the apptheme, but the buttons created in xml follow it.

Below is my style.xml

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="buttonStyle">@style/Button.Primary</item>
    </style>

    <style name="Button.Primary" parent="Widget.AppCompat.Button.Colored">
        <item name="textAllCaps">true</item>
        <item name="android:textColor">#fff</item>
        <item name="backgroundTint">@color/btn_bck</item>
    </style>

And this is how I create a button programmatically:

Button progBtn = new Button(this);
progBtn.setText("Programmatic button");
LinearLayout layout = findViewById(R.id.container);
layout.addView(progBtn);

And it shows up as the default gray colored background with black text color.

But if I use the button in xml like:

<Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

It works fine and shows up with white text color and the correct backgroundTint specified in style.

I'd like to know why is there an inconsistency in the button style between the above 2 methods of button creation?

Earl answered 21/4, 2021 at 14:1 Comment(4)
You're using the Button constructor that doesn't include any styled attributes; you want the overloaded constructor that accepts them; Edit: it's also not inheriting the default button style because you're defining the attribute for an AppCompatButton (buttonStyle vs android:buttonStyle) but then using a ButtonLune
Ohh thanks, I tried using new Button(this, null, R.attr.buttonStyle);( though I'm not really sure if this is the correct way to use it), but it still doesn't really work as expected. It does apply the style but the background color is not the same. It's using color accent as background color.Earl
Anytime, and for "It's using color accent as background color." -- that's the same reason as my edit from the first comment: the styles are implemented using the AppCompat attribute format (backgroundTint instead of android:backgroundTint), which the default Button doesn't use. You either need to use the android style declaration (android:xxxx) or use an AppCompatButton insteadLune
@ShivamPokhriyal new Button(this, null, R.attr.buttonStyle); doesn't work because it uses the same style defined with the attribute buttonStyle but it is a Button and not an AppCompatButton. It means that the implementations are different. Check the answer below.Laden
L
4

They are different because you are using a Theme.AppCompat.* theme. With this theme the Button defined in the layout is replaced at runtime by a AppCompatButton.

You can use:

Button progBtn = new AppCompatButton(this);
progBtn.setText("Programmatic button");
LinearLayout layout = findViewById(R.id.container);
layout.addView(progBtn)

enter image description here

Laden answered 21/4, 2021 at 14:22 Comment(0)
E
1

I was able to achieve the result of the android material design with my adjustments in this way:

In your Activity:

import com.google.android.material.button.MaterialButton;

Button progBtn = new MaterialButton(this);
progBtn.setText("ClickMe");
progBtn.setOnClickListener(view -> clickHandler(view)); //using java 8 lambda
//progBtn.setOnClickListener(this::clickHandler); or using java 8 method reference
layout.addView(progBtn);

In your style.xml add this:

Notice the parent definition of the style!

<style name="Button.Primary" parent="android:style/Widget.Button">
    <item name="android:background">@color/green</item> //the color definition is in colors.xml
    .
    more custom styles if you need...
    .
</style>

Hopefully this will help someone...

Encrata answered 28/7, 2023 at 22:31 Comment(1)
Works for me. Need to check themes.xml and if Theme.MaterialComponents.* used then you need to use MaterialButton, if Theme.AppCompat.* used then you need to use AppCompatButton.Hailee
C
0

This should do the trick

int buttonStyle = R.style.Button.Primary;
Button button = new Button(this, null, buttonStyle);

or

int buttonStyle = Button.Primary;
Button button = new Button(new ContextThemeWrapper(this, buttonStyle), null, buttonStyle);
Contagium answered 21/4, 2021 at 14:21 Comment(1)
it is not enough. In this way your Button uses the style defined with the attribute buttonStyle but it is not an AppCompatButton as the Button defined in the layout. In this way they are using a different implementation.Laden

© 2022 - 2024 — McMap. All rights reserved.