API 级别 21 之前的默认样式资源
Posted
技术标签:
【中文标题】API 级别 21 之前的默认样式资源【英文标题】:Default Style Resource pre API Level 21 【发布时间】:2017-07-31 01:32:07 【问题描述】:我希望创建一个自定义 ViewGroup
以在库中使用;其中包含一些 ImageButton
对象。我希望能够为每个ImageButton
应用一个样式;但我无法弄清楚如何以编程方式应用样式,除非将属性资源应用于defStyleAttr
参数;像这样:
mImageButton = new ImageButton(
getContext(), // context
null, // attrs
R.attr.customImageButtonStyle); // defStyleAttr
问题在于,更改每个ImageButton
样式的唯一方法是将样式应用于父主题中的此属性。但我希望能够设置默认样式,而不必为使用此库的每个项目手动设置此属性。
有一个参数完全符合我的要求; defStyleRes
,可以这样使用:
mImageButton = new ImageButton(
getContext(), // context
null, // attrs
R.attr.customImageButtonStyle, // defStyleAttr
R.style.customImageButtonStyle); // defStyleRes
此参数仅适用于 API 级别 21 及以上,但我的项目针对 API 级别 16 及以上。那么如何设置defStyleRes
,或者应用默认样式,而不访问这个参数呢?
按照@EugenPechanec 的建议,我使用ContextThemeWrapper
应用了我的样式,这似乎效果很好,但是每个ImageButton
现在都有默认的ImageButton
背景,即使我的样式应用了<item name="android:background">@null</item>
。
这是我使用的样式:
<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>
这就是我的应用方式:
ContextThemeWrapper wrapper = new ContextThemeWrapper(getContext(), R.style.Widget_Custom_Icon);
mImageButton = new AppCompatImageButton(wrapper);
左边是我得到的,右边是我想要的样子:
【问题讨论】:
【参考方案1】:defStyleAttr
用于从主题属性解析默认小部件样式。
示例:AppCompatCheckBox
请求 R.attr.checkBoxStyle
。您的主题定义了<item name="checkBoxStyle">@style/Widget.AppCompat.CheckBox</item>
。
如果您的主题中未定义该属性,小部件将获取其defStyleRes
,例如R.style.Widget_AppCompat_CheckBox
.
请注意,这些不是小部件使用的实际值。
我没有看到在框架之外使用defStyleRes
构造函数参数。但是,在向TypedArray
询问资源时,会使用所有这些参数(加上默认值)。
如何真正解决您的问题
所以四参数构造函数并不是在所有平台上都可用。您需要找到一种方法来输入您的默认样式。考虑一下您要应用的样式:
<style name="MyImageButtonStyle" parent=""> ... </style>
您需要一种将其转换为defStyleAttr
参数的方法。在主题叠加层上定义默认样式:
<style name="MyImageButtonThemeOverlay" parent="">
<!-- AppCompat widgets don't use the android: prefix. -->
<item name="imageButtonStyle">@style/MyImageButtonStyle</item>
</style>
现在您可以使用此主题叠加创建您的ImageButton
:
// When creating manually you have to include the AppCompat prefix.
mImageButton = new AppCompatImageButton(
new ContextThemeWrapper(getContext(), R.style.MyImageButtonThemeOverlay)
);
您不需要指定任何其他参数,因为AppCompatImageButton
默认会拾取R.attr.imageButtonStyle
。
如果这看起来很麻烦,您可以随时从您指定 style="@style/MyImageButtonStyle"
属性的 XML 中扩充您的自定义视图层次结构或单个小部件。
【讨论】:
ContextThemeWrapper
似乎是正确的方法。我以前遇到过它,但它完全不在我的脑海里。不幸的是,它引起了另一个问题;出于某种原因,它在每个ImageButton
上添加了一个背景资源。我可以通过设置mImageButton.setBackgroundResource(0)
在事后删除背景,但我不能在我的样式资源中使用<item name="android:background">@null</item>
执行此操作,即使我可以更改其他属性。知道是什么原因造成的吗?
@Bryan 好的,请在您的问题末尾发布更改内容,我会调查一下。
@Bryan 你混合了风格和主题(主题覆盖)。 不要跳过主题覆盖。 不要将样式资源 ID 与 ContextThemeWrapper 一起使用。不要在主题中定义样式属性,反之亦然。这可能会帮助你chris.banes.me/2014/11/12/theme-vs-style
啊,我明白了,谢谢。不过,我不能动态应用样式,所以如果 ContextThemeWrapper
将 theme 应用于 ImageButton
;除了在主题覆盖中这样做之外,还有一种方法可以在创建时将 style 应用于ImageButton
?
@Bryan 在这种情况下,这种方法(一组相应的主题覆盖和样式)可能不是最佳选择。您可能希望在 Java 中的构造函数之后设置小部件的样式。以上是关于API 级别 21 之前的默认样式资源的主要内容,如果未能解决你的问题,请参考以下文章
如何为 google map api v2 设置默认位置和缩放级别?
camera2(API 级别 21)是不是暴露了所有旧摄像头?