Goal
How to programmatically create a MaterialButton with a custom style resources instead of attr?
styles.xml
<style name="CustomButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="android:textColor">#FF0000</item>
</style>
I have tried with the following, but it is not working as expected (the button will fallback to R.style.Widget_MaterialComponents_Button no matter which style were provided).
MaterialButton button = new MaterialButton(context, null, R.style.CustomButtonStyle);
Note
I do NOT wish to create a custom theme attribute and pass it like so new MaterialButton(context, null, R.attr.CustomButtonStyle);
Tried with material-components-android 1.2.0-alpha05 and 1.1.0
Related
I am looking to create a custom ViewGroup to be used in a library; which contains a few ImageButton objects. I would like to be able to apply a style each ImageButton; but I cannot figure out how to apply a style programmatically other than by applying a attribute resource to the defStyleAttr parameter; like so:
mImageButton = new ImageButton(
getContext(), // context
null, // attrs
R.attr.customImageButtonStyle); // defStyleAttr
The issue with this is that the only way to change the style of each ImageButton would be by applying a style to this attribute in a parent theme. But I would like to be able to set a default style, without having to manually set this attribute for each project that uses this library.
There is a parameter that does exactly what I am looking for; defStyleRes, which can be used like so:
mImageButton = new ImageButton(
getContext(), // context
null, // attrs
R.attr.customImageButtonStyle, // defStyleAttr
R.style.customImageButtonStyle); // defStyleRes
This parameter is only available at API Level 21 and above, but my projects target API Level 16 and above. So how can I set the defStyleRes, or apply a default style, without access to this parameter?
I applied my style using a ContextThemeWrapper, as suggested by #EugenPechanec, which seems to work well, but each ImageButton now has the default ImageButton background, even though my style applies <item name="android:background">#null</item>.
Here is the style I am using:
<style name="Widget.Custom.Icon" parent="android:Widget">
<item name="android:background">#null</item>
<item name="android:minWidth">56dp</item>
<item name="android:minHeight">48dp</item>
<item name="android:tint">#color/selector_light</item>
</style>
And this is how I am applying it:
ContextThemeWrapper wrapper = new ContextThemeWrapper(getContext(), R.style.Widget_Custom_Icon);
mImageButton = new AppCompatImageButton(wrapper);
On the left is what I am getting, and on the right is what I would like it to look like:
defStyleAttr is for resolving default widget style from theme attribute.
Example: AppCompatCheckBox asks for R.attr.checkBoxStyle. Your theme defines <item name="checkBoxStyle">#style/Widget.AppCompat.CheckBox</item>.
If that attribute is not defined in your theme the widget would pickup its defStyleRes e.g. R.style.Widget_AppCompat_CheckBox.
Note that these are not actual values used by the widget.
I have not seen defStyleRes constructor parameter used outside of the framework. All of these parameters (plus defaults) are however used when asking TypedArray for resources.
How to actually solve your problem
So the four parameter constructor is not available on all platforms. You need to find a way to feed in your default style. Consider a style you'd like to apply:
<style name="MyImageButtonStyle" parent=""> ... </style>
You need a way to convert it to a defStyleAttr parameter. Define the default style on a theme overlay:
<style name="MyImageButtonThemeOverlay" parent="">
<!-- AppCompat widgets don't use the android: prefix. -->
<item name="imageButtonStyle">#style/MyImageButtonStyle</item>
</style>
Now you can create your ImageButton using this theme overlay:
// When creating manually you have to include the AppCompat prefix.
mImageButton = new AppCompatImageButton(
new ContextThemeWrapper(getContext(), R.style.MyImageButtonThemeOverlay)
);
You don't need to specify any other parameters as AppCompatImageButton will pickup R.attr.imageButtonStyle by default.
If that looks hacky you can always inflate your custom view hierarchy or individual widgets from XML where you specified the style="#style/MyImageButtonStyle" attribute.
This question already has answers here:
Set style for TextView programmatically
(13 answers)
Closed 3 years ago.
Here is my style:
<style name="buttonQuestionStyle" parent="#style/Widget.AppCompat.Button.Colored">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#color/white</item>
<item name="android:textSize">16sp</item>
<item name="android:padding">25dp</item>
<item name="android:layout_margin">10dp</item>
<item name="android:background">#color/questionButton</item>
</style>
And here my code:
Button btn = new Button(getActivity());
btn.setText(ojb.getText());
if (Build.VERSION.SDK_INT < 23) {
btn.setTextAppearance(getActivity(), R.style.buttonQuestionStyle);
} else {
btn.setTextAppearance(R.style.buttonQuestionStyle);
}
In the app:
Programmatically button appears like this:
And via layout it worked. Appears like this:
Here is my code in the XML Layout:
<Button
android:text="Question"
style="#style/buttonQuestionStyle" />
So... I dont know why it happens, and how fix it.
You can pass a ContextThemeWrapper in constructor for button and use 3 arguments constructor for Button(context, attributeset, defStyle).
ContextThemeWrapper wrapper = new ContextThemeWrapper(this,R.style.buttonQuestionStyle);
Button btn = new Button(wrapper, null, 0); // note this constructor
btn.setText("some text");
Some info around why you cannot set button's style programmatically, as per the JavaDoc of method setTextAppearance
Sets the text appearance from the specified style resource.
<p>
Use a framework-defined {#code TextAppearance} style like
{#link android.R.style#TextAppearance_Material_Body1 #android:style/TextAppearance.Material.Body1}
or see {#link android.R.styleable#TextAppearance TextAppearance} for the
set of attributes that can be used in a custom style.
#param resId the resource identifier of the style to apply
#attr ref android.R.styleable#TextView_textAppearance
So it deals with only text appearance not other style elements.
Still if you want to apply some style at runtime programmatically you need to
make each and every change separately for example to set background you need to call setBackground and similarly for other cases.
or
Inflate that view programmatically using that particular theme.
I need to run a custom dialog layout using only theme/style options. Running custom Dialog layout by code is not an option for me. I think this should be possible by mean of attributes "android:layout", "android:dialogLayout", "*android:dialogCustomTitleDecorLayout", "*android:dialogTitleIconsDecorLayout", "*android:dialogTitleDecorLayout".<br/><br/>
My Activity onCreate load layout in a Dialog Style:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.MyDialog);
setContentView(R.layout.mydialog);
this.setTitle("A title");
}
style xml:
<style name="MyDialog" parent="android:Theme.Holo.Light.Dialog">
<item name="android:windowTitleStyle">#style/MyDialog.WindowTitle</item>
<item name="android:layout">#layout/dialog_title</item>
<item name="android:dialogLayout">#layout/dialog_title</item>
<item name="*android:dialogCustomTitleDecorLayout">#layout/dialog_title</item>
<item name="*android:dialogTitleIconsDecorLayout">#layout/dialog_title</item>
<item name="*android:dialogTitleDecorLayout">#layout/dialog_title</item>
</style>
<style name="MyDialog.WindowTitle">
<item name="android:maxLines">1</item>
<item name="android:scrollHorizontally">true</item>
<item name="android:textAppearance">#style/TextAppearance_WindowTitle</item>
</style>
<style name="TextAppearance_WindowTitle">
<item name="android:textSize">32sp</item>
<item name="android:textColor">#+color/verdeTI</item>
</style>
Please, note that Text colour of the title is correctly applied (#+color/verdeTI) so I am confident the cascading styling is right but it seems none of the layout options work at all because I continue to see the standard Dialog Layout. My "dialog_title" use a completely different ImageView for divider so I can be sure when it is loaded.
The custom divider is just the main reason because I need a different layout.
Update 15/4/2014
Android theme Guide stats:
Some style properties, however, are not supported by any View element and can only be applied as a theme. These style properties apply to the entire window and not to any type of View. For example, style properties for a theme can hide the application title, hide the status bar, or change the window's background. These kind of style properties do not belong to any View object. To discover these theme-only style properties, look at the R.attr reference for attributes that begin with window. For instance, windowNoTitle and windowBackground are style properties that are effective only when the style is applied as a theme to an Activity or application. See the next section for information about applying a style as a theme.
OK attributes starting with "window" are applied only in Themes not in Styles. What's about *Layout attributes ? When they are applied ?
You can try by passing ThemeName as argument of constructor like this way.
public class TestDialog extends Dialog{
public TestDialog(Context context) {
super(context, R.style.YourTheme);
// TODO Auto-generated constructor stub
}
}
Add window feature if you require.
Make object of this class in any Activity so you can use Dialog property.
:-
More info https://stackoverflow.com/a/18224754/942224
i was using this way. so it may be help you.
You can try by creating your required layout file and opening it with an activity class just in the manifest add this code to your activity
android:theme="#android:style/Theme. Dialog"
But you will be getting title bar in your dialog with this which is your label name for your activity. To remove it add this code before setContentView
requestWindowFeature(Window. FEATURE_NO_TITLE);
Let's say I have the following custom theme declared in themes.xml:
<style name="Theme.Custom.Light" parent="#style/Theme.Sherlock.Light">
<item name="android:actionBarTabStyle">#style/Widget.Custom.Light.ActionBar.TabView</item>
<item name="android:actionBarTabTextStyle">#style/Widget.Custom.Light.ActionBar.TabText</item>
<item name="android:actionMenuTextColor">#color/ab_item_text</item>
<item name="android:actionMenuTextAppearance">#style/TextAppearance.Custom.Light.Widget.ActionBar.Menu</item>
</style>
From the application context, we are able to get the Theme class currently applied using
Theme myTheme = appContext.getTheme();
and also, we are able to get the theme's resource id using:
int themeResId = appContext.getApplicationInfo().theme;
What I want
From my code, I would like to check programmatically which is the parent theme of the theme I'm using in order to differentiate between Sherlock, Sherlock.Light & Sherlock.Light.DarkActionBar.
In the example above, I would like to know that I am using the Light variation of the Sherlock theme.
Note: You may wonder why I need to check the parent if I declared it in the xml. Reason is that I'm in a particular situation in which I actually won't know, but this goes beyond the scope of this question.
Theme myTheme = appContext.getTheme();
You can get its parent class using
Theme myThemeParent = appContext.getTheme().getClass().getSuperclass();
and compare it with Sherlock.getclass() to verify if it is the parent. Likewise for other comparisons.
I have to have an EditText in my application with a white background. I did this in my theme.xml file
<style name="myEditText" parent="#android:style/Widget.EditText">
<item name="android:background">#ffffffff</item>
<item name="android:textColor">#ff000000</item>
</style>
The problem now is that the cursor is still white and therefore not visible.
I did some googling and found this question here on StackOverflow:
Set EditText cursor color
The way it's done there is the android:textCursorDrawable key. But this key does seem to be only available with a 3.2 target. But our clients wants a 3.0 target and I could not find any other solution...
Is there any way i can change the color of the blinking cursor with 3.0 as the target?
Thanks for helping :)
I found the answer :)
I've set the Theme's editText style to:
<item name="android:editTextStyle">#style/myEditText</item>
Then I've used the following drawable to set the cursor:
<style name="myEditText" parent="#android:style/Widget.Holo.Light.EditText">
<item name="android:background">#android:drawable/editbox_background_normal</item>
<item name="android:textCursorDrawable">#android:drawable/my_cursor_drawable</item>
<item name="android:height">40sp</item> </style>
android:textCursorDrawable is the key here.
And also refer this one
Vertical line using XML drawable
I was trying to change the cursor color in my app which targeted API 8. I've found out that TextView uses textColor property as the cursor color. Here's a part of onDraw() defined in TextView API 8:
int color = mCurTextColor;
if (mLayout == null) {
assumeLayout();
}
Layout layout = mLayout;
int cursorcolor = color;
The cursorcolor is then used to constract an android.graphics.Path object representing the color.
If you need to change this behaviour, you're up to quite a task, you'll have to implement your own TextView.