Próbuję wykorzystać nowość Snackbar
z biblioteki wsparcia projektowania Androida, aby wyświetlić wielowierszowy pasek przekąskowy, jak pokazano na 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();
Wyświetla się tylko First line...
na moim Nexusie 7. Jak sprawić, by wyświetlał wszystkie linie?
PS: Spróbowałem Toast
i wyświetliło się wszystkie linie.
Odpowiedzi:
Wystarczy ustawić
maxLines
atrybut Snackbars TextviewView snackbarView = snackbar.getView(); TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text); textView.setMaxLines(5); // show multiple line
Jeśli używasz nowszej
"com.google.android.material:material:1.0.0"
zależności, użyjesz tego:com.google.android.material.R.id.snackbar_text
aby uzyskać dostęp do TextView Snackbar.Możesz użyć nawet
R.id.snackbar_text
. to dla mnie praca.źródło
Można zastąpić predefiniowaną wartość używaną do tego w values.xml aplikacji
<integer name="design_snackbar_text_max_lines">5</integer>
Ta wartość jest domyślnie używana przez Snackbar.
źródło
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();
źródło
Oto moje odkrycie:
Android obsługuje wielowierszowe paski przekąsek, ale ma maksymalny limit 2 linii, co odpowiada wytycznej projektowej, w której mówi, że wysokość wielowierszowego batonika powinna wynosić 80 dp (prawie 2 linie)
Aby to sprawdzić, użyłem przykładowego projektu cheesesquare android. Jeśli użyję następującego ciągu:
Snackbar.make(view, "Random Text \n When a second snackbar is triggered while the first is displayed", Snackbar.LENGTH_LONG) .setAction("Action", null).show();
W tym przypadku widzę wielowierszowy batonik z tekstem drugiego wiersza, tj. „Kiedy uruchamiany jest drugi pasek przekąskowy”, ale jeśli zmienię ten kod na następującą implementację:
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();
Widzę tylko „Losowy tekst \ nKiedy ... ”. Oznacza to, że biblioteka projektów celowo wymusza na widoku tekstowym maksymalnie 2 wiersze.
źródło
W przypadku Material Design odniesienie to
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()
źródło
Alternatywą dla sugestii, które obejmują zakodowanie na stałe identyfikatora zasobu dla widoku tekstu zawartego w pasku przekąskowym, jest iteracja w celu znalezienia TextView. Jest to bezpieczniejsze w dłuższej perspektywie i pozwala aktualizować bibliotekę wsparcia przy minimalnym strachu przed zmianą identyfikatora.
Przykład:
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; }
źródło
findViewsWithText
, ponieważ znasz już tekst. To rozwiązanie może się zepsuć w kilku sytuacjach (np. Jeśli nasz widok tekstu stanie się dzieckiem dziecka układu snackbar).snackbarLayout.getChildAt()
nigdy nie zwróciTextView
.Zamiast używać setMaxLines, używam setSingleLine, aby zawijać tekst do zawartości.
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();
źródło
to działa dla mnie
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();
źródło
Spóźniony, ale może być pomocny dla kogoś:
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(); }
źródło
Za pomocą biblioteki komponentów materiałów można ją zdefiniować za pomocą
snackbarTextViewStyle
atrybutu w motywie aplikacji:<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>
Uwaga : wymaga wersji 1.2.0 biblioteki.
źródło
W kotlin możesz używać rozszerzeń.
// SnackbarExtensions.kt fun Snackbar.allowInfiniteLines(): Snackbar { return apply { (view.findViewById<View?>(R.id.snackbar_text) as? TextView?)?.isSingleLine = false } }
Stosowanie:
Snackbar.make(view, message, Snackbar.LENGTH_LONG) .allowInfiniteLines() .show()
źródło
W Kotlinie możesz po prostu to zrobić
Snackbar.make(root_view, "Yo\nYo\nYo!", Snackbar.LENGTH_SHORT).apply { view.snackbar_text.setSingleLine(false) show() }
Można również wymienić
setSingleLine(false)
sięmaxLines = 3
.Android Studio powinno poprosić o dodanie
import kotlinx.android.synthetic.main.design_layout_snackbar_include.view.*
EDYTOWAĆ
Nie udało mi się ponownie uruchomić tego, więc po prostu podzielę się tym, co uważam za najczystszy sposób pisania w Kotlinie, co kilka innych już udostępniło:
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() }
źródło
snackbar_text
.java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setSingleLine(boolean)' on a null object reference
implementation 'com.google.android.material:material:1.1.0'
i czy Twój Snackbar jest tymcom.google.android.material.snackbar.Snackbar
jedynym? Jeśli nie, spróbujandroid.support.design.R.id.snackbar_text
jako identyfikator zasobu.Sposób na zrobienie tego, który nie ulegnie awarii w przypadku zmiany rzeczy w nowszych wersjach biblioteki:
Snackbar.make(...).setAction(...) { ... }.apply { (view.findViewById<View?>(R.id.snackbar_text) as? TextView?)?.setSingleLine(false) }.show()
I sposób na zrobienie tego bez używania identyfikatorów, ustawiając wszystkie TextViews w Snackbar tak, aby miały nieograniczoną liczbę wielu linii:
@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()
Ta sama funkcja w Javie:
@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()); }
źródło
Tylko krótki komentarz, jeśli używasz
com.google.android.material:material
prefiksu lub pakietu dlaR.id
powinno byćcom.google.android.material
val snackbarView = snackbar.view val textView = snackbarView.findViewById<TextView>(com.google.android.material.R.id.snackbar_text) textView.maxLines = 3
źródło
więc używam najnowszej biblioteki projektowania materiałów z Google
com.google.android.material:material:1.1.0
i użyłem prostego poniższego fragmentu kodu, aby rozwiązać kwestię zezwalania na więcej linii w pasku przekąskowym. mam nadzieję, że pomoże to również nowym programistom.TextView messageView = snackbar.getView().findViewById(R.id.snackbar_text); messageView.setMaxLines(5);
źródło
Aby uniknąć niestabilności innych odpowiedzi
updateMaxLine
, to rozwiązanie jest mniej prawdopodobne, jeśli Google zdecyduje się zmienić identyfikator widoku tekstu)val snackBar = Snackbar.make(view, message, duration) snackBar.view.allViews.updateMaxLine(5) snackBar.show()
uwaga, ta opcja zaktualizuje linię max dla wszystkich widoków tekstu w widoku Snakbar (co, nie sądzę, że ma to znaczenie)
dodaj to jako rozszerzenie
private fun <T> Sequence<T>.updateMaxLine(maxLine : Int) { for (view in this) { if (view is TextView) { view.maxLines = maxLine } } }
źródło