问题
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:
回答1:
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.
来源:https://stackoverflow.com/questions/42705945/default-style-resource-pre-api-level-21