API 级别 21 之前的默认样式资源

Default Style Resource pre API Level 21

我想创建一个自定义 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);

左边是我得到的,右边是我想要的样子:

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


如果这看起来很老套,您始终可以从 XML 指定 style="@style/MyImageButtonStyle" 属性的地方扩展您的自定义视图层次结构或单个小部件。