Androidマルチラインスナックバー


84

http://www.google.com/design/spec/components/snackbars-toasts.html#snackbars-toasts-specsにSnackbar示すように、Android Design SupportLibraryの新しい機能を利用して複数行のスナックバーを表示しようとしています

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、スナックバーはユーザーへの迅速なアラート/フィードバックを目的としており、それをサポートするように設計されています。つまり、「シングルライン」です。複数行のアラート/フィードバックを表示したい場合は、ユーザーがメッセージを読んだ後にアクションを実行できるため、ダイアログを表示することをお勧めします。
mudit 2015年

3
@muditは国際化について考えています。英語の文字列が1行に収まる場合でも、ドイツ語は収まらない場合があります。また、Googleはマルチラインスナックバーのマテリアルデザイン仕様を提供しました(質問でリンクしました)-なぜそれを避ける必要があるのですか?
ディマコルニーロフ2015年

回答:


223

maxLinesSnackbarsTextviewの属性を設定するだけです

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、スナックバーのTextViewにアクセスします。

使用することもできますR.id.snackbar_text。それは私のために働いています。


必要な実際の行数を計算する方法はありますか、それとも推測する必要がありますか?
クリス

@ChrisはAndroidにあるかもしれませんが、テキストが短い場合はmaxLineを指定でき、自動的に縮小されます...
Nilesh Senta

22
最新のandroidxライブラリの場合、com.google.android.material.R.id.snackbar_textである必要があります。ただし、IMHO IDは将来変更される可能性があるため、この方法は避けてください。
mtsahakis

1
これは、サポートライブラリのバージョンごとに変更される可能性のあるTextView IDに依存しているため、この回答は実際には永続的な解決策ではなく、ハックです。動作する可能性がありますが、本番環境でランダムに破損する可能性もあります。
Chapz

1
これに推奨されるAPIはありますか?この方法がハックであることに同意しますが、これに対して公開されているAPIがない場合、代替手段はありません。
fobbymaster

31

アプリのvalues.xmlで使用されている事前定義された値をオーバーライドできます

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

この値は、Snackbarによってデフォルトで使用されます。


18
これはデザインライブラリによって定義されたプライベート整数であり、アプリでコンパイルエラーやランタイムエラーを生成せずに名前を変更したり削除したりできるため、この方法は避けてください。
Oasis Feng

4
はい。ただし、これはOSのプライベートリソースへのアクセスとは大きく異なることを明確にする必要があると思います。これは、同じバージョンのデザインライブラリに固執している限り機能します。新しいバージョンに更新する場合は、とにかくアプリを徹底的にテストする必要があります。これをチェックリストに入れてください。
devconsole 2016

これは、1行しか表示されないように見えるKindleFireデバイスでは機能しないことをお知らせします。@Nileshの回答は機能しました。
Naveen Dissanayake 2018年

1
チェックリストが長くなるという考えが気に入らないので、反対票を投じました。
ban-geoengineering 2018年

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はマルチラインスナックバーをサポートしていますが、マルチラインスナックバーの高さは80dp(ほぼ2行)であると記載されている設計ガイドラインに一致する最大2行の制限があります

これを確認するために、cheesesquareandroidサンプルプロジェクトを使用しました。次の文字列を使用する場合:

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

この場合、2行目のテキスト、つまり「2番目のスナックバーがトリガーされたとき」の複数行のスナックバーが表示されますが、このコードを次の実装に変更すると、次のようになります。

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

「ランダムテキスト\ nいつ...」しか表示されませ。これは、デザインライブラリが意図的にテキストビューを最大2行にすることを強制していることを意味します。


2
私はこの答えを受け入れましたが、材料の仕様には112dpのスナックバーも記載されています:i.imgur.com/1ACCoQb.png
Dima Kornilov

マルチラインスナックバーの高さを寸法で指定できますか?
alp 2015年


1
そのガイドラインを受け入れたくない場合は、ガイドラインに従わないでください。グーグルがそのガイドラインとツールにおいて、グラドルビルドシステムが開発者にとって頭痛の種である理由よりもはるかに正しいとしたら?
ジガー2015年

@DimaKornilov完全に2行の長さのテキストがあり、アクションを指定した場合にのみ、112dpに設定されます。その場合、アクションによりスナックバーが112dpに拡張されます。
クリストファー・ルチンスキー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

スナックバーに含まれるテキストビューのリソース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;
}

テキスト何とか常にnullは
stannums

コードを再確認してください。スナックバーのレイアウトのAOSPソースコードは次のとおりです。そこにTextViewオブジェクトがあることに気付くでしょう。そのため、テキストをnullにすることはできません。
Chantell Osejo 2017年

findViewsWithTextあなたはすでにテキストを知っているので、を使用する方がさらに良いかもしれません。このソリューションは、いくつかの状況で機能しなくなる可能性があります(たとえば、テキストビューがスナックバーレイアウトの子の子になる場合)。
natario 2017年

これは私にはうまくいきません。SnackbarLayoutには、その内部に別のビューがあります。したがって、snackbarLayout.getChildAt()を返すことはありませんTextView
Vitor Hugo Schwaab

2

setMaxLinesを使用する代わりに、setSingleLineを使用してテキストビューをそのコンテンツにラップします。

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

マテリアルコンポーネントライブラリを使用するとsnackbarTextViewStyle、アプリテーマの属性を使用して定義できます。

<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
良い点ですが、ライブラリはまだアルファ状態です(2020年5月):)
アントンマリシェフ

2

Kotlinでは、次のことができます

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

また、置き換えることができsetSingleLine(false)maxLines = 3

AndroidStudioは追加するように促します

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私もそれを再び動作させることができないので、私は答えを更新しました。
ガンビーザグリーン

今のクラッシュ: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setSingleLine(boolean)' on a null object reference
アンドロイド開発者

@androiddeveloperこの依存関係implementation 'com.google.android.material:material:1.1.0'はありますcom.google.android.material.snackbar.Snackbarか:そしてあなたのSnackbarは1つですか?そうでない場合は、android.support.design.R.id.snackbar_textリソースIDとして試してください。
ガンビーザグリーン

これらは、新しいプロジェクトを作成したときに得られるものであり(私もそうしました)、クラッシュしました。
Androidの開発者

1

新しいバージョンのライブラリで状況が変わってもクラッシュしない方法:

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

また、IDを使用せずにこれを行う方法として、スナックバーのすべてのTextViewを無制限の複数行に設定します。

@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

グーグルの最新のマテリアルデザインライブラリを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
        }
    }
}

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.