104

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.

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Mahonster
  • 1,381
  • 2
  • 8
  • 14

24 Answers24

184

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))
AdamHurwitz
  • 9,758
  • 10
  • 72
  • 134
Jarod Young
  • 1,978
  • 2
  • 10
  • 9
  • 2
    Just in case anyone else is futilely searching for a way to change the text size of a Snackbar, this is it! – Janis Peisenieks Nov 20 '15 at 13:38
  • snack.getView()? what is snack object? – angel Mar 11 '16 at 15:19
  • I believe I have got the complete code View rootView = ((Activity)context).getWindow().getDecorView().findViewById(android.R.id.content); Snackbar mysnack= Snackbar.make(rootView, Mensaje, Snackbar.LENGTH_LONG); View view= mysnack.getView(); TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text); tv.setTextColor(Color.WHITE); mysnack.show(); – angel Mar 11 '16 at 15:22
  • 2
    FYI, you can do the same with the Action text by using `snackbar_action` instead of `snackbar_text`. See this answer for an example: http://stackoverflow.com/a/36800101/293280 – Joshua Pinter Apr 22 '16 at 17:39
  • 7
    This is a hack at best - what happens when the ID for android.support.design.R.id.snackbar_text changes in a future release of the support library? Is there not some kind of default SnackBar style that can be overridden in styles.xml? – DiscDev Apr 25 '16 at 22:11
  • 8
    That ID was indeed changed in a future release of the support library, I'm getting a null pointer now. – CaptainForge Jul 21 '16 at 15:49
  • This is not a good answer for future compat. Answer below is much better, http://stackoverflow.com/a/37309267/346309 – JPM Nov 28 '16 at 20:54
  • This is actual solution of that question. I was searching for that types of answer. Thanks. – Ahamadullah Saikat Jul 29 '17 at 18:58
  • 1
    Do not use this please, it is very insecure. – Emmanuelguther Jun 01 '18 at 11:05
  • 3
    Update - with androidx, the id is now as follows: `snack.view.findViewById(com.google.android.material.R.id.snackbar_text) as TextView` – dblackker Dec 18 '18 at 17:26
41

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()
fawaad
  • 341
  • 6
  • 12
JPM
  • 9,077
  • 13
  • 78
  • 137
18

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

Richard
  • 14,427
  • 9
  • 57
  • 85
16

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.

Mahonster
  • 1,381
  • 2
  • 8
  • 14
  • I've just completed this task, phew, took a while! However, I needed to use "m vai's" method below for my antiquated Preferences activity (using preferences.xml). I think it's left my app's styling far more correctly theme based which is nice. +1 – BrantApps Oct 15 '15 at 22:00
  • 1
    Not a good solution IMO , i wanna keep my actual theme for textview and just change snakbar text color... – issamux Aug 15 '16 at 01:13
  • 1
    You're not supposed to define `android:textColor` in your theme at all. It's a *style* attribute of `TextView`. If you define it in your *theme* you override text color of every `TextView` or `Button` which doesn't specify its text color in XML. That also happens to be the snackbar message which would normally take color from its dark *theme overlay*. – Eugen Pechanec Aug 28 '16 at 18:59
15

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();
Jet Zhao
  • 151
  • 1
  • 2
12

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/

ulcica
  • 478
  • 5
  • 15
10

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.

Rohit Maurya
  • 730
  • 1
  • 9
  • 22
9

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.

ATom
  • 15,960
  • 6
  • 46
  • 50
7

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

com.google.android.material.R.id.snackbar_text
Matjaz Kristl
  • 746
  • 1
  • 5
  • 12
6

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();
natario
  • 24,954
  • 17
  • 88
  • 158
4

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")
}
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
2

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.

Derlin
  • 9,572
  • 2
  • 32
  • 53
Pavneet_Singh
  • 36,884
  • 5
  • 53
  • 68
2

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.

Sandro Machado
  • 9,921
  • 4
  • 36
  • 57
2

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();
makata
  • 2,188
  • 2
  • 28
  • 23
2

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

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
Anrimian
  • 4,257
  • 4
  • 22
  • 30
  • For me works! There is no the only solution for this problem... Depending on used libraries, themes, styles snackbars can be instantiated in different ways. The clue is to find exactly such one Textview to set it text color. I recommend to use debugger and looking at structure of Snackbar when it is made. – Antares Apr 06 '23 at 08:34
0

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));
Derlin
  • 9,572
  • 2
  • 32
  • 53
Summved Jain
  • 872
  • 2
  • 18
  • 21
0

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

Ifta
  • 1,536
  • 18
  • 25
0

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()
Phil
  • 4,730
  • 1
  • 41
  • 39
0

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()
        }
    }
Manoj Perumarath
  • 9,337
  • 8
  • 56
  • 77
0

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
    }
Suraj Bahadur
  • 3,730
  • 3
  • 27
  • 55
0

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

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

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

}

Robert Longson
  • 118,664
  • 26
  • 252
  • 242
Dr. Failov
  • 311
  • 4
  • 7
  • 1
    This is a hack, and relies on the id's of various support library views to be static. I would avoid this solution at all costs. – DiscDev Apr 25 '16 at 22:12