【问题标题】:getTheme().applyStyle(...) multiple times without overwriting the previous onegetTheme().applyStyle(...) 多次而不覆盖前一个
【发布时间】:2017-01-21 13:15:13
【问题描述】:

当我多次向 AppTheme 应用额外属性时,它会覆盖前一个属性。这是我正在使用的代码:

MainActivity:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {

    getTheme().applyStyle(R.style.AppTheme_OverlayPrimaryRed);

    // If you change `false` to `true`, the overlay above is overwritten.
    if (false) {
        getTheme().applyStyle(R.style.AppTheme_OverlayAccentRed);
    }

    super.onCreate(savedInstanceState);

    ...
}

AppTheme.OverlayPrimaryRed:

<style name="AppTheme.OverlayPrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

AppTheme.OverlayAccentRed:

<style name="AppTheme.OverlayAccentRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>

有什么办法可以解决这个问题吗?

【问题讨论】:

    标签: android android-activity android-xml android-theme android-styles


    【解决方案1】:

    您的样式定义AppTheme.OverlayPrimaryRedAppTheme.OverlayAccentRed 隐式继承自AppTheme。由于AppTheme 可能还包含colorPrimarycolorPrimaryDark 的定义,第二个applyStyle 语句也将设置这些属性,撤消第一个applyStyle 调用。

    因此,在我对this question 的回答中,我没有在样式覆盖名称中使用任何点。

    如果您出于美学原因想要保留点,您可以为叠加定义一个空的父样式,如下所示:

    <style name="Overlay">
    </style>
    
    <style name="Overlay.PrimaryRed">
        <item name="colorPrimary">@color/material_red_500</item>
        <item name="colorPrimaryDark">@color/material_red_700</item>
    </style>
    
    <style name="Overlay.AccentRed">
        <item name="colorAccent">@color/material_red_A200</item>
    </style>
    

    【讨论】:

    • 太棒了,不知道这种隐含的主题扩展存在。这解决了我在使用applyStyle时flags消失的问题,比如android:windowDrawsSystemBarBackgrounds, android:statusBarColor等。
    • 我一整天都在用头撞墙,直到我找到了这个。谢谢!
    【解决方案2】:

    编辑 2:这是一次失败的尝试,再次应用样式会删除以前通过编程设置的样式。

    Android 中的每个样式都可以有父样式。因此,子样式将继承其父样式并应用自己的样式。此外,子级可以覆盖其父级的样式或属性。

    <!-- This is a parent style -->
    <style name="AppTheme.OverlayPrimaryRed">
        <item name="colorPrimary">@color/material_red_500</item>
        <item name="colorPrimaryDark">@color/material_red_700</item>
    </style>
    
    <!-- This is a child of above style -->
    <style name="AppTheme.OverlayAccentRed" parent="AppTheme.OverlayPrimaryRed">
        <item name="colorAccent">@color/material_red_A200</item>
    </style>
    

    在 Android 开发者资源中阅读 Defining Styles。另外,如果你不想使用parent 属性:

    如果你想继承你自己定义的样式,你不必使用 parent 属性。相反,只需将要继承的样式名称作为新样式名称的前缀,用句点分隔。例如,要创建一个继承 MyTextStyle 定义的样式的新样式,但将颜色设为红色,您可以这样创作新样式:

    <style name="MyTextStyle">
        <item name="android:textAllCaps">false</item>
        <item name="android:textColor">#FFFFFF</item>  <!-- white text (default) -->
        <item name="android:textStyle">bold</item>
        <item name="android:textSize">12dp</item>
    </style>
    
    <!-- red text -->
    <style name="MyTextStyle.RED">
        <item name="android:textColor">#FF0000</item>
    </style>
    
    <!-- green text -->
    <style name="MyTextStyle.GREEN">
        <item name="android:textColor">#00FF00</item>
    </style>
    
    <!-- blue text -->
    <style name="MyTextStyle.BLUE">
        <item name="android:textColor">#0000FF</item>
    </style>
    

    注意标签中没有父属性,但是因为name属性以MyTextStyle样式名称开头(这是您创建的样式),所以该样式继承了该样式的所有样式属性。此样式可以覆盖android:textColor 属性以使文本变为红色。您可以将此新样式引用为@style/MyTextStyle.RED

    您可以通过将名称与句点链接起来,继续进行多次这样的继承。例如,您可以将MyTextStyle.RED 扩展为更大,使用:

    <style name="MyTextStyle.RED.Big">
        <item name="android:textSize">30sp</item>
    </style>
    

    编辑 1:

    <!-- this is your root style -->
    <style name="AppTheme.Overlay">
        <!-- default styles for primary, primaryDark (you can add accent too) -->
    </style>
    
    <!-- 1. add Custom Primary Color to root style -->
    <style name="AppTheme.Overlay.PrimaryRed">
        <item name="colorPrimary">@color/material_red_500</item>
        <item name="colorPrimaryDark">@color/material_red_700</item>
    </style>
    
    <!-- 1. add Custom Accent Color to root style -->    
    <style name="AppTheme.Overlay.AccentRed">
        <item name="colorAccent">@color/material_red_A200</item>
    </style>
    
    <!-- 2. add Custom Primary Color to root style -->
    <style name="AppTheme.Overlay.PrimaryBlue">
        <item name="colorPrimary">@color/material_blue_500</item>
        <item name="colorPrimaryDark">@color/material_blue_700</item>
    </style>
    
    <!-- 2. add Custom Accent Color to root style -->    
    <style name="AppTheme.Overlay.AccentBlue">
        <item name="colorAccent">@color/material_blue_A200</item>
    </style>
    
    <!-- add 10 for each...... -->
    

    为您的主色制作 10 种样式,为您的强调色制作 10 种样式。

    然后,在您的代码中:

    // if root style has some styles to add (default)
    getTheme().applyStyle(R.style.AppTheme_Overlay);
    
    // first color selection
    getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryRed);
    getTheme().applyStyle(R.style.AppTheme_Overlay_AccentRed);
    
    // when you want blue color
    getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryBlue);
    getTheme().applyStyle(R.style.AppTheme_Overlay_AccentBlue);
    
    // when you want bluePrimary, but redAccent color (bad choice)
    getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryBlue);
    getTheme().applyStyle(R.style.AppTheme_Overlay_AccentRed);
    

    在这里,AppTheme_Overlay_PrimaryBlue 将覆盖 AppTheme_Overlay_PrimaryRed。等等。

    您刚刚添加了一种根样式、十种原色样式和十种强调色样式 = 21 种样式。

    【讨论】:

    • 感谢您的详细解答。在我的应用程序中,我想要一个更改“主要(深色)颜色”和“强调色”的选项。对于 10 种颜色,这是:10 + 10 = 20 个可能的叠加主题。您的方法有 10 * 10 = 100 个可能的叠加主题。这在styles.xml 中有很多内容。你明白这一点还是想让我更详细地解释一下?
    • 在回复你之前我才知道这一点。请检查我的编辑。如果它仍然没有回答您的问题,let us continue our discussion in this room,请告诉我我错过了什么?
    【解决方案3】:

    应用样式

    textInputStyle = R.style.TextInputFilled;
    recreate();
    

    在活动销毁之前保存样式:

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("textInputStyle", textInputStyle);
    }
    

    在活动创建时应用样式:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            textInputStyle = savedInstanceState.getInt("textInputStyle", 
            R.style.TextInputFilled);
        }
        getTheme().applyStyle(textInputStyle, true);
        setContentView(R.layout.act_text_field);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-05
      • 2013-03-15
      • 2019-09-20
      • 1970-01-01
      • 1970-01-01
      • 2015-12-04
      • 1970-01-01
      • 2015-01-12
      相关资源
      最近更新 更多