I'm trying to apply a custom Button background across my entire application, but it only seems to work when I do it programmatically.
Here is styles.xml. I use <item name="android:buttonStyle">@style/OverlayButton</item>
to indicate the custom style "OverlayButton" (by the way, <item name="buttonStyle">@style/OverlayButton</item>
gives "No resource found that matches the given name: attr 'buttonStyle'.") and then <item name="android:background">@drawable/overlay_button</item>
to call the custom Drawable
.
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
<!-- http://stackoverflow.com/questions/6159113/android-where-is-the-spinner-widgets-text-color-attribute-hiding -->
<item name="android:spinnerItemStyle">@style/SpinnerItem</item>
<item name="android:spinnerDropDownItemStyle">@style/SpinnerItem.DropDownItem</item>
<!-- http://stackoverflow.com/questions/8922924/how-to-change-android-spinner-popupbackground -->
<!-- http://www.ezzylearning.com/tutorial.aspx?tid=1763429 -->
<item name="android:listViewStyle">@style/myListView</item>
<item name="android:buttonStyle">@style/OverlayButton</item>
</style>
<style name="SpinnerItem" parent="@android:style/Widget.TextView.SpinnerItem">
<item name="android:textColor">#ADD8E6</item>
</style>
<style name="SpinnerItem.DropDownItem" parent="@android:style/Widget.DropDownItem.Spinner">
<item name="android:textColor">#ADD8E6</item>
</style>
<style name="myListView" parent="@android:style/Widget.ListView">
<item name="android:background">@drawable/intro_spinner</item>
</style>
<!-- Style for Overlay Buttons -->
<style name="OverlayButton" parent="@android:style/Widget.Button">
<item name="android:background">@drawable/overlay_button</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">12sp</item>
<item name="android:textColor">#FF000000</item>
<item name="android:layout_marginLeft">0dp</item>
<item name="android:layout_marginRight">0dp</item>
<item name="android:layout_marginTop">10dp</item>
<item name="android:layout_marginBottom">10dp</item>
</style>
<!-- Style for Confirmation Dialog -->
<style name="AlertDialogCustom" parent="@android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:background">@drawable/dialog_background</item>
<item name="android:textColor">#FF000000</item>
<item name="android:textSize">12sp</item>
<item name="android:typeface">monospace</item>
</style>
</resources>
The custom Drawable, overlay_button.xml, is here.
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape>
<gradient
android:startColor="#999999"
android:endColor="#c0c0c0"
android:angle="270" />
<stroke
android:width="3dp"
android:color="#202619" />
<corners
android:radius="3dp" />
<padding
android:left="1dp"
android:top="1dp"
android:right="1dp"
android:bottom="1dp" />
<margin
android:left="5dp"
android:top="5dp"
android:right="5dp"
android:bottom="5dp" />
</shape>
</item>
<item android:state_focused="true" >
<shape>
<gradient
android:endColor="#999999"
android:startColor="#c0c0c0"
android:angle="270" />
<stroke
android:width="3dp"
android:color="#202619" />
<corners
android:radius="3dp" />
<padding
android:left="1dp"
android:top="1dp"
android:right="1dp"
android:bottom="1dp" />
<margin
android:left="5dp"
android:top="5dp"
android:right="5dp"
android:bottom="5dp" />
</shape>
</item>
<item>
<shape>
<gradient
android:endColor="#aa393939"
android:startColor="#aa737373"
android:angle="270" />
<stroke
android:width="3dp"
android:color="#202619" />
<corners
android:radius="3dp" />
<padding
android:left="1dp"
android:top="1dp"
android:right="1dp"
android:bottom="1dp" />
<margin
android:left="5dp"
android:top="5dp"
android:right="5dp"
android:bottom="5dp" />
</shape>
</item>
</selector>
When I create a Button with final Button b = new Button(context);
I do not get the custom Drawable. This, however, works:
final Button b = new Button(context);
Drawable buttonStates; // get Drawable to set button states
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
buttonStates = context.getResources().getDrawable(R.drawable.overlay_button, context.getTheme());
} else {
buttonStates = context.getResources().getDrawable(R.drawable.overlay_button);
}
b.setBackground(buttonStates);
Why should this work programmatically but not in the XML?
Update: @r-zagórski had a good clue. The XML-inflated buttons take the custom style and work as expected. The buttons that don't work are created programmatically and inserted via LinearLayout.addView(b)
. (By the way, final Button b = new Button(context, null, R.drawable.overlay_button_selector)
doesn't work.) I don't see why this is not working like the XML-inflated buttons.