【问题标题】:How to apply Theme-Specific Styles?如何应用主题特定样式?
【发布时间】:2012-05-28 06:03:50
【问题描述】:

在这里搜索了几个小时并测试了这个和那个之后,我既不能解决我的问题,也不能在这里找到任何适用于我的问题的问题/答案 - 但也许我只使用了错误的搜索词 - 所以我很感激对于正确方向的任何提示!

基本上它是关于使用 2 个主题(深色和浅色)的应用程序,其中一些 TextView 显示状态 - 状态可以是打开或关闭,为了更好地识别状态,文本的颜色应该反映状态:红色为关闭,绿色为开启。

当我没有使用任何主题或样式时,我只是将 TextView 的 .setColor(#ffff0000) 用于红色,等等......

然后我开始使用深色/浅色主题在不同情况下获得更好的可见性 - 例如。户外白色背景上的黑色文本更易于阅读。

因此我定义了我的 2 个主题,覆盖了 textAppearance:

<style name="Theme.MyApp" parent="Theme.Sherlock">
...
<item name="android:textAppearance">@style/TextNormal</item>
...
</style>

<style name="Theme.MyApp.Light" parent="Theme.Sherlock.Light">
...
 <item name="android:textAppearance">@style/TextNormalLight</item>
...

<style name="TextNormal">
    <item name="android:textColor">#ffffffff</item>
</style>

<style name="TextNormalLight">
    <item name="android:textColor">#ff000000</item>
</style>

这很好用,“正常”文本视图会根据主题以正确的颜色显示。到目前为止一切顺利!

我没有使用 TextView 的 setColor,而是改用 .setTextAppearance tv.setTextAppearance(getSherlockActivity(), R.style.TextRed);

并定义了一些样式(只粘贴一个,其他是TextGreen,...):

<style name="TextRed">
    <item name="android:textColor">#ffff0000</item>
</style>

这也很好用!

终于解决了我的问题:

现在我想根据主题为“红色”设置不同的颜色...

所以我保留了 TextRed 样式,并添加了一个在 Light 主题中使用的样式,为了测试,我只是做了一个奇怪的颜色来看看它是否有效:

<style name="TextRedLight">
    <item name="android:textColor">#ffffff00</item>
</style>

如果我在 TextView 的 .setTextAppearance 周围放置一个 switch 语句,并根据所选主题选择正确的样式 - 伪代码,这也有效:

switch (currentheme) {
   case Dark: tv.setTextAppearance(... R.style.TextRed); break;
   case Light: tv.setTextAppearance(... R.style.TextRedLight); break;
}

现在的挑战/问题是 - 我怎样才能避免 switch 语句?

在 layout.xml 文件中引用样式时,我们可以使用 ?引用当前主题...(而不是“@”)

在这种情况下,我需要在运行时设置样式并且尊重主题:所以它必须通过代码而不是 xml 来完成 - 但是 setTextAppearance 只接受一个 id样式,而不是主题通配符 + id...

这是我卡住的地方...是的,我可以围绕这个包装一个类并将其保留在代码中的一行并“隐藏”该类中的主题检测/切换语句,但另一方面手 - Android 复杂的样式/主题架构也应该有解决这个问题的方法,不是吗...?

只要需要帮助类或 switch/if 语句来完成一些增强的事情,使用主题和样式似乎有点无意义......

感谢任何提示/想法!!!

编辑 1 - 在 Tomáš 回答之后: 更新了 style.xml:

<style name="TextNormal" parent="Theme.ARMoDroid">
    <item name="android:textColor">#ffffffff</item>
</style>
 <style name="TextNormal" parent="Theme.ARMoDroid.Light">
    <item name="android:textColor">#ff000000</item>
</style>
<style name="TextRed" parent="Theme.ARMoDroid">
    <item name="android:textColor">#ffff0000</item>
</style>
 <style name="TextRed" parent="Theme.ARMoDroid.Light">
    <item name="android:textColor">#ffffff00</item>
</style>

在 layout.xml 中分配了 TextNormal 的 TextView,或者当从两个主题中引用 TextNormal 时:

<item name="android:textAppearance">@style/TextNormal</item>

像以前一样工作(使用这种不同的方法),在使用红色文本时也是如此。

但最初的问题仍然存在: 当我想(在运行时)将文本的颜色更改为红色时,使用

tv.setTextAppearance(getActivity(),R.style.TextRed)

它总是使用 TextRed 的最后一个定义 - 因此使用上面的定义,文本将被着色为 #ffffff00 -> 黄色。当我交换 2 个 TextRed 定义的顺序时,它使用最后一个定义 - #ffff0000 - 并且文本是红色的。

所以在运行时设置样式时,setTextAppearance 不支持主题 - 它不区分当前主题和 2 个定义的样式。

我们可以根据主题定义一种具有不同文本颜色值的样式,并根据所选主题正确着色 - 只要它的样式在 layout.xml 中指定,或者主题集的默认样式为此样式.

但是在运行时在代码中动态切换样式时,我们仍然需要类似上面的 switch 语句 - 检测选择了哪个主题,并根据主题,将不同的样式应用于 textview。

我想要实现的是,它应该根据当前主题选择正确的“TextRed”样式。所以不需要对主题意识进行硬编码...一旦添加了新主题,上述开关语句也必须更新...

编辑 2:我目前的“解决方案”

我想我也可以发布当前的解决方案,但这并不是一个很好的解决方案 - 尽管它正在工作 - 但它是每种样式的自定义代码,并且对于另一个主题,它甚至是更多代码......

辅助函数如下所示:

     public static int getThemedStyle(int normalStyle) {
     if (prefs==null) { prefs = PreferenceManager.getDefaultSharedPreferences(appContext); }
     int theme = Integer.valueOf(prefs.getString("GUI_Theme","0"));
     if (theme==0) return normalStyle; //dark theme
     else { //return correct  Light-Theme Style
         switch (normalStyle) {
            case R.style.TextNormal: return R.style.TextNormalLight;
            case R.style.TextRed: return R.style.TextRedLight;
            case R.style.TextOrange: return R.style.TextOrangeLight;
            case R.style.TextGreen: return R.style.TextGreenLight;
            case R.style.TextYellow: return R.style.TextYellowLight;
            case R.style.TextBlue: return R.style.TextBlueLight;
            default: return normalStyle;
         } //switch
     } //else theme==0
 } //getThemedStyle

在片段中,我通过在 onCreate 上调用上述函数来缓存样式引用:

styleRed = preferences.getThemedStyle(R.style.TextRed);
styleOrange = preferences.getThemedStyle(R.style.TextOrange);
styleGreen = preferences.getThemedStyle(R.style.TextGreen);

最后分配样式使用:

tv.setTextAppearance(getSherlockActivity(), styleRed);

工作,但很复杂,如果这就是它原本的样子,那就太可悲了... ;)

【问题讨论】:

    标签: android styles themes


    【解决方案1】:

    你试过了吗?

    <style name="Theme.MyApp" parent="Theme.Sherlock">
    ...
    </style>
    
    <style name="Theme.MyApp.Light" parent="Theme.Sherlock.Light">
    ...
    </style>
    
    <style name="TextNormal" parent="Theme.MyApp">
        <item name="android:textColor">#ffffffff</item>
    </style>
    
    <style name="TextNormal" parent="Theme.MyApp.Light">
        <item name="android:textColor">#ff000000</item>
    </style>
    

    layout.xml 中的引用为:

    <TextView style="@style/TextNormal" .../>
    

    【讨论】:

    • Tomáš - 感谢您的回答!带着一些希望我尝试了你的想法,但它并没有解决问题 - 为了更好的可读性,我已经编辑/添加了结果到上面的问题。只要样式分配是静态的(通过layout.xml),您的方法就很好并且可以工作(就像我的一样),但是在更改每个代码的样式时它会失败(就像我的一样):(
    【解决方案2】:

    回答我自己的问题:

    found this

    所以代替我的 - 工作 - switchstatement,仍然需要一些代码,但至少不需要对主题 ID 进行硬编码,... -> 用这个 sn-p 更新了我的 getThemedStyle

    public static int getThemedStyle(int normalStyle) {
     Resources.Theme theme = appContext.getTheme();
     TypedValue styleID = new TypedValue();
     if (theme.resolveAttribute(R.attr.TextAppRed, styleID, true)) return styleID.data;
      else return normalStyle;
    } //getThemedStyle
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多