如何应用主题特定样式?

时间:2012-05-21 18:08:46

标签: android styles themes

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

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

当我没有使用任何主题或样式时,我只使用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;
}

现在的挑战/问题是 - 如何避免切换声明?

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

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

这就是我被卡住的地方...是的,我可以围绕这个包装一个类并将它保持在代码中的一行并“隐藏”此类中的主题检测/开关语句,但另一方面手 - Android的复杂风格/主题架构也应该有解决这个问题的方法,不应该......?

使用主题和样式似乎有点无意义,只要需要helperclasses或switch / if-statements来完成一些增强的东西......

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

编辑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的TextViews,或者在以下两个主题引用TextNormal时使用:

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

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

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

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

它总是使用TextRed的最后一个定义 - 所以在上面的定义中,文本将被着色#ffffff00 - &gt;黄色当我交换2个TextRed定义的顺序时,它使用的是最后一个定义 - #ffff0000 - 并且文本是红色的。

因此,在运行时设置样式时,setTextAppearance不是Theme-Aware - 它不区分当前主题和2个定义的样式。

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

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

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

编辑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);

工作,但很复杂,如果这是它的方式,那很难过......;)

2 个答案:

答案 0 :(得分: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" .../>

答案 1 :(得分:0)

回答我自己的问题:

found this

所以代替我的工作 - 切换声明,仍然需要一些代码,但它至少没有主题ID的硬编码,... - &gt;使用此代码段更新了我的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