【问题标题】: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?如何为添加/覆盖基类的默认样式而不是替换它的子类小部件创建自己的默认样式?
【发布时间】:2017-08-04 07:32:26
【问题描述】:

TLDR 版本

我正在继承 Android 的内置小部件,如 TextView、CheckBox 和 RadioButton,并添加一些额外的属性/属性。我还想为我的每个子类指定一个默认样式,以便在使用时预先配置它们。

我的问题是如何定义自己的默认样式,但要将该样式与基类的默认样式合并,而不是直接替换它?

完整版

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

对于名为 MyWidget 的 View 子类,请考虑以下内容:

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>

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

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

如果我不将我的 defStyleAttr 传递给“super”并且只在调用 gainStyledAttributes(处理我的自定义属性)时使用它,那么任何以该样式设置的非自定义属性(如边距、背景、buttonTint等)不会被应用,因为通常处理它们的基类不再知道我的默认样式,所以它回退到基类的默认外观。

解决这个问题的最简单方法当然是通过我的样式的“父”属性将我的默认样式基于 RadioButton 的现有默认样式,然后当我的成为新的默认样式时,这两种样式与我的值混合优先。

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

希望您能够遵循这一点。更好的是,希望你能给我一个答案!

【问题讨论】:

  • 样式可以有父元素。示例:
  • 是的,我已经在扩展 AppCompat 版本。我也知道(并在我的问题中提到)通过样式的父属性基于其他样式。但我不知道如何使用这些基本样式!换句话说,实际放入“父”字段的内容。如果您这样做了,并且可以将其放入答案中,我会将其标记为已接受。

标签: java android subclass android-theme android-styles


【解决方案1】:

问题是我不知道基本控件的默认样式是什么

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

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

  1. 开源您要扩展的任何类,例如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 之类的扩展平台小部件,情况会有所不同。我只会在必要时扩展答案。

【讨论】:

  • 很好的答案,正是我所追求的。为了完整起见,我仍然建议您将其扩展为非 AppCompat 版本。问题本身并不规定一种或另一种方式,因此您的答案在展示所有案例时肯定会很有用。但是,这太棒了!谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2020-03-31
  • 1970-01-01
相关资源
最近更新 更多