如何为添加 to/overrides 基础 class 的默认样式而不是替换它的子classed 小部件创建自己的默认样式?

How can you create your own default style for a subclassed widget that adds to/overrides the base class's default style, not replaces it?

TLDR 版本

我正在使用 classing Android 的内置小部件,如 TextView、CheckBox 和 RadioButton,并且正在添加一些额外的 properties/attributes。我还想为我的每个子 class 指定一个默认样式,这样我就可以在使用时预先配置它们。

我的问题是如何定义我自己的默认样式,但该样式是否与 base-class 的默认样式合并,而不是完全替换它?

完整版

我一直在遵循使用以下推荐技术为我们的应用程序的自定义小部件设置主题的最佳实践。

为名为 MyWidget 的视图子class考虑以下内容:

MyWidget.java

public class MyWidget extends View
{
    public MyWidget(Context context)
    {
        this(context, null);
    }

    public MyWidget(Context context, AttributeSet attrs)
    {
        super(context, attrs, R.attr.myWidgetStyle);

        TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MyWidget, R.attr.myWidgetStyle, 0);

        // Only need to read custom attributes here
        // Others are handled in the base class

        styledAttrs.recycle();
    }
}

在attrs.xml

<!-- Attribute to hold the default style -->
<attr name="myWidgetStyle" format="reference" />

<!-- Assigning attributes to controls -->
<declare-styleable name="MyWidget">
    <attr name="isRealTime" format="boolean" />
</declare-styleable>

在styles.xml

<style name="MyTheme">

    <!-- Store default style in the style-reference attributes -->
    <item name="myWidgetStyle">@style/MyWidget</item>

</style>

<style name="MyWidget">
    <item name="background">@color/someColorResource</item>
    <item name="isRealTime">true</item>
</style>

一切都按预期工作,我的控件采用指定的默认样式。

当我没有subclassing View,而是subclass RadioButton 之类的东西时,问题就出现了。以此为例,由于我在构造函数中对 'super' 的调用中手动指定了 defStyleAttr,因此我的样式完全替换了默认样式,我失去了 RadioButton 的默认外观并且点没有出现, 只是文字。

如果我不将我的 defStyleAttr 传递给 'super' 并且仅在调用 obtainStyledAttributes 时使用它(以处理我的自定义属性),那么任何非自定义属性设置为该样式(如边距, background, buttonTint, 等等)没有得到应用,因​​为通常处理它们的基础 class,不再知道我的默认样式,所以它回到基础 class 的默认外观。

解决这个问题的最简单方法当然是通过我的样式 'parent' 属性 将我的默认样式基于 RadioButton 现有的默认样式,然后当我的成为新的默认样式时,就是这两种样式优先考虑我的价值观。

问题是我不知道基本控件(本例中的 RadioButton)的默认样式是什么,因为我不知道他们使用哪个属性来保存它(它是 supposed 是 radioButtonStyle 但这没有用),即使我确实知道该属性,那也不是我需要的。我需要它指向的样式。 (我也试过 ?someAttr 和 ?attr/someAttr' 但都没有用。)

希望您能够理解。更好的是,希望你能给我一个答案!

The problem there is I don't know what the default style is for the base control

AppCompat 提供的小部件及其默认样式遵循命名约定。示例:AppCompatEditText 默认样式由 ?editTextStyle 主题属性控制,该属性默认指向 @style/Widget.AppCompat.EditText.

大多数时候您可以猜出正确的名称(IDE 会帮助您),但如果您正在寻找 "correct" 确定样式的方法,请按照以下步骤操作:

  1. 你正在扩展的任何 class 的开源,比如 AppCompatEditText
  2. 查看其双参数构造函数。它调用三参数构造函数,第三个参数是默认样式 主题属性 。在这种情况下 R.attr.editTextStyle.
  3. 从 appcompat-v7 库中打开 values.xml 并找到 Theme.AppCompat 定义。它将包含所有默认样式。查找主题属性引用的具体样式。

看起来像这样:

<style name="Theme.AppCompat" parent="@style/Base.Theme.AppCompat">
    <item name="editTextStyle">@style/Widget.AppCompat.EditText</item>
    <!-- Other styles... -->
</style>
  1. 定义你自己的风格...

...作为您找到的样式的扩展。

<style name="Widget.VeryCustomEditText" parent="@style/Widget.AppCompat.EditText">

如果您直接扩展了 EditText 等平台小部件,情况会有所不同。我只会在必要时扩展答案。