How to set support library snackbar text color to something other than android:textColor?

瘦欲@ 提交于 2019-12-02 16:27:35
JPM

I know this has been answered already but the easiest way I found was directly in the make using the Html.fromHtml method and a font tag

Snackbar.make(view, 
       Html.fromHtml("<font color=\"#ffffff\">Tap to open</font>").show()
Jarod Young

I found this at What are the new features of Android Design Support Library and how to use its Snackbar?

This worked for me for changing the text color in a 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();



UPDATE: ANDROIDX: As dblackker points out in the comments, with the new AndroidX support library, code to find the ID of Snackbar TextView changes to:

TextView tv = snack.findViewById(com.google.android.material.R.id.snackbar_text);

Created this kotlin extention function i use in my projects:

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

    return this
}

Usage like you would expect:

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

Hacking on android.support.design.R.id.snackbar_text is fragile, a better or less hacky way to do that will be:

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();

Alright so I fixed it by basically reorganizing the way I do text colors.

In my light theme, I set android:textColorPrimary to the normal dark text I wanted, and I set android:textColor to white.

I updated all of my text views and buttons to have android:textColor="?android:attr/textColorPrimary".

So because snackbar draws from textColor, I just set all of my other text to textColorPrimary.

EDIT JANUARY 2017: ----------------------------------------------------

So as the comments say, and as stated in the edited original question above, you should probably not define android:textColor in your themes, as this changes the text color of every view inside the theme.

One approach is to use spans:

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();

With spans you can also add several colors and styles inside one Snackbar. Here's a nice guide:

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

If you migrated to androidX use com.google.android.material.R.id.snackbar_text instead of android.support.design.R.id.snackbar_text for changing color of text on snackbar.

The only way I see is using getView() and cycling through its child. I don't know if it's going to work, and it is bad as it looks. I hope they'll add some API about this issue soon.

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();

If you will migrate your code to AndroidX, the TextView property is now:

com.google.android.material.R.id.snackbar_text

This is what I use when I need custom colors

    @NonNull
    public static Snackbar makeSnackbar(@NonNull View layout, @NonNull CharSequence  text, int duration, int backgroundColor, int textColor/*, int actionTextColor*/){
        Snackbar snackBarView = Snackbar.make(layout, text, duration);
        snackBarView.getView().setBackgroundColor(backgroundColor);
        //snackBarView.setActionTextColor(actionTextColor);
        TextView tv = (TextView) snackBarView.getView().findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(textColor);
        return snackBarView;
    }

And consumed as:

CustomView.makeSnackbar(view, "Hello", Snackbar.LENGTH_LONG, Color.YELLOW,Color.CYAN).setAction("DO IT", myAction).show();
Pavneet_Singh

I changed my theme

Theme.AppCompat.Light.NoActionBar

to

Theme.AppCompat.NoActionBar 

It worked.Try to use simple theme instead of light or other theme.

If you decide to use the dirty and hacky solution with finding TextView in Snackbar by id and you already migrated to androidx, then here's the code:

val textViewId = com.google.android.material.R.id.snackbar_text
val snackbar = Snackbar.make(view, "Text", Snackbar.LENGTH_SHORT)
val textView = snackbar.view.findViewById(textViewId) as TextView
textView.setTextColor(Color.WHITE)

You can use this library: https://github.com/SandroMachado/restaurant

new Restaurant(MainActivity.this, "Snackbar with custom text color", Snackbar.LENGTH_LONG)
    .setTextColor(Color.GREEN)
    .show();

Disclaimer: I made the library.

Find by id did't work for me so I found another solution:

Snackbar snackbar = Snackbar.make(view, text, duration);//just ordinary creation

ViewGroup snackbarView = (ViewGroup) snackbar.getView();
SnackbarContentLayout contentLayout = (SnackbarContentLayout) snackbarView.getChildAt(0);
TextView tvText = contentLayout.getMessageView();
tvText.setTextColor(/*your color here*/);

//set another colors, show, etc
Summved Jain

I have a simple code that will help to get an instance of both the textview of Snackbar, after that you can call all methods that are applicable on a textview.

Snackbar snackbar = Snackbar.make( ... )    // Create Snack bar


snackbar.setActionTextColor(getResources().getColor(R.color.white));  //if you directly want to apply the color to Action Text

TextView snackbarActionTextView = (TextView) snackbar.getView().findViewById( android.support.design.R.id.snackbar_action );

snackbarActionTextView.setTextColor(Color.RED);  //This is another way of doing it

snackbarActionTextView.setTypeface(snackbarActionTextView.getTypeface(), Typeface.BOLD);

//Below Code is to modify the Text in Snack bar
TextView snackbarTextView = (TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text);
snackbarTextView.setTextSize( 16 );
snackbarTextView.setTextColor(getResources().getColor(R.color.white));

Just to save your precious development time, here is the static method I am using:

public static void snack(View view, String message) {
    if (!TextUtils.isEmpty(message)) {
        Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT);
        snackbar.getView().setBackgroundColor(Color.YELLOW);
        TextView tv =  snackbar.getView().findViewById(android.support.design.R.id.snackbar_text); //snackbar_text
        tv.setTextColor(Color.BLACK);
        snackbar.show();
    }
}

This is how it looks:

If you are in Kotlin, you can create an extension :

fun Snackbar.withTextColor(color: Int): Snackbar {
    val tv = this.view.findViewById(android.support.design.R.id.snackbar_text) as TextView
    tv.setTextColor(color)
    return this
}

Usage :

yourSnackBar.withTextColor(Color.WHITE).show()

As per new AndroidX Jitpack components

implementation 'com.google.android.material:material:1.0.0'

Use this extension which i had created

inline fun View.snack(message: String, length: Int = Snackbar.LENGTH_LONG,
 f: Snackbar.() -> Unit) {
val snack = Snackbar.make(this, message, length)
snack.f()
snack.show()
}

fun Snackbar.action(action: String, actionColor: Int? = null, textColor: Int? = null, listener: (View) -> Unit) {
setAction(action, listener)
actionColor?.let {
    setActionTextColor(it)
    }
textColor?.let {
    this.view.findViewById<TextView>(R.id.snackbar_text).setTextColor(it)
    }
}

Use it like this

btn_login.snack(
        getString(R.string.fields_empty_login),
        ContextCompat.getColor(this@LoginActivity, R.color.whiteColor)
    ) {
        action(getString(R.string.text_ok), ContextCompat.getColor(this@LoginActivity, R.color.gray_300),ContextCompat.getColor(this@LoginActivity, R.color.yellow_400)) {
            this@snack.dismiss()
        }
    }

This is my workaround to solve this type of problem in androidx using kotlin

 fun showSnackBar(message: String) {
        mContent?.let {
            val snackbar = Snackbar.make(it, message, Snackbar.LENGTH_LONG)
            val snackbarView = snackbar.view
            val tv = snackbarView.findViewById<TextView>(R.id.snackbar_text)
            tv.setTextColor(Color.WHITE) //change the color of text
            tv.maxLines = 3 //specify the limit of text line
            snackbar.duration = BaseTransientBottomBar.LENGTH_SHORT //specify the duraction of text message
            snackbar.show()
        }
    }

You need initialize mContent inside onViewCreated method like below

var mContent: View? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mContent = view
    }
Dr. Failov

I also noticed the same problem. Thanks to the answers here I've created a small class, which can help to solve this problem in more easily, just by replacing this:

Snackbar.make(view, "Error", Snackbar.LENGTH_LONG).show();

with this:

Snackbar2.make(view, "Error", Snackbar.LENGTH_LONG).show();

Here is my class:

public class Snackbar2 {
static public Snackbar make(View view, int resid, int duration){
    Snackbar result = Snackbar.make(view, resid, duration);
    process(result);
    return result;
}
static public Snackbar make(View view, String text, int duration){
    Snackbar result = Snackbar.make(view, text, duration);
    process(result);
    return result;
}
static private void process(Snackbar snackbar){
    try {
        View view1= snackbar.getView();

        TextView tv = (TextView) view1.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(Color.WHITE);

    }catch (Exception ex)
    {
        //inform about error
        ex.printStackTrace();
    }
}

}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!