Reputation: 18729
I am trying to programmatically create some Buttons to add them to an existing ViewGroup. This works fine, but I am not able to init the buttons with the right style.
I am aware, that it is not possible to set/change the style of view once it has been created. But all solutions I found so far say, that it should be no problem to create a view with a custom style (from a API level 11 up I think and I am using 14+):
Button button = new Button (getActivity(), null, R.style.MyButtonStyle);
The only effect is, that the button is created without any style. No background, so selector, no margin/padding just the plain text. I thought MyButtonStyle would be broken, but creating the button in XML using MyButtonStyle it no problem.
Why is this not working?
Upvotes: 2
Views: 3731
Reputation: 18729
I finally found the solution! The question was, why the following is not working:
Button button = new Button (getActivity(), null, R.style.MyButtonStyle);
Turned out, that the problem is, that R.style.xxx
is being used instead of R.attr.xxx
. It seems that this is a bug in the implementation of View(Context context, AttributeSet attrs, int defStyleAttr)
or at least in the documentation of this contstructor: The third paramater MUST be R.attr for the constructor to work and to apply the style correctly.
So in order to get the constructor working one has to add some more code to /res/values/attr.xml
and /res/values/styles.xml
:
<!-- /res/values/attr.xml -->
<declare-styleable name="AppTheme">
<attr name="specialButtonStyle" format="reference"/>
</declare-styleable>
<!-- /res/values/styles.xml -->
<style name="AppTheme" parent="AppBaseTheme">
...
<item name="specialButtonStyle">@style/MyButtonStyle</item>
</style>
<style name="MyButtonStyle" parent="@android:style/Widget.Button">
...
</style>
// In Java we can now use R.attr.specialButtonStyle instead of R.style.MyButtonStyle
// getActivity() is used because I am working in a Fragment. Within an
// Activity this can be used instead...
Button button = new Button(getActivity(), null, R.attr.specialButtonStyle);
It is quite annoying, that the documentation has not been updated about this problem. The first bug report about this issue was filed back in 2011...
Also one has to write some extra code to get this running this solution is much faster and (from my point of view) much better than inflating a XML layout as usually proposed.
Upvotes: 11
Reputation: 39836
you probably can achieve that by using a ContextThemeWrapper
ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.MyButtonStyle);
Button = new Button(ctw);
edit:
I just checked the source code and the reason your code (and I guess mine code) doesn't work is clear now.
public View(Context context, AttributeSet attrs, int defStyleAttr) {
this(context);
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View,
defStyleAttr, 0);
with the attrs
being null, the TypedArray
doesn't have any values to use.
My code I used before for Dialogs and I thought it would work the same.
You can check it on the View source code.
so probably an update answer that should work is if you pass the AttributeSet
on the constructor. I'm not sure how to do that, but looking at the docs (HERE) you probably can do something like that:
// the docs says `myResource` so probably the style ID
XmlPullParser parser = resources.getXml(R.style.MyButtonStyle);
AttributeSet attributes = Xml.asAttributeSet(parser);
Button button = new Button (getActivity(), attributes, R.style.MyButtonStyle);
Upvotes: 1
Reputation: 63
I am not very sure about why it is not working. However would like to share my answer, which helped me have custom style button.
Inside your activity, include following:
Button btnMyCustomButton = (Button) findViewById(R.id.myTestButton);
Inside your layout xml file, include following:
<Button
android:id="@+id/myTestButton"
android:background="@drawable/my_custom_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|bottom"
android:layout_marginBottom="30dp"
style="@style/my_custom_button_text"/>
Inside your drawable folder, create my_custom_button.xml and include following for example:
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape>
<solid
android:color="#35adad" />
<stroke
android:width="1dp"
android:color="#2f9999" />
<corners
android:radius="6dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
<item>
<shape>
<gradient
android:startColor="#35adad"
android:endColor="#2f9999"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#2f9999" />
<corners
android:radius="6dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
</selector>
You can also include following in your style.xml so that button text can also be custom.
<style name="my_custom_button_text" >
<item name="android:layout_width" >fill_parent</item>
<item name="android:layout_height" >wrap_content</item>
<item name="android:textColor" >#ffffff</item>
<item name="android:gravity" >center</item>
<item name="android:layout_margin" >3dp</item>
<item name="android:textSize" >30sp</item>
<item name="android:textStyle" >bold</item>
<item name="android:shadowColor" >#000000</item>
<item name="android:shadowDx" >1</item>
<item name="android:shadowDy" >1</item>
<item name="android:shadowRadius" >2</item>
</style>
Upvotes: 0
Reputation: 751
You can do like this.
First create a xml file in the res/drawable
folder of your project having the custom style. (say buttonstyle.xml). Then,
Button btn = new Button(this);
btn.setText("Test Example");
btn.setId(R.string.btn_name);
btn.setBackground(R.drawable.buttonstyle);
Hope this helps you.
Upvotes: -1