避免 android 样式中的重复代码

Avoiding duplicated code in android styles

我有一个 Android 应用程序支持 api 14 和目标 api 21。我有一些样式需要被 api 21 覆盖。什么发生的是我需要复制所有样式项目只是为了改变一个项目。

例如:

<!-- values/styles.xml -->

<style name="Widget.HelloWorld.Button">
    <item name="android:textSize">24sp</item>
    <item name="android:drawableLeft">@android:drawable/ic_menu_delete</item>
</style>

如果我只想覆盖 api 21 中的属性 android:textSize,我还需要复制项目 android:drawableLeft

所以为了避免这种情况,我想出了一个解决方案。在这个例子中,我有三个按钮(foobarfancy)以及一些样式(Widget.HelloWorld.Button.FooWidget.HelloWorld.Button.BarWidget.HelloWorld.Button.Fancy

<!-- values/styles.xml -->

<resources>
    <style name="v0.Widget.HelloWorld.Button" parent="Widget.AppCompat.Button">
        <item name="android:textSize">24sp</item>
        <item name="android:drawableLeft">@android:drawable/ic_menu_delete</item>
    </style>

    <style name="v0.Widget.HelloWorld.Button.Foo" parent="Widget.HelloWorld.Button">
        <item name="android:textColor">#f00</item>
    </style>

    <style name="v0.Widget.HelloWorld.Button.Bar" parent="Widget.HelloWorld.Button">
        <item name="android:textColor">#ff0</item>
    </style>

    <style name="v0.Widget.HelloWorld.Button.Fancy" parent="Widget.HelloWorld.Button">
        <item name="android:textColor">#f0f</item>
    </style>

    <!-- Alias -->
    <style name="Widget.HelloWorld.Button" parent="v0.Widget.HelloWorld.Button" />
    <style name="Widget.HelloWorld.Button.Foo" parent="v0.Widget.HelloWorld.Button.Foo" />
    <style name="Widget.HelloWorld.Button.Bar" parent="v0.Widget.HelloWorld.Button.Bar" />
    <style name="Widget.HelloWorld.Button.Fancy" parent="v0.Widget.HelloWorld.Button.Fancy" />
</resources>

我已经在所有样式名称前加上会产生影响的 api 的版本号。由于 values/styles.xml 是默认值,我在前面加上 v0.

现在,在 values-v21/styles.xml 中,我可以只覆盖我想要的项目,而无需重复代码。

<!-- values-v21/styles.xml -->

<resources>
    <style name="v21.Widget.HelloWorld.Button" parent="v0.Widget.HelloWorld.Button">
        <item name="android:textSize">36sp</item>
    </style>

    <style name="v21.Widget.HelloWorld.Button.Fancy" parent="v0.Widget.HelloWorld.Button.Fancy">
        <item name="android:colorPrimary">@color/primary</item>
    </style>

    <!-- Alias -->
    <style name="Widget.HelloWorld.Button" parent="v21.Widget.HelloWorld.Button" />
    <style name="Widget.HelloWorld.Button.Fancy" parent="v21.Widget.HelloWorld.Button.Fancy" />
</resources>

我想知道这种方法的缺点是什么。

您可以使用打开版本限定符的维度资源修复原始重复问题,然后在样式中引用它:

<!-- values/dimens.xml -->
<resource>
    <dimen name="hello_text_size">24sp</dimen>
</resource>

<!-- values-v21/dimens.xml -->
<resource>
    <dimen name="hello_text_size">36sp</dimen>
</resource>

<!-- values/styles.xml -->
<style name="Widget.HelloWorld.Button">
    <item name="android:textSize">@dimen/hello_text_size</item>
    <item name="android:drawableLeft">@android:drawable/ic_menu_delete</item>
</style>

正如@DanielLew 回答的那样,仅覆盖xml 值文件中的dimen/color/drawable 值是为不同Android 版本或更改某些样式项目的最佳方式屏幕尺寸。

当您必须覆盖新 Android 版本以使用新视图 属性(android:layout_marginStart for v17)时,样式变得更加复杂且难以支持。在这种情况下,我建议 提取基本样式 并将其用作默认值和新版本值(例如 v17)文件夹中样式的父级。

<!-- values/dimens.xml -->
<resource>
    <dimen name="button_text_size">24sp</dimen>
    <dimen name="margin_size">10dp</dimen>
</resource>

<!-- values/styles.xml -->
<resources>
    <!-- Parent style - add all common properties -->
    <style name="Widget.HelloWorld.Button" parent="Widget.AppCompat.Button">
        <item name="android:textSize">@dimen/button_text_size</item>
        <item name="android:drawableLeft">@android:drawable/ic_menu_delete</item>
    </style>

    <!-- Child style - add version specific properties (minimum version) -->
    <style name="Widget.HelloWorld.Button.Foo">
        <item name="android:layout_marginLeft">@dimen/margin_size</item>
    </style>
<resources>

<!-- values-v17/styles.xml - minimum version for the new property -->
<resources>
    <!-- Child style - add version specific properties (v17) -->
    <style name="Widget.HelloWorld.Button.Foo">
        <item name="android:layout_marginStart">@dimen/margin_size</item>
    </style>
<resources>

请阅读Styling Views on Android。 您两次(显式和隐式)设置了父级,这增加了额外的混乱。阅读 link 中的 Implicit vs. Explicit Parenting 部分。