Android多行小吃店


84

我正在尝试利用SnackbarAndroid设计支持库中的新功能来显示多行快餐栏,如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();

它仅显示First line...在我的Nexus 7上。如何使其显示所有行?

PS:我尝试过Toast,它显示了所有行。


AFAIK快餐栏用于快速的用户警报/反馈,并已设计为支持它,即“单行”。如果要显示包含多行的警报/反馈,我建议显示一个对话框,以便用户在阅读邮件后可以采取措施。
泥泞

3
@mudit考虑国际化。即使英语字符串可以放在一行中,德语也可能不行。谷歌还提供了多行快餐栏的材料设计规范(我在问题中链接了它)-为什么应避免使用它?
Dima Kornilov

Answers:


223

只需设置maxLinesSnackbars Textview的属性

View snackbarView = snackbar.getView();
TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
textView.setMaxLines(5);  // show multiple line

如果您使用的是较新的"com.google.android.material:material:1.0.0"依赖项,则将使用此:com.google.android.material.R.id.snackbar_text访问Snackbar的TextView。

您甚至可以使用R.id.snackbar_text。这对我有用。


有没有一种方法可以计算所需的实际行数,或者我们必须猜测?
克里斯(Chris

@Chris可能是android的人,但您可以指定maxLine如果文本太短,它将自动缩小...
Nilesh Senta

22
对于最新的androidx库,应为com.google.android.material.R.id.snackbar_text。但是恕我直言,ID可能会在将来更改,因此应避免这种做法。
mtsahakis

1
由于这依赖于可以随支持库的每个版本更改的TextView ID,因此,此答案实际上不是永久性的解决方案,而是黑客。它可能有效,但也可能会随机中断生产。
查普兹

1
是否有为此推荐的API?我同意这种方法是一种hack,但是如果没有为此公开的API,那么别无选择。
fobbymaster,

31

可以覆盖应用程序的values.xml中用于该值的预定义值

<integer name="design_snackbar_text_max_lines">5</integer>

默认情况下,Snackbar使用此值。


18
应该避免这种做法,因为它是设计库定义的私有整数,可以对它进行重命名或删除,而不会在应用程序中产生任何编译或运行时错误。
绿洲峰

4
是的,但是我认为应该澄清一下,这与访问OS的私有资源有很大不同。只要您坚持使用相同版本的设计库,这将起作用。如果您更新到较新的版本,则无论如何都必须彻底测试您的应用程序,只需将其放在清单中即可。
devconsole '16

只是让您知道这不适用于似乎仅显示1行的kindle fire设备。@Nilesh回答确实有效。
Naveen Dissanayake

1
由于我不喜欢清单变长的想法而被否决。
ban-geoengineering

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

11

这是我对此的发现:

Android确实支持多行快餐栏,但它的最大限制为2行,这与设计准则相符,在该设计准则中,多行快餐栏的高度应为80dp(将近2行)

为了验证这一点,我使用了cheesesquare android示例项目。如果我使用以下字符串:

Snackbar.make(view, "Random Text \n When a second snackbar is triggered while the first is displayed", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();

在这种情况下,我可以看到带有第二行文本的多行小吃店,即“何时触发第二个小吃店”,但是如果我将此代码更改为以下实现:

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

我只能看到“随机文本\ nWhen ... ”。这意味着设计库有意将textview强制设为最多2行。


2
我接受了这个答案,但是材料规格也提到了带有112dp的小吃店:i.imgur.com/1ACCoQb.png
Dima Kornilov

您可以在尺寸上命名多行小吃店的高度吗?
2015年


1
如果您不想接受该指导原则,请不要遵循任何指导原则。如果google在其指导方针和工具方面非常正确,那么为什么gradle构建系统会让开发人员感到头疼?
Jigar 2015年

@DimaKornilov它将被设置为112dp,并且仅当您的文本长度为2行且您提供一个动作时。在这种情况下,该动作将使Snackbar扩展到112dp。
Christopher Rucinski 2015年

5

对于材料设计,参考为 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()

3

对于涉及对快餐栏所包含的textview的资源ID进行硬编码的建议的替代方法是迭代查找TextView。长期而言,它更安全,可让您以最小的担心更改ID来更新支持库。

例:

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

文本总以某种方式为空
锡宁

仔细检查您的代码。这是Snackbar布局的AOSP源代码。您会注意到那里有一个TextView对象,因此文本不可能为null。
Chantell Osejo

可能会更好用findViewsWithText,因为您已经知道文本了。此解决方案可能在几种情况下无法使用(例如,如果我们的文本视图变成了快餐栏布局的子视图的子视图)。
natario

这对我不起作用。SnackbarLayout内部有另一个视图。因此snackbarLayout.getChildAt()永远不会返回TextView
维托·雨果·施瓦布

2

我没有使用setMaxLines,而是使用setSingleLine使textview换行为其内容。

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

2

这对我有用

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

2

迟了,但可能对某人有帮助:

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

?您刚刚为最终变量分配了null并在侦听器中调用了它?您想要100%NPE吗?
osipxd

@OsipXD为他修复了:)
android开发人员

2

使用Material Components Library,您可以使用snackbarTextViewStyleapp主题中的属性对其进行定义:

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

在此处输入图片说明

注意:它需要库的版本1.2.0


2
好点,但图书馆仍处于Alpha状态(2020年5月):)
Anton Malyshev

2

在科特林,你可以做

Snackbar.make(root_view, "Yo\nYo\nYo!", Snackbar.LENGTH_SHORT).apply {
    view.snackbar_text.setSingleLine(false)
    show()
}

您也可以替换setSingleLine(false)maxLines = 3

Android Studio应提示您添加

import kotlinx.android.synthetic.main.design_layout_snackbar_include.view.*

编辑

我无法再次使它正常工作,所以我将只分享我认为是用Kotlin编写其他一些人已经分享过的最干净方法的东西:

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


它不提供使用/导入snackbar_text
Android开发人员

@androiddeveloper我也无法使其再次工作,所以我更新了答案。
Gumby The Green

现在崩溃: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setSingleLine(boolean)' on a null object reference
Android开发人员

@androiddeveloper您是否有这种依赖性:implementation 'com.google.android.material:material:1.1.0'Snackbar是com.google.android.material.snackbar.Snackbar其中之一吗?如果不是,请尝试android.support.design.R.id.snackbar_text作为资源ID。
Gumby The Green

这些就是您创建新项目(我做了)时得到的,并且崩溃了。
Android开发人员

1

这样做的方法不会在新版本的库发生更改的情况下崩溃:

Snackbar.make(...).setAction(...) {
    ...
}.apply {
    (view.findViewById<View?>(R.id.snackbar_text) as? TextView?)?.setSingleLine(false)
}.show()

以及一种无需使用ID的方式,将Snackbar中的所有TextViews设置为具有无限多行:

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

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

1

在kotlin中,您可以使用扩展名。

// SnackbarExtensions.kt

fun Snackbar.allowInfiniteLines(): Snackbar {
    return apply { (view.findViewById<View?>(R.id.snackbar_text) as? TextView?)?.isSingleLine = false }
}

用法:

Snackbar.make(view, message, Snackbar.LENGTH_LONG)
                        .allowInfiniteLines()
                        .show()

0

只是一个快速评论,如果您使用com.google.android.material:material的前缀或包R.id应该是com.google.android.material

val snackbarView = snackbar.view
val textView = snackbarView.findViewById<TextView>(com.google.android.material.R.id.snackbar_text)
textView.maxLines = 3

0

因此,由于我使用的是来自Google的最新材料设计库,com.google.android.material:material:1.1.0 并且我在下面使用了以下简单的代码段,以解决在小吃栏中增加行数的问题。希望它也对新开发人员有所帮助。

TextView messageView = snackbar.getView().findViewById(R.id.snackbar_text);
messageView.setMaxLines(5);

0

为了避免出现其他答案可能会显得有些笨拙,updateMaxLine如果Google决定更改文本视图的ID,则此解决方案不太可能破解)

val snackBar = Snackbar.make(view, message, duration)
 snackBar.view.allViews.updateMaxLine(5)
 snackBar.show()

请注意,此选项将更新Snakbar视图中所有文本视图的最大行(我认为这并不重要)

将此添加为扩展

private fun <T> Sequence<T>.updateMaxLine(maxLine : Int) {
    for (view in this) {
        if (view is TextView) {
            view.maxLines = maxLine
        }
    }
}

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.