Related
Good afternoon,
I am working with Snackbars and I try to put an aciton (like UNDO), but the text is not aligned to the right of the screen.
The result I need :
The result I have :
As you can see, the "UNDO" action is not aligned right, as I need.
Here is my Snackbar code :
Snackbar snackbar = Snackbar.make(mMainContent, "Message deleted", Snackbar.LENGTH_LONG)
.setAction("UNDO", new View.OnClickListener() {
#Override
//Todo: Click on "UNDO"
public void onClick(View view) {
}
});
snackbar.setActionTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
View snackbarView = snackbar.getView();
snackbarView.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.colorAccent));
snackbar.show();
Can someone help me ?
Thank you !
Create your own custom snackbar layout Custom snackbar
The core part is below
<!-- language: lang-java -->
// Create the Snackbar
Snackbar snackbar = Snackbar.make(containerLayout, "", Snackbar.LENGTH_LONG);
// Get the Snackbar's layout view
Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
// Hide the text
TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
textView.setVisibility(View.INVISIBLE);
// Inflate our custom view
View snackView = mInflater.inflate(R.layout.my_snackbar, null);
// Configure the view
ImageView imageView = (ImageView) snackView.findViewById(R.id.image);
imageView.setImageBitmap(image);
TextView textViewTop = (TextView) snackView.findViewById(R.id.text);
textViewTop.setText(text);
textViewTop.setTextColor(Color.WHITE);
// Add the view to the Snackbar's layout
layout.addView(snackView, 0);
// Show the Snackbar
snackbar.show();
I am showing snackbar in a DialogFragment within the positive touch of the alert dialog. Here is my code snippet:
Snackbar snackbar = Snackbar.make(view, "Please enter customer name", Snackbar.LENGTH_LONG)
.setAction("Action", null);
View sbView = snackbar.getView();
sbView.setBackgroundColor(Color.BLACK);
snackbar.show();
I am passing the view of the DialogFragment to the snackbar. I want the background color to be black. How can I do this? I am returning the alertDialog in the DialogFragment. And the theme I am setting to the dialog as follow's:
<style name="MyAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog.Alert">
<!-- Used for the buttons -->
<item name="colorAccent">#color/accent</item>
<!-- Used for the title and text -->
<item name="android:textColorPrimary">#color/primary</item>
<!-- Used for the background -->
<item name="android:background">#color/white</item>
</style>
Although I am setting the background color to white for the dialog, it should override by setting the background color to the snackbar.
Try setting background color like this:
sbView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.BLACK));
It will work 100% !
you can do it like this
Snackbar snackbar;
snackbar = Snackbar.make(view, "Message", Snackbar.LENGTH_SHORT);
View snackBarView = snackbar.getView();
snackBarView.setBackgroundColor(yourColor);
TextView textView = (TextView) snackBarView.findViewById(android.support.design.R.id.snackbar_text);
textView.setTextColor(textColor);
snackbar.show();
As none of the other answers provided a custom style override (that I consider one of the safest update way to do that) I post here my solution.
I post a solution that already address the new AndroidX (support design 28) theme.
Provided that your application use a custom them called MyAppTheme in your AndroidManifest.xml:
<application
android:name=".MyApplicationName"
android:allowBackup="true"
android:icon="#mipmap/icon"
android:roundIcon="#mipmap/icon_round"
android:label="#string/app_name"
android:theme="#style/MyAppTheme">
Create (if you haven't already) values/style.xml file overriding the theme used by your application:
<style name="MyAppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">#color/myColorPrimary</item>
<item name="colorPrimaryDark">#color/myColorPrimaryDark</item>
<item name="colorAccent">#color/myColorAccent</item>
<item name="snackbarStyle">#style/MySnackBarStyle</item>
</style>
<!-- snackbar style in res/values -->
<style name="MySnackBarStyle" parent="Widget.MaterialComponents.Snackbar">
<item name="android:background">#color/mySnackbarBackgroundColor</item>
</style>
and provide your colors in your values/colors.xml file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="myColorPrimary">#008577</color>
<color name="myColorPrimaryDark">#00574B</color>
<color name="myColorAccent">#D81B60</color>
<color name="mySnackbarBackgroundColor">#D81B60</color>
</resources>
UPDATE 2020
As the above solution removes the round corner of the snacker bacause setting the background this way uses the legacy snackbar design, if you want to preserve the material design you can.
If you are targeting API 21+
replace android:background with android:backgroundTint
<!-- snackbar style in res/values-21/ -->
<style name="MySnackBarStyle" parent="Widget.MaterialComponents.Snackbar">
<item name="android:backgroundTint">#color/mySnackbarBackgroundColor</item>
</style>
If you are targeting API < 21 then if you decide to use legacy snackbar for API < 21 you could set your abouve MySnackbarStyle in res/values-21/ folder and leave the previous — legacy — style in your res/values folder.
If you are targeting API < 21 and you want to have the material style of the snackbar also in this lower API levels you can change your snackbar style in your res/values/ this way:
<!-- snackbar style in res/values/ -->
<style name="MySnackBarStyle" parent="Widget.MaterialComponents.Snackbar">
<item name="android:background">#drawable/my_snackbar_background</item>
</style>
and borrow your my_snackbar_background from the official repo, this way:
<!-- in res/drawable/ -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="4dp"/>
<solid android:color="#color/mySnackbarBackgroundColor"/>
</shape>
EDIT 2022:
If you only want to change a single snackbar, and not across the app, then you can use a ContextThemeWrapper as following;
ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.CustomSnackbarTheme);
customSnackBar = Snackbar.make(ctw, view, "", Snackbar.LENGTH_LONG);
and in your style file
<style name="CustomSnackbarTheme">
<item name="snackbarStyle">#style/MySnackBarStyle</item>
</style>
<style name="MySnackBarStyle" parent="Widget.MaterialComponents.Snackbar">
<item name="android:background">#android:color/red</item>
</style>
Here is a playground repo.
Kotlin version (with an extension) :
Create in a file (for exemple SnackbarExtension.kt) an extension :
fun Snackbar.withColor(#ColorInt colorInt: Int): Snackbar{
this.view.setBackgroundColor(colorInt)
return this
}
Next, in your Activity/Fragment, you'll be able to do this :
Snackbar
.make(coordinatorLayout, message, Snackbar.LENGTH_LONG)
.withColor(YOUR_COLOR)
.show()
If you want to define a background color for all your Snackbars, just override the design_snackbar_background_color value somewhere in your resources. For example:
<color name="design_snackbar_background_color" tools:override="true">#color/colorPrimaryLight</color>
Bellow code is useful for change the text color of message.
Snackbar snackbar = Snackbar.make(rootView, "Enter Your Message",Snackbar.LENGTH_SHORT);
View view = snackbar.getView();
TextView tv = (TextView)view.findViewById(android.support.design.R.id.snackbar_text);
tv.setTextColor(Color.RED);
snackbar.show();
Second Way: You can change color by changing theme of activity also.
With the Material Components Library just use the setBackgroundTint method.
Snackbar snackbar = Snackbar.make(view, "Snackbar custom style", Snackbar.LENGTH_LONG);
snackbar.setBackgroundTint(ContextCompat.getColor(this,R.color.secondaryColor));
snackbar.show();
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,
backgroundColor = Color.Red
)
}
},
Then just use it:
scope.launch {scaffoldState.snackbarHostState.showSnackbar("Snackbar text")}
It's too late but In case someone still needs help. Here is the working solution.
Snackbar snackbar = Snackbar.make(mainView, text, Snackbar.LENGTH_LONG);
View snackBarView = snackbar.getView();
snackBarView.setBackgroundColor(context.getResources().getColor(R.color.btn_background_color));
snackbar.show();
I made a little utils class so I can easily make custom colored snackbars thru out the app.
package com.yourapppackage.yourapp;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class SnackbarUtils {
private int BACKGROUND_COLOR;
private int TEXT_COLOR;
private int BUTTON_COLOR;
private String TEXT;
public SnackbarUtils(String aText, int aBgColor, int aTextColor, int aButtonColor){
this.TEXT = aText;
this.BACKGROUND_COLOR = aBgColor;
this.TEXT_COLOR = aTextColor;
this.BUTTON_COLOR = aButtonColor;
}
public Snackbar snackieBar(){
Snackbar snackie = Snackbar.make(MainActivity.getInstance().findViewById(android.R.id.content), TEXT, Snackbar.LENGTH_LONG);
View snackView = snackie.getView();
TextView snackViewText = (TextView) snackView.findViewById(android.support.design.R.id.snackbar_text);
Button snackViewButton = (Button) snackView.findViewById(android.support.design.R.id.snackbar_action);
snackView.setBackgroundColor(BACKGROUND_COLOR);
snackViewText.setTextColor(TEXT_COLOR);
snackViewButton.setTextColor(BUTTON_COLOR);
return snackie;
}
}
then to use it, like this any where in the app:
new SnackbarUtils("This is the text displayed", Color.RED, Color.BLACK, Color.YELLOW).snackieBar().setAction("OTAY", v -> {
//donothing
}).show();
While Working with xamarin android I found out that ContextCompat.GetColor() returns Int but the setBackgroundColor() expects a Parameter of type Color.
So here is how I got it working in my xamarin android project.
Snackbar snackbarview = Snackbar.Make(toolbar, message, Snackbar.LengthLong);
View snckView = snackbarview.View;
snckView.SetBackgroundColor(Color.ParseColor(GetString(Resource.Color.colorPrimary)));
snackbarview.Show();
Put it in an Utility class:
public class Utility {
public static void showSnackBar(Context context, View view, String text) {
Snackbar sb = Snackbar.make(view, text, Snackbar.LENGTH_SHORT);
sb.getView().setBackgroundColor(ContextCompat.getColor(context, R.color.colorAccent));
sb.show();
}
}
Using like this:
Utility.showSnackBar(getApplicationContext(), findViewById(android.R.id.content), "Add success!!!");
None of other solutions really worked for me. If I only set Snackbar's background color, the layout under TextView and Button was in default color. If I set TextView's background it did a little blink after SnackBar was shown. And layout around button was still in default color.
At the end I found out that the best way for me is to change background color of TextView's parent (SnackbarContentLayout). Now whole Snackbar is colored properly and it doesn't blink when it shows up.
snack = Snackbar.make(view, text, duration)
View view = snack.getView();
view.setBackgroundColor(BACKGROUND_COLOR);
TextView tv = view.findViewById(android.support.design.R.id.snackbar_text);
tv.setTextColor(TEXT_COLOR);
((SnackbarContentLayout) tv.getParent()).setBackgroundColor(BACKGROUND_COLOR);
setBackgroundResource() works just as well.
Snackbar snackbar = Snackbar.make(view, text, Snackbar.LENGTH_LONG);
View sbView = snackbar.getView();
sbView.setBackgroundResource(R.color.background);
snackbar.show();
I don't know why setBackgroundColor() didn't find in my project. That's why I created an extension function and it's fine now.
fun View.showSnackBar(message: String) {
val snackBar = Snackbar.make(this, message, Snackbar.LENGTH_LONG)
snackBar.setBackgroundTint(ContextCompat.getColor(this.context, R.color.colorAccent))
snackBar.show()
}
and call it like bellow
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/login_holder_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
// your UI
</FrameLayout>
LoginActivity.kt
login_holder_layout.showSnackBar("Invalid Email")
Basically, the solutions that were provided have one disadvantage.
They change the shape of snackbar and remove the radius.
Personally, prefer something like that
val snackbar = Snackbar.make(view, text, Snackbar.LENGTH_LONG);
val view = snackbar.getView();
val color = view.resources.getColor(colorId)
view.background.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
For Kotlin:
Snackbar.make(view,"simple text",Snackbar.LENGTH_SHORT).setBackgroundTint(Color.RED).show()
Old format using Java
mySnackbar.setBackgroundColor(ContextCompat.getColor(getActivity(), android.R.color.black));
Actualy format using kt
mySnackbar.setBackgroundTint(ContextCompat.getColor(applicationContext, android.R.color.black));
public class CustomBar {
public static void show(View view, String message, boolean isLong) {
Snackbar s = Snackbar.make(view, message, isLong ? Snackbar.LENGTH_LONG : Snackbar.LENGTH_SHORT);
s.getView().setBackgroundColor(ContextCompat.getColor(view.getContext(), R.color.red_900));
s.show();
}
public static void show(View view, #StringRes int message, boolean isLong) {
Snackbar s = Snackbar.make(view, message, isLong ? Snackbar.LENGTH_LONG : Snackbar.LENGTH_SHORT);
s.getView().setBackgroundColor(ContextCompat.getColor(view.getContext(), R.color.red_900));
s.show();
}
}
you can use this code on the material design library
you can use the way
create color code
open the res/values/colors.xml and add this line
<resources>
<color name="custom_color_name">CustomCode</color>
</resources>
create Snackbar and change Background
open your activity or fragment and create Snackber
Snackbar snackbar= Snackbar.make(root,R.string.imageUploadTitle_error, BaseTransientBottomBar.LENGTH_LONG);
get Snackbar View
now you should get the SnackbarView and Change custom background in it
View snackview = snackbar.getView();
change background color
set the snackbar background color with this function
snackview.setBackgroundColor(ContextCompat.getColor(getActivity() , R.color.error));
showing this snackbar
now should show the Snackbar
snackbar.show();
so you can see changed background to custom color
Trying out the new Design Support Library, I added a snackbar; but unlike its main background, the text area is not colored with the default value of #323232. Instead, it looks like this. It seems to take its color from the android:background value defined in the custom theme in my styles.xml, which goes like this:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="android:background">#4f4f5e</item>
...
</style>
If I try to forcefully color it with
View snackbarView = snackbar.getView();
snackbarView.setBackgroundColor(Color.YELLOW);
it only impacts the main background, like this, and the text background still gets colored by the custom theme. Is there a way to both keep my custom theme, and have a standard snackbar? Thanks!
To change the Snackbar's background colour you can do the following from code:
Snackbar snack = Snackbar.make(...);
ViewGroup group = (ViewGroup) snack.getView();
group.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.red));
snack.show();
Instead of red you can use the Snackbar's default colour: #323232
.setBackgroundColor allows you to change background color of snackbar
msnackBar.setBackgroundColor(Color.parseColor("#009688"));
or
msnackBar.setBackgroundColor(getResources().getColor(R.color.BLUE)););
Here is complete tutorial to use snackbar using design support library.
The snackbar contains a TextView, so you need to change the background color for both, the snackbar the way you already did, and then the TextView like this:
View snackbarView = snackbar.getView();
TextView textView = (TextView)snackbarView.findViewById(android.support.design.R.id.snackbar_text);
textView.setBackgroundColor(Color.YELLOW);
This effect happens when in style attribute android:background is set.
Removing that will of course affect all layouts in your application but snackbar will be fixed.
Here is a complete sample:
Snackbar snack = Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null);
ViewGroup group = (ViewGroup) snack.getView();
group.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.blue));
snack.show();
replace MainActivity.this with your currently activity or getAppContext()
You can simply create your own Snackbar class and simulate Snackbar's make method. Doing this, you just have to use this class instead of android's snackbar widget.
Snackbar.class
import android.graphics.Color;
import android.support.annotation.IntDef;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.view.View;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class Snackbar {
/** Snackbar's lengths **/
public static final int LENGTH_SHORT = android.support.design.widget.Snackbar.LENGTH_SHORT;
public static final int LENGTH_LONG = android.support.design.widget.Snackbar.LENGTH_LONG;
public static final int LENGTH_INDEFINITE = android.support.design.widget.Snackbar.LENGTH_INDEFINITE;
#NonNull
public static android.support.design.widget.Snackbar make(#NonNull View view, #NonNull CharSequence text,
#Duration int duration) {
android.support.design.widget.Snackbar snackbar = android.support.design.widget.Snackbar.make(view, text, duration);
// TODO: This is where you have to customize your snackbar
snackbar.getView().setBackgroundColor(Color.RED);
return snackbar;
}
#NonNull
public static android.support.design.widget.Snackbar make(#NonNull View view, #StringRes int resId, #Duration int duration) {
return make(view, view.getResources().getText(resId), duration);
}
// Optional
#IntDef({LENGTH_INDEFINITE, LENGTH_SHORT, LENGTH_LONG})
#IntRange(from = 1)
#Retention(RetentionPolicy.SOURCE)
public #interface Duration {}
}
Use:
// WARNING: Make sure you're using your snackbar's package
import com.mypackage.custom_views.Snackbar;
public class MyActivity extends Activity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Snackbar.make(view, R.string.my_msg, Snackbar.LENGTH_LONG).show();
}
}
Hope this helps!
You can use this library: https://github.com/SandroMachado/restaurant
new Restaurant(MainActivity.this, "Snackbar with custom background and text color", Snackbar.LENGTH_LONG)
.setBackgroundColor(Color.GRAY)
.show();
Disclaimer: I made the library.
this is how i'm using custom snackbar
Snackbar snackbar_network = Snackbar.make(rLayout, "Your Message", Snackbar.LENGTH_SHORT)
.setAction("EXIT", new View.OnClickListener() {
#Override
public void onClick(final View v) {
finish();
}
});
Action Text Color
snackbar_network.setActionTextColor(Color.RED);
Action Message Text Color
final View sbView = snackbar_network.getView();
final TextView tv = (TextView) sbView.findViewById(android.support.design.R.id.snackbar_text);
tv.setTextColor(Color.YELLOW);
Set Snackbar Background
sbView.setBackgroundColor(ContextCompat.getColor(MapsActivity.this, R.color.black));
snackbar_network.show();
Works this way for me:
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll);
Snackbar snackbar = Snackbar.make(lineatLayout, "TEXT", Snackbar.LENGTH_LONG);
ViewGroup group = (ViewGroup) snackbar.getView();
group.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.yourColor));
TextView textView = (TextView) group.findViewById(android.support.design.R.id.snackbar_text);
textView.setTextColor(ContextCompat.getColor(this, R.color.yor collor));
snackbar.show();
I also faced similar issue & unfortunately no solution works for me Hence I write my own solution where I set background color for parent view too.
TextView snackbarTextView = snackbar.getView().findViewById(android.support.design.R.id.snackbar_text);
snackbarTextView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.colorPrimary));
ViewParent parentView = snackbarTextView.getParent();
if (parentView instanceof View) {
((View) parentView).setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.colorPrimary));
}
View snackbarView = snackbar.getView();
snackbarView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.colorPrimary));
snackbar.show();
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.
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.
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))
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()
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()
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.
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();
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.
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.
If you will migrate your code to AndroidX, the TextView property is now:
com.google.android.material.R.id.snackbar_text
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();
Use the Snackbar included in the Material Components Library and apply the
setTextColor to define the text color
setActionTextColor to define the text color used by the action. You can use a color or a color selector
setBackgroundTint to define the background color of the Snackbar
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();
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)
)
}
}
Then just use it:
scope.launch {
scaffoldState.snackbarHostState.showSnackbar(
message = "Snackbar text # ${++clickCount}",
actionLabel = "Done")
}
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.
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();
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)
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
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
}
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>
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();
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();
}
}
}
I'm trying to leverage new Snackbar from Android Design Support Library to display multiline snackbar, as shown in http://www.google.com/design/spec/components/snackbars-toasts.html#snackbars-toasts-specs:
import android.support.design.widget.Snackbar;
final String snack = "First line\nSecond line\nThird line";
Snackbar.make(mView, snack, Snackbar.LENGTH_LONG).show();
It displays only First line... on my Nexus 7. How to make it display all lines?
PS: I tried Toast and it displayed all lines.
Just set the maxLines attribute of Snackbars Textview
View snackbarView = snackbar.getView();
TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
textView.setMaxLines(5); // show multiple line
If you're using the more recent "com.google.android.material:material:1.0.0"dependency, then you will use this: com.google.android.material.R.id.snackbar_text to access the Snackbar's TextView.
You can use even R.id.snackbar_text as well. it's work for me.
One can override the predefined value used for that in values.xml of the app
<integer name="design_snackbar_text_max_lines">5</integer>
This value is used by Snackbar by default.
With the Material Components Library you can define it using with the snackbarTextViewStyle attribute in the app theme:
<style name="AppTheme" parent="Theme.MaterialComponents.*">
...
<item name="snackbarTextViewStyle">#style/snackbar_text</item>
</style>
<style name="snackbar_text" parent="#style/Widget.MaterialComponents.Snackbar.TextView">
...
<item name="android:maxLines">5</item>
</style>
Note: it requires the version 1.2.0 of the library.
Snackbar snackbar = Snackbar.make(view, "Text",Snackbar.LENGTH_LONG).setDuration(Snackbar.LENGTH_LONG);
View snackbarView = snackbar.getView();
TextView tv= (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
tv.setMaxLines(3);
snackbar.show();
Here is my finding on this :
Android does support multiline snackbars but it has a max limit of 2 lines which matches the design guideline where it says that the height of multiline snack bar should be 80dp (almost 2 lines)
To verify this, i used the cheesesquare android sample project. If i use following string:
Snackbar.make(view, "Random Text \n When a second snackbar is triggered while the first is displayed", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
In this case, i can see the multiline snack bar with the text of 2nd line, i.e. "When a second snackbar is triggered" but if i change this code to following implementation:
Snackbar.make(view, "Random Text \n When \n a second snackbar is triggered while the first is displayed", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
I can only see the "Random Text\nWhen ...". This means that design library is intentionally forcing the textview to be of max 2 lines.
In kotlin you can use extensions.
// SnackbarExtensions.kt
fun Snackbar.allowInfiniteLines(): Snackbar {
return apply { (view.findViewById<View?>(R.id.snackbar_text) as? TextView?)?.isSingleLine = false }
}
Usage:
Snackbar.make(view, message, Snackbar.LENGTH_LONG)
.allowInfiniteLines()
.show()
For Material Design, the reference is com.google.android.material.R.id.snackbar_text
val snack = Snackbar.make(myView, R.string.myLongText, Snackbar.LENGTH_INDEFINITE).apply {
view.findViewById<TextView>(com.google.android.material.R.id.snackbar_text).maxLines = 10
}
snack.show()
In Kotlin, you can just do
Snackbar.make(root_view, "Yo\nYo\nYo!", Snackbar.LENGTH_SHORT).apply {
view.snackbar_text.setSingleLine(false)
show()
}
You could also replace setSingleLine(false) with maxLines = 3.
Android Studio should prompt you to add
import kotlinx.android.synthetic.main.design_layout_snackbar_include.view.*
EDIT
I haven't been able to get this to work again, so I'll just share what I think is the cleanest way to write in Kotlin what a few others have already shared:
import com.google.android.material.R as MaterialR
Snackbar.make(root_view, "Yo\nYo\nYo!", Snackbar.LENGTH_SHORT).apply {
val textView = view.findViewById<TextView>(MaterialR.id.snackbar_text)
textView.setSingleLine(false)
show()
}
2021 Answer in Kotlin for com.google.android.material:material:1.4.0
isSingleLine = false is required as well as maxLines = 5
Snackbar.make(view, "line 1\nline 2", BaseTransientBottomBar.LENGTH_INDEFINITE)
.apply {
this.view.findViewById<TextView>(com.google.android.material.R.id.snackbar_text)?.apply {
maxLines = 5
isSingleLine = false
}
}
.show()
An alternative to the suggestions that involve hardcoding the resource ID for the textview contained by the snackbar is to iterate to find the TextView. It's safer long-term and lets you update the support library with minimal fear of the ID changing.
Example:
public static Snackbar getSnackbar(View rootView, String message, int duration) {
Snackbar snackbar = Snackbar.make(rootView, message, duration);
ViewGroup snackbarLayout = (ViewGroup) snackbar.getView();
TextView text = null;
for (int i = 0; i < snackbarLayout.getChildCount(); i++) {
View child = snackbarLayout.getChildAt(i);
// Since action is a button, and Button extends TextView,
// Need to make sure this is the message TextView, not the
// action Button view.
if(child instanceof TextView && !(child instanceof Button)) {
text = (TextView) child;
}
}
if (text != null) {
text.setMaxLines(3);
}
return snackbar;
}
Instead of using setMaxLines, i use setSingleLine to make the textview wrap to its content.
String yourText = "First line\nSecond line\nThird line";
Snackbar snackbar = Snackbar.make(mView, yourText, Snackbar.LENGTH_SHORT);
TextView textView =
(TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text);
textView.setSingleLine(false);
snackbar.show();
this works for me
Snackbar snackbar = Snackbar.make(mView, "Your text string", Snackbar.LENGTH_INDEFINITE);
((TextView) snackbar.getView().findViewById(android.support.design.R.id.snackbar_text)).setSingleLine(false);
snackbar.show();
Late, but might be helpful to someone:
public void showSnackBar(String txt, View view){
final Snackbar snackbar = Snackbar.make(view,txt,Snackbar.LENGTH_INDEFINITE)
.setAction("OK", new View.OnClickListener() {
#Override
public void onClick(View view) {
//do something
}
});
View view = snackbar.getView();
TextView textView = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
textView.setMaxLines(5);
snackbar.show();
}
May i suggest you to use com.google.android.material.snackbar.Snackbar. This is the recommanded way by google. First you have to add your snackbar.
final Snackbar snackbar = Snackbar.make(
findViewById(R.id.activity_layout),
"snackbar explanation text \n multilines \n\n here",
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.action_settings, new View.OnClickListener() {
#Override
public void onClick(View view) {
// your action here
}
});
Then to add multilines support
TextView messageView = snackbar.getView().findViewById(R.id.snackbar_text);
messageView.setMaxLines(4);
Finally show the snackbar.
snackbar.show();
A way to do it which won't crash in case things change on newer versions of the library :
Snackbar.make(...).setAction(...) {
...
}.apply {
(view.findViewById<View?>(R.id.snackbar_text) as? TextView?)?.setSingleLine(false)
}.show()
And a way to do it without having ids being used, setting all TextViews in the Snackbar to have unlimited multi-lines :
#UiThread
fun setAllTextViewsToHaveInfiniteLinesCount(view: View) {
when (view) {
is TextView -> view.setSingleLine(false)
is ViewGroup -> for (child in view.children)
setAllTextViewsToHaveInfiniteLinesCount(child)
}
}
Snackbar.make(...).setAction(...) {
...
}.apply {
setAllTextViewsToHaveInfiniteLinesCount(view)
}.show()
The same function in Java:
#UiThread
public static void setAllTextViewsToHaveInfiniteLines(#Nullable final View view) {
if (view == null)
return;
if (view instanceof TextView)
((TextView) view).setSingleLine(false);
else if (view instanceof ViewGroup)
for (Iterator<View> iterator = ViewGroupKt.getChildren((ViewGroup) view).iterator(); iterator.hasNext(); )
setAllTextViewsToHaveInfiniteLines(iterator.next());
}
Just a quick comment, if you are using com.google.android.material:material the prefix or package for R.id should be com.google.android.material
val snackbarView = snackbar.view
val textView = snackbarView.findViewById<TextView>(com.google.android.material.R.id.snackbar_text)
textView.maxLines = 3
so as i am using latest material design library from google, com.google.android.material:material:1.1.0 and i used simple following code snipet below, to resolve allow to more lines in snackbar. hope it will help to new developers as well.
TextView messageView = snackbar.getView().findViewById(R.id.snackbar_text);
messageView.setMaxLines(5);
To avoid flakiness of other answers can use updateMaxLine, this solution is less likely to break if Google decide to change the id of a text view)
val snackBar = Snackbar.make(view, message, duration)
snackBar.view.allViews.updateMaxLine(5)
snackBar.show()
just note, this option will update the max line for all the text views in the Snakbar view (which tbh I do not think it matters)
add this as extension
private fun <T> Sequence<T>.updateMaxLine(maxLine : Int) {
for (view in this) {
if (view is TextView) {
view.maxLines = maxLine
}
}
}
Snackbar height adjustment:
val sMsg = "Msg\n\n"
val sOk = getString(R.string.ok)
val sMoreLines = StringBuilder()
for (iCtr in 1..6) {
sMoreLines.append("\n")
}
Snackbar
.make(
this.requireActivity().findViewById(android.R.id.content),
sMsg,
Snackbar.LENGTH_INDEFINITE)
.setAction("$sMoreLines$sOk\n$sMoreLines") {
// ...
}
.show()