【问题标题】:Where to put XML styles放置 XML 样式的位置
【发布时间】:2018-01-25 15:27:06
【问题描述】:

问题 1

我希望所有Toolbar 看起来都一样,而不是在所有它们中设置样式, 所以我虽然我会为它设置应用程序主题。我希望他们拥有的一件事是colorControlNormal 属性。这些是我的尝试:

代码示例 1

<resources>
    <style name="MyTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="toolbarStyle">@style/MyTheme.ToolbarStyle</item>
    </style>

    <style name="MyTheme.ToolbarStyle" parent="@style/Widget.AppCompat.Toolbar">
        <item name="colorControlNormal">@color/toolbarColorControlNormal</item>
    </style>
</resources>

代码示例 2

<resources>
    <style name="MyTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorControlNormal">@color/toolbarColorControlNormal</item>
    </style>
</resources>

代码示例1中,我尝试为Toolbar 属性创建自定义样式,并将其设置为主题,但没有成功。

代码示例 2 中,我在全局范围内设置了属性并正常工作。但是,也会影响其他组件,所以它是无效的。

  • 为什么 代码示例 1 不起作用?

问题 2

我需要更改所有TabLayouttabTextColortabSelectedTextColor属性,所以我尝试了这个:

代码示例 3

<resources>
  <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:tabWidgetStyle">@style/TabsStyle</item>
  </style>

  <style name="TabsStyle" parent="Widget.Design.TabLayout">
    <item name="tabTextColor">@color/tabTextColor</item>
    <item name="tabSelectedTextColor">@color/tabSelectedTextColor</item>
  </style>
</resources>

但它不起作用,我让它工作的唯一方法是在 XML 中手动设置它们:

<android.support.design.widget.TabLayout
    [...]
    android:background="?android:attr/colorPrimary"
    app:tabTextColor="@color/tabTextColor"
    app:tabSelectedTextColor="@color/tabSelectedTextColor" />
  • 为什么代码示例 3 不起作用?

最后,我会赞成任何对良好风格和主题指南/书籍的引用。在这方面我真的需要改进。

提前致谢。

【问题讨论】:

  • 是否在 AndroidManifes 中设置了主题?
  • @fisher3421 如果我不这样做,第二个代码示例就不会工作。
  • 我强烈推荐 github 中的Android-Material-Themes-Demo。通过实践学习。 README.md 中关于样式和主题的精彩概述。
  • 你在使用TabHostTabWidget吗? tabWidgetStyle 适用于这些控件,而不适用于 TabLayout,它看起来不像其他小部件那样具有默认值。如果你能澄清这一点,这将有助于给出答案。有关tabWidgetStyle 属性的使用,请参阅here

标签: android android-toolbar android-theme android-styles


【解决方案1】:

Toolbar中的后退箭头全局指定颜色

这并不像应该的那么简单,但请尝试以下操作:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- style the back arrow -->
    <item name="toolbarNavigationButtonStyle">@style/NavButtonStyle</item>
</style>

<style name="NavButtonStyle" parent="@style/Widget.AppCompat.Toolbar.Button.Navigation">
    <item name="android:tint">#FF0000</item>
</style>

android:tint 会改变后退箭头的颜色。

通常,默认工具栏样式由属性toolbarStyle 设置。在下面的 XML 中,它设置为 @style/MyToolbarStyleMyToolbarStyle 定义了三个属性,将用于应用程序中的所有工具栏。这是一个样子:

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="toolbarStyle">@style/MyToolbarStyle</item>
        <item name="titleTextColor">@android:color/holo_red_light</item>
    </style>

    <style name="MyToolbarStyle" parent="@style/Widget.AppCompat.Toolbar">
        <item name="titleTextColor">@android:color/white</item>
        <item name="subtitleTextColor">@android:color/holo_green_light</item>
        <item name="android:background">@color/vermillion</item>
    </style>
</resources>

如您所见,MyToolbarStyle 设置了三个属性的值。不幸的是,这种方法不适用于所有属性,例如 colorControlNormal,如果在主题中指定,则会更改后退箭头的颜色。


关于TabLayout的问题:

没有很好的解决方案来为TabLayout 全局定义属性。您可以执行this 之类的操作,然后覆盖Widget.Design.TabLayout,但您必须重新创建在那里定义的所有属性,并且这些属性可能会根据正在运行的版本而改变。这可行,但可能是一个维护问题。我认为这不是一个好的解决方案。

另一种解决方案是创建您自己的自定义TabLayout。这将非常简单,只需将tabTextAppearance 定义为TabLayout 的全局默认属性。整个自定义布局将如下所示:

public class MyTabLayout extends TabLayout {
    public MyTabLayout(Context context, AttributeSet attrs) {
        super(context, attrs, R.attr.tabTextAppearance);
    }
}

将所有对TabLayout 的引用替换为MyTabLayout 后,您将能够在styles.xml 中执行以下操作:

<style name="AppTheme" parent="BaseAppTheme">
    <item name="tabTextAppearance">@style/MyTabStyle</item>
</style>

<style name="MyTabStyle" parent="Widget.Design.TabLayout">
    <item name="tabTextColor">#FF0000</item>
    <item name="tabSelectedTextColor">#00FF00</item>
</style>

这将使标签文本颜色为红色和绿色,但它们可以是您选择的颜色。您现在可以在 XML 中声明 TabLayout 并为其应用默认样式,而无需显式指定样式/主题。

根本问题是TabLayout 的 CTOR 不使用 defStyleResource,它定义了应用于主题中定义的视图的默认样式,而 tabWidgetStyle 不是它......(参见 this .) 自定义布局MyTabLayout 规避了这个问题。但是,这确实引发了一个问题,即是否有原因不使用defStyleResource,也许我们正在潜入一个我们最好避免的荆棘补丁。

这些方法确实有效,但我还没有完全测试过它们。您必须确定是执行此处描述的操作还是简单地逐个视图定义样式更好。

如果有人有一个标准的、Android 批准的方式来全局指定 TabLayout 属性,我会很高兴听到这个消息。


【讨论】:

  • 感谢您的回答。我真的在这里关注一个简​​单的问题,那就是:我为什么要在主题中添加&lt;item name="toolbarStyle"&gt;@style/MyToolbarStyle&lt;/item&gt;,如果它不起作用,除非我用android:theme="@style/MyToolbarStyle 明确设置它?我虽然小部件会从主题中读取属性,但为什么我必须设置两次?不是所有的小部件都可以从主题中读取属性吗?
  • @JonZarate 啊,但你不必添加android:theme="@style/MyToolbarStyle。您在我提供的 XML 中看到了吗?用我提供的 XML 和 java 代码创建一个简单的项目,你就会明白我的意思了。
  • 是的,我明白了,但 colorControlNormal 不起作用。我更新了帖子和问题。
  • @JonZarate 您希望colorControlNormalToolbar 中为您做什么?
  • 更改后退箭头颜色
【解决方案2】:

问题 1

themestyle 之间的区别是微妙的,而且由于您使用 &lt;style&gt; 标记定义它们,所以事情比应有的更加混乱.但即使它们都使用&lt;style&gt; 标签,它们的行为也不同。

在视图的主题 中指定的属性适用于该视图及其所有子视图。在视图的 style 中指定的属性仅适用于该视图。此外,还有一些称为 主题属性 的属性仅在它们是主题的一部分时才有效。 colorControlNormal 是主题属性;将其设置为样式不会有任何效果。

代码示例 1 不起作用,因为您的 &lt;item name="colorControlNormal"&gt; 元素是在样式而不是主题中定义的。

代码示例 2 改变了一切,因为现在 colorControlNormal 在您的应用主题中,因此它适用于您的应用中关心它的所有元素。

不幸的是,我认为没有办法简单地为应用程序中的每个Toolbar 指定一个主题。您必须满足以下条件之一:

1) 使用android:theme 属性

为此,您可以创建如下样式:

<style name="MyToolbarTheme">
    <item name="colorControlNormal">@color/toolbarColorControlNormal</item>
</style>

然后,在每个 &lt;Toolbar&gt; 标签上,您将添加

android:theme="@style/MyToolbarTheme"

2) 创建Toolbar的自定义子类

同样,您需要像上面这样的样式。然后你会创建一个这样的类:

public class MyToolbar extends Toolbar {

    public MyToolbar(Context context, AttributeSet attrs) {
        super(wrapContext(context), attrs);
    }

    private static Context wrapContext(Context context) {
        return new ContextThemeWrapper(context, R.style.MyToolbarTheme);
    }
}

并像这样在你的布局文件中使用它:

<com.example.stackoverflow.MyToolbar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

这通过获取工具栏正在膨胀的Context 实例并将其主题更改为您的自定义工具栏主题来工作。由于这个(包装的)上下文仅用于创建您的自定义工具栏,因此不会影响您应用中的其他视图。

不管怎样,这就是我在我的应用程序中所做的。

问题 2

这里,为什么更简单一点:android:tabWidgetStyleTabWidget 的默认样式,而不是 TabLayout。事实上,我不知道TabLayout 有任何定义的默认样式。

同样,您有两个选择。您可以创建一个样式并将其应用于每个&lt;TabLayout&gt; 标签,或者您可以创建一个自定义子类并使用它来代替TabLayout

public class MyTabLayout extends TabLayout {

    public MyTabLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        int normalColor = ContextCompat.getColor(context, R.color.tabTextColor);
        int selectedColor = ContextCompat.getColor(context, R.color.tabSelectedTextColor);
        setTabTextColors(normalColor, selectedColor);
    }
}

进一步阅读

这是我在学习这些东西时阅读的一些材料:

https://developer.android.com/guide/topics/ui/look-and-feel/themes.html

https://medium.com/google-developers/theming-with-appcompat-1a292b754b35

https://www.androiddesignpatterns.com/2016/08/contextcompat-getcolor-getdrawable.html

【讨论】:

  • 尽管我更喜欢你的答案(更有条理和清晰的点),但另一个答案给出了一个更适合我的解决方案(通过 XML)。我只能给你点赞。谢谢。
  • @JonZarate 不用担心。我不知道toolbarNavigationButtonStyle,所以这对我来说也是一个胜利。
【解决方案3】:

右键res文件夹,选择New-->Android资源文件,为新文件“styles”设置同名,在Available qualifiers中:选择最后一项“Version”,最后设置“Platform API level” 21 .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    • 2012-10-21
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多