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

49.5k views Asked by At

So I've started using the new Snackbar in the Design Support Library, but I found that when you define "android:textColor" in your theme, it applies to the text color of the snackbar. This is obviously a problem if your primary text color is dark.

enter image description here

Does anyone know a way around this or have advice for how I should color my text?

EDIT January 2017: (Post-Answer)

While there are some custom solutions to fix the problem below, it's probably good to provide the correct way to theme Snackbars.

Firstly, you probably shouldn't be defining android:textColor in your themes at all (unless you really know the scope of what is using the theme). This sets the text color of basically every view that connects to your theme. If you want to define text colors in your views that are not default, then use android:primaryTextColor and reference that attribute in your custom views.

However, for applying themes to Snackbar, please reference this quality guide from a third party material doc: http://www.materialdoc.com/snackbar/ (Follow the programmatic theme implementation to have it not rely on an xml style)

For reference:

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

(You can also create your own custom Snackbar layouts too, see the above link. Do so if this method feels too hacky and you want a surely reliable way to have your custom Snackbar last through possible support library updates).

And alternatively, see answers below for similar and perhaps faster answers to solve your problem.

24

There are 24 answers

4
JPM On BEST ANSWER

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()
0
natario On

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();
3
Mahonster On

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.

1
Gabriele Mariotti On

Use the Snackbar included in the Material Components Library and apply the

Something like:

Snackbar snackbar = Snackbar.make(view, "My custom Snackbar", Snackbar.LENGTH_LONG);        
snackbar.setTextColor(ContextCompat.getColor(this,R.color.xxxxx));
snackbar.setActionTextColor(ContextCompat.getColor(this,R.color.my_selector));
snackbar.setBackgroundTint(ContextCompat.getColor(this,R.color.xxxx));
snackbar.show();

enter image description here


With Jetpack Compose you can customize the SnackbarHost defining a custom Snackbar

    snackbarHost = {
        // reuse default SnackbarHost to have default animation and timing handling
        SnackbarHost(it) { data ->
            Snackbar(
                snackbarData = data,
                contentColor = Yellow,
                actionColor = Red.copy(alpha = 0.9f)
            )
        }
    }

enter image description here

Then just use it:

scope.launch {
    scaffoldState.snackbarHostState.showSnackbar(
        message = "Snackbar text  # ${++clickCount}",
        actionLabel = "Done")
}
3
Richard On

Created this kotlin extention function i use in my projects:

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
}

Usage like you would expect:

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

0
Grzegorz Matyszczak On

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)
0
Jet Zhao On

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();
1
Sandro Machado On

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.

0
Ifta On

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:

yellow snackbar with black text

2
Rohit Maurya On

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.

1
Anrimian On

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
0
Manoj Perumarath On

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)) {
            [email protected]()
        }
    }
0
Matjaz Kristl On

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

com.google.android.material.R.id.snackbar_text
1
Phil On

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()
0
Summved Jain On

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));
0
abhilash kaveriappa On

This worked for me

Snackbar.make(v, "Loading...", Snackbar.LENGTH_LONG).setTextColor(getColor(R.color.orange)).show();

Before that I declared my color in color.xml

<color name="orange">#FF9800</color>
0
SUBHAJIT ROY On

You can try this code

Snackbar snackbar;
    snackbar = Snackbar.make(binding.getRoot(), "Hello World!", Snackbar.LENGTH_INDEFINITE);
    View snackBarView = snackbar.getView();
    snackBarView.setBackgroundColor(getColor(R.color.purple_700));
    snackbar.show();

    snackbar.setTextColor(ContextCompat.getColor(this, R.color.white));
    snackbar.setActionTextColor(ContextCompat.getColor(this, R.color.purple_200));
    snackbar.setBackgroundTint(ContextCompat.getColor(this, R.color.purple_700));
    snackbar.setAction("Ok", new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Toast.makeText(MainActivity.this, "Click", Toast.LENGTH_SHORT).show();
        }
    });
    snackbar.show();
0
ulcica On

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/

0
Pavneet_Singh On

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.

10
Jarod Young On

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 = view.findViewById(com.google.android.material.R.id.snackbar_text);
tv.setTextColor(ContextCompat.getColor(requireContext(), R.color.someColor))
0
ATom On

Currently (January 2020) with com.google.android.material:material:1.2.0 and probably also 1.1.0

Is definitely the best way how to do it by overrides these styles:

<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>

If you use a material theme with .Bridge at the end, for some reason, neither of these styles are defined. So Snackar will use some legacy layout without these styles.

I found in the source code that both snackbarButtonStyle and snackbarTextViewStyle must be defined otherwise it will be not used.

0
Suraj Bahadur On

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
    }
1
Dr. Failov On

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

}

0
makata On

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