Search code examples
androidmaterial-components-androidmaterial-components

How to dynamically create a Material 3 Tonal Button?


I have tried a number of variations of new MaterialButton(context) including new MaterialButton(new ContextThemeWrapper(context, R.style.Widget_Material3_Button_TonalButton)) but it always results in a standard Material Button (Material 3).

Looking at the original source, the constructor doesn't seem to allow for a style resource:

public MaterialButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(wrap(context, attrs, defStyleAttr, DEF_STYLE_RES), attrs, defStyleAttr);

If my understanding of the wrap method is correct, it seems to create a ContextThemeWrapper but since the value of DEF_STYLE_RES (which is set to R.style.Widget_MaterialComponents_Button) is always passed in, a default Material Button is always created.

Is there a way to create a Tonal Button by specifying R.style.Widget_Material3_Button_TonalButton for the defStyleRes parameter? Alternatively, how would I go about dynamically creating a Material 3 Tonal Button?


Solution

  • Using

    MaterialButton(new ContextThemeWrapper(context, R.style.Widget_Material3_Button_TonalButton))
    

    you are applying a themeoverlay to the default style, you are not applying a different style.

    It means something like:

    <style name="Widget.Material3.Button.TonalButton" parent="">
        <item name="colorPrimary">@color/...</item>
        <item name="colorOnPrimary">@color/...</item>
        <!-- .... ->
    </style>
    

    The 3rd parameter of the constructor is defStyleAttr and it is an attribute defined in your app theme, it is not a style. If you want to apply a different style you have to:

    • Define a custom attribute in attrs.xml
        <attr name="myButtonStyle" format="reference"/>
    
    • Assing a style to this attribute in your app theme:
       <style name="AppTheme" parent="Theme.Material3.*">
            <item name="myButtonStyle">@style/Widget.Material3.Button.TonalButton</item>
       </style>
    

    Finally use:

    val customButton = MaterialButton(context, null, R.attr.myButtonStyle)