如何将支持库Snackbar文本颜色设置为除android:textColor之外的其他颜色?

104

我已经开始使用设计支持库中的新Snackbar,但是我发现当你在主题中定义了"android:textColor"时,它会应用于Snackbar的文本颜色。如果你的主要文本颜色是暗色,这显然是一个问题。

enter image description here

有人知道如何解决这个问题或者有什么建议可以让我的文本变色吗?

2017年1月编辑:(回答后)

虽然有一些自定义解决方案可以解决下面的问题,但最好提供正确的方法来主题化 Snackbar。

首先,你可能根本不应该在主题中定义 android:textColor(除非你真正了解使用主题的范围)。这会设置与你的主题连接的基本上每个视图的文本颜色。如果你想在视图中定义非默认的文本颜色,则使用android:primaryTextColor并在你的自定义视图中引用该属性。

然而,要将主题应用于 Snackbar,请参考第三方材料文档中的这个优质指南:http://www.materialdoc.com/snackbar/ (遵循编程主题实现,使其不依赖于 xml 样式)

供参考:

// create instance
Snackbar snackbar = Snackbar.make(view, text, duration);

// set action button color
snackbar.setActionTextColor(getResources().getColor(R.color.indigo));

// get snackbar view
View snackbarView = snackbar.getView();

// change snackbar text color
int snackbarTextId = android.support.design.R.id.snackbar_text;  
TextView textView = (TextView)snackbarView.findViewById(snackbarTextId);  
textView.setTextColor(getResources().getColor(R.color.indigo));

// change snackbar background
snackbarView.setBackgroundColor(Color.MAGENTA);  

你也可以创建自己的自定义 Snackbar 布局,详见上面的链接。如果这种方法感觉太过 hacky,并且你想要一个确保可靠的方式来让你的自定义 Snackbar 在可能的支持库更新中保持不变,请这样做。此外,查看下面的答案,以了解类似且可能更快地解决问题的方法。

感谢您提供的解决方案!该属性实际上被称为 android:textColorPrimary - muetzenflo
感谢您提供这么详尽的解释。 - Bugs Happen
1
在你的主题中完全不应该定义 android:textColor... 这对我来说是关键,谢谢! - Tyler
24个回答

184

我在《Android Design Support Library 的新特性及如何使用 Snackbar》找到了这个答案。

对于我来说,这个方法可以用来改变 Snackbar 中文本的颜色。

Snackbar snack = Snackbar.make(view, R.string.message, Snackbar.LENGTH_LONG);
View view = snack.getView();
TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
tv.setTextColor(Color.WHITE);
snack.show();
更新:AndroidX: 正如dblackker在评论中指出的那样,使用新的AndroidX支持库,查找Snackbar TextView ID的代码将更改为:
TextView tv = view.findViewById(com.google.android.material.R.id.snackbar_text);
tv.setTextColor(ContextCompat.getColor(requireContext(), R.color.someColor))

2
如果有人正在徒劳地寻找更改Snackbar文本大小的方法,那么这就是它! - Janis Peisenieks
2
你可以使用 snackbar_action 替代 snackbar_text 来处理操作文本。参考这个答案的示例:https://dev59.com/k47ea4cB1Zd3GeqPBnqp#36800101 - Joshua Pinter
7
这个方法最多只能算是一种Hack - 如果android.support.design.R.id.snackbar_text的ID在未来版本中发生改变,会发生什么情况?是否有一种默认的SnackBar样式可以在styles.xml中覆盖? - DiscDev
8
那个ID确实在支持库的未来版本中被更改了,现在我得到了一个空指针。 - CaptainForge
3
更新 - 使用androidx后,id现在如下: snack.view.findViewById(com.google.android.material.R.id.snackbar_text) as TextView 意为:使用androidx之后,Snackbar的ID变为com.google.android.material.R.id.snackbar_text,可通过snack.view.findViewById方法获取Snackbar的视图,再转换为TextView类型。 - dblackker
显示剩余5条评论

41
我知道这个问题已经有答案了,但我发现最简单的方法是在make中直接使用Html.fromHtml方法和一个font标签。
Snackbar.make(view, 
       Html.fromHtml("<font color=\"#ffffff\">Tap to open</font>").show()

3
我更喜欢这个解决方案,因为它只有一行。 - Lahiru Chandima
1
这不是那个问题的实际解决方案。使用:snackbar.setActionTextColor(Color.WHITE).show(); - Ahamadullah Saikat
Snackbar存在/曾经存在一个bug,设置颜色没有任何作用。这种方法可以在任何情况下工作,但可能不是最优解决方案。 - JPM
这需要API级别> 24。 - frank17

18

我创建了这个 Kotlin 扩展函数并在我的项目中使用:

fun Snackbar.setTextColor(color: Int): Snackbar {
    val tv = view.findViewById(com.google.android.material.R.id.snackbar_text) as TextView
    tv.setTextColor(color)

    return this
}

使用方式如您所预期:

Snackbar.make(view, R.string.your_string,Snackbar.LENGTH_LONG).setTextColor(Color.WHITE).show()


喜欢Kotlin扩展方法的简单使用!;-) - Patrick Kuijpers
14
如果您迁移到AndroidX,请使用com.google.android.material.R.id.snackbar_text - Rishabh876
更改了@Rishabh876 :) - Richard

16

好的,所以我通过重新组织文本颜色的方式来解决了这个问题。

在我的浅色主题中,我将android:textColorPrimary设置为我想要的普通深色文本,并将android:textColor设置为白色

我更新了所有文本视图和按钮,使它们具有android:textColor="?android:attr/textColorPrimary"

因此,因为snackbar从textColor中绘制,所以我只需将所有其他文本设置为textColorPrimary即可。

编辑于2017年1月:--------------------------------------------------

正如评论所述,并如上面编辑的原始问题所述,您可能不应该在主题中定义android:textColor,因为这会更改主题内每个视图的文本颜色。


我刚完成了这个任务,呼,花了一段时间!不过,我需要使用下面“m vai”的方法来处理我的古老的首选项活动(使用preferences.xml)。我认为它使我的应用程序的样式更正确地基于主题,这很好。+1 - BrantApps
1
在我看来,这不是一个好的解决方案。我想保留我的实际主题用于TextView,并仅更改Snackbar文本颜色... - issamux
1
你不应该在主题中定义android:textColor。它是TextView样式属性。如果你在主题中定义它,你会覆盖每个TextViewButton的文本颜色,这些控件在XML中没有指定文本颜色。这也适用于Snackbar消息,它通常会从其深色主题叠加层中获取颜色。 - Eugen Pechanec

15
android.support.design.R.id.snackbar_text上进行黑客攻击是不稳定的,更好或不那么hacky的方法是:
String snackText = getResources().getString(YOUR_RESOURCE_ID);
SpannableStringBuilder ssb = new SpannableStringBuilder()
    .append(snackText);
ssb.setSpan(
    new ForegroundColorSpan(Color.WHITE),
    0,
    snackText.length(),
    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Snackbar.make(
        getView(),
        ssb,
        Snackbar.LENGTH_SHORT)
        .show();

12

一种方法是使用span:

final ForegroundColorSpan whiteSpan = new ForegroundColorSpan(ContextCompat.getColor(this, android.R.color.white));
SpannableStringBuilder snackbarText = new SpannableStringBuilder("Hello, I'm white!");
snackbarText.setSpan(whiteSpan, 0, snackbarText.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);

Snackbar.make(view, snackbarText, Snackbar.LENGTH_LONG)
                .show();

使用 Span,您还可以在一个 Snackbar 中添加多种颜色和样式。这是一个不错的指南:

https://androidbycode.wordpress.com/2015/06/06/material-design-snackbar-using-the-design-support-library/


10
如果您已经迁移至AndroidX,请使用com.google.android.material.R.id.snackbar_text代替android.support.design.R.id.snackbar_text来更改Snackbar上文本的颜色。

你应该获得一枚奖章。 - frank17
@frank17,这里有几个评论提到了。 - CoolMind

9

目前(2020年1月),最好的做法是通过覆盖这些样式来实现:

com.google.android.material:material:1.2.0和可能也包括1.1.0

<item name="snackbarStyle">@style/Widget.MaterialComponents.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.MaterialComponents.Snackbar.TextView</item>

如果您使用带有.Bridge结尾的材料主题,则由于某些原因,这两种样式都未被定义。因此,Snackar将使用一些没有这些样式的传统布局。

我在源代码中发现, snackbarButtonStyle snackbarTextViewStyle 都必须定义,否则它将不会被使用。


7
如果你要将你的代码迁移到AndroidX,那么TextView属性现在应该是:
com.google.android.material.R.id.snackbar_text

6

我所看到的唯一方法就是使用getView()并循环遍历其子项。我不知道它是否有效,而且它看起来很糟糕。希望他们能尽快增加一些关于这个问题的API。

Snackbar snack = Snackbar.make(...);
ViewGroup group = (ViewGroup) snack.getView();
for (int i = 0; i < group.getChildCount(); i++) {
    View v = group.getChildAt(i);
    if (v instanceof TextView) {
        TextView t = (TextView) v;
        t.setTextColor(...)
    }
}
snack.show();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接