105

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.

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Dima Kornilov
  • 2,003
  • 3
  • 16
  • 25
  • AFAIK, snackbars are meant for quick user alert/feedback and have been designed to support it i.e. "Single Line". If you want to show an alert/feedback which has multilines, i would suggest show a dialog as user can take action after reading your message. – mudit Jun 08 '15 at 09:38
  • 4
    @mudit think about internationalization. Even if English string can fit into single line, German may not. Also Google provided Material Design spec for multiline snackbar (I linked it in the question) - why if it should be avoided? – Dima Kornilov Jun 08 '15 at 09:44

20 Answers20

258

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.

Prashant Jajal
  • 3,469
  • 5
  • 24
  • 38
Nilesh Senta
  • 5,236
  • 2
  • 19
  • 27
  • Is there a way to calculate the actual number of lines that are needed, or do we have to guess? – Chris Sep 12 '18 at 17:10
  • @Chris may android have but you can specify maxLine if text is small length it will automatically becomes shrink... – Nilesh Senta Sep 12 '18 at 17:49
  • 24
    For the latest androidx libs should be com.google.android.material.R.id.snackbar_text. But IMHO the ID might change in the future so this practice should be avoided. – mtsahakis Nov 16 '18 at 21:44
  • 2
    Since this relies on the TextView ID that can change with each version of the support lib, this answer is not really a permanent solution, but a hack. It may work, but it may also randomly break in production. – Chapz Aug 30 '19 at 07:21
  • 1
    Is there a recommended API for this? I agree that this method is a hack, but if there's no API exposed for this, then there's no alternative. – fobbymaster Oct 31 '19 at 17:57
  • Now that Toast is even more useless than usual with the deprecation of setview() and getview() as of API level 30, customizing the Snackbar has become more important. Hopefully Snackbar customization won't get deprecated too. – Androidcoder Jun 16 '20 at 18:38
  • 1
    This is not permanent solution. Please refer below Gabriele Mariotti solution. Its permanent solution. – Hitesh Sarsava Aug 17 '21 at 13:20
36

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.

akd005
  • 540
  • 4
  • 13
  • 21
    This practice should be avoided, since it's a private integer defined by design library, which might be renamed or deleted without generating any compilation or runtime error in your app. – Oasis Feng Sep 30 '15 at 09:54
  • 6
    Yes, but I think it should be clarified that this is very different from accessing private resources of the OS. This will work as long as you stick to the same version of the design library. If you update to a newer version you have to test your app thoroughly anyway, just put this on your checklist. – devconsole Apr 29 '16 at 03:26
  • Just letting you know that this does not work on kindle fire devices which seems to only show 1 line. @Nilesh answer did work. – Naveen Dissanayake Mar 28 '18 at 10:03
  • 1
    Downvoted as I don't like the idea of the checklist getting longer. – ban-geoengineering Nov 06 '18 at 23:36
18

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>

enter image description here

Note: it requires the version 1.2.0 of the library.

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
14
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();
Ramesh R
  • 7,009
  • 4
  • 25
  • 38
12

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.

mudit
  • 25,306
  • 32
  • 90
  • 132
  • 2
    I accepted this answer however material specs mention snackbar with 112dp too: http://i.imgur.com/1ACCoQb.png – Dima Kornilov Jun 16 '15 at 08:15
  • can you name the height of multiline snack bar in dimension? – Alp Jun 23 '15 at 06:59
  • @alp see https://www.google.com/design/spec/components/snackbars-toasts.html#snackbars-toasts-specs – Dan Dar3 Aug 31 '15 at 01:20
  • 1
    Don't follow any guidlines if you don't want to accept that guide line. If google is that much right in its guidline and tool than why gradle build system is headache for the developer? – Jigar Nov 03 '15 at 10:13
  • @DimaKornilov it will be set to 112dp if and only if you have text that is fully 2 lines long AND you provide an action. In that case the action will cause the Snackbar to expand to 112dp. – Christopher Rucinski Dec 23 '15 at 15:57
  • @Jigar I don't see the connection between the build system and the design guidelines. – The incredible Jan Jul 10 '23 at 13:49
11

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()
Vincent Sit
  • 2,214
  • 1
  • 24
  • 27
7

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()
rmirabelle
  • 6,268
  • 7
  • 45
  • 42
5

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

Gumby The Green
  • 603
  • 7
  • 10
  • It doesn't offer to use/import `snackbar_text` . – android developer Jun 13 '19 at 08:41
  • @androiddeveloper I can't get it to work again either, so I've updated the answer. – Gumby The Green May 16 '20 at 23:01
  • Crashes now : `java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setSingleLine(boolean)' on a null object reference` – android developer May 16 '20 at 23:30
  • @androiddeveloper Do you have this dependency: `implementation 'com.google.android.material:material:1.1.0'` and is your Snackbar the `com.google.android.material.snackbar.Snackbar` one? If not, try `android.support.design.R.id.snackbar_text` as the resource ID. – Gumby The Green May 16 '20 at 23:37
  • Those are what you get when you create a new project (and I did), and it crashed. – android developer May 16 '20 at 23:54
  • @androiddeveloper It must be an issue with the device or OS version. I just tried it with a new "Basic Activity" project and it worked fine, and it seems to be working for others on this page. – Gumby The Green May 17 '20 at 00:08
  • @androiddeveloper I'd try another solution like [this one](https://stackoverflow.com/a/38335555) or [this one](https://stackoverflow.com/a/58671164), which don't require a resource ID to access the TextView. – Gumby The Green May 17 '20 at 00:15
  • I tested on Pixel 4 with Android 10. Also tested on emulator with Android 10. And tried to update to 1.2.0-alpha06 . Still crash. At first I thought it's because "view" wasn't the correct one, but even after fixing it, and doing findViewById on MainActivity itself, it still couldn't find this view. However, using `snackbar.view.findViewById` works fine. – android developer May 17 '20 at 06:15
  • BTW, no need for `import com.google.android.material.R as MaterialR` . You can use the ID directly: `com.google.android.material.R.id.snackbar_text` , but it's nice to finally see a useful usage of "as" in imports. How did you find the correct ID though? The layout-inspector doesn't show any attribute of the SnackBar for some reason... – android developer May 17 '20 at 06:17
  • @androiddeveloper The `apply` function in my code should cause the `view` to belong to the snackbar, so I wonder if your code was missing it. I realize the import is unnecessary. I just don't like having full package names in the middle of my code - it's noisy. That ID can be found [here](https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/snackbar/res/layout/mtrl_layout_snackbar_include.xml) and the path for referencing it can be seen [here](https://developer.android.com/reference/com/google/android/material/R.layout). – Gumby The Green May 18 '20 at 01:58
  • OK I know what happened. I used it in onClickListener like on a new project, so the "view" was of the FAB. Seems odd that the IDE doesn't warn about this. The "view has double possible meaning here... So this is one of the examples when Kotlin shortcuts can cause bugs quite easily... A possible fix would be to use `getView()` instead of `view` which could be an issue. As for the ID, I think the DDMS tool can get it, and also the "developer assistant" app. – android developer May 18 '20 at 13:42
4

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()
Awsom3D
  • 920
  • 7
  • 22
3

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;
}
Chantell Osejo
  • 1,456
  • 15
  • 25
  • text somehow always null – stannums Mar 14 '17 at 20:39
  • Double check your code. [Here's the AOSP source code for the layout of Snackbar](https://github.com/dandar3/android-support-design/blob/master/res/layout/design_layout_snackbar_include.xml) You'll notice there is a TextView object there, so it isn't possible for text to be null. – Chantell Osejo Mar 16 '17 at 18:43
  • Might be even better to use `findViewsWithText`, since you already know the text. This solution might break in a couple situations (e.g. if our text view becomes a child of a child of the snackbar layout). – natario Mar 22 '17 at 11:58
  • This won't work for me. SnackbarLayout has another view inside of it. So `snackbarLayout.getChildAt()` will never return a `TextView`. – Vitor Hugo Schwaab Feb 10 '20 at 16:39
2

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();
medhdj
  • 1,168
  • 10
  • 17
2

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();
techSquats
  • 21
  • 2
2

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();
}
Minding
  • 1,383
  • 1
  • 17
  • 29
Adeeb karim
  • 292
  • 3
  • 9
2

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();
Zhar
  • 3,330
  • 2
  • 24
  • 25
1

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());
}
android developer
  • 114,585
  • 152
  • 739
  • 1,270
0

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
Nicolas Jafelle
  • 2,661
  • 2
  • 24
  • 30
0

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);
Abhishek Garg
  • 3,092
  • 26
  • 30
0

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

enter image description here

bastami82
  • 5,955
  • 7
  • 33
  • 44
0

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()
GotDots
  • 53
  • 1
  • 8
0

There's now a method on Snackbar to do exactly this. For example:

val snackbar = Snackbar.make(view, msgResId, Snackbar.LENGTH_LONG)
snackbar.setTextMaxLines(2)
snackbar.show()

See setTextMaxLines(int)

nmw
  • 6,664
  • 3
  • 31
  • 32