Wie kann ich feststellen, ob meine Textansicht ellipsiert wurde?


77

Ich habe eine Mehrfachleitung TextView, die android:ellipsize="end"eingestellt hat. Ich würde jedoch gerne wissen, ob die Zeichenfolge, die ich dort platziere, tatsächlich zu lang ist (damit ich sicherstellen kann, dass die vollständige Zeichenfolge an anderer Stelle auf der Seite angezeigt wird).

Ich könnte verwenden TextView.length()und herausfinden, wie die ungefähre Länge der Zeichenfolge passt, aber da es sich um mehrere Zeilen handelt, müssen die TextViewZiehpunkte umbrochen werden, sodass dies nicht immer funktioniert.

Irgendwelche Ideen?

Antworten:


122

Sie können das Layout der erhalten TextViewund die Anzahl der Auslassungspunkte pro Zeile überprüfen. Für eine Endellipse reicht es aus, die letzte Zeile wie folgt zu überprüfen:

Layout l = textview.getLayout();
if (l != null) {
    int lines = l.getLineCount();
    if (lines > 0)
        if (l.getEllipsisCount(lines-1) > 0)
            Log.d(TAG, "Text is ellipsized");
}

Dies funktioniert erst nach der Layoutphase, andernfalls ist das zurückgegebene Layout null. Rufen Sie dies an einer geeigneten Stelle in Ihrem Code auf.


7
Dies schlägt fehl, wenn Sie in der letzten Zeile Ihrer Eingabe einen langen Text ohne Leerzeichen eingeben, z. getEllipsisCount () gibt in diesem Fall 0 zurück. Um dies zu beheben, müssen Sie nicht nur die letzte Zeile überprüfen, sondern alle Zeilen durchlaufen und prüfen, ob (l.getEllipsisCount (n)> 0) true zurückgibt. für alle 0 <= n <Zeilen.
Tiago

1
Aufgrund eines getEllipsisCountFunktionsfehlers in API <= 14 schlägt dies fehl und gibt 0 zurück, wenn der Text Sonderzeichen wie '\ n' enthält. So können Sie es umgehen , indem sie die Unterstützung Bibliotheken und Ersetzen if (l.getEllipsisCount(lines-1) > 0)mit if (l.getEllipsisCount(lines-1) > 0 || TextViewCompat.getMaxLines(this)).
Bam

1
Ugh, verwenden Sie Klammern auch für einzeilige Anweisungen,
wenn Sie möchten

@ r3flssExlUtr, und deshalb genau?
Zarsky

Könnten Sie bitte näher erläutern, was Sie unter der Layoutphase verstehen? Meinen Sie, während das Layout aufgeblasen ist und warum sollte das später null werden?
6rchid

34

textView.getLayout ist der richtige Weg, aber das Problem dabei ist, dass es null zurückgibt, wenn das Layout nicht vorbereitet ist. Verwenden Sie die folgende Lösung.

 ViewTreeObserver vto = textview.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
           Layout l = textview.getLayout();
           if ( l != null){
              int lines = l.getLineCount();
              if ( lines > 0)
                  if ( l.getEllipsisCount(lines-1) > 0)
                    Log.d(TAG, "Text is ellipsized");
           }  
        }
    });

Code-Snippet zum Entfernen des Listeners ( Quelle ):

mLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    public void onGlobalLayout() {
        scrollToGridPos(getCenterPoint(), false);
        mLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);        
    }
});

16
Vergiss nicht, removeOnGlobalLayoutListener()wenn du es nicht mehr brauchst.
mmathieum

1
Fügen Sie dies hinzu, wenn die Ellipsengröße gefunden wird: if (Build.VERSION.SDK_INT <16) {textview.getViewTreeObserver (). RemoveGlobalOnLayoutListener (this); } else {textview.getViewTreeObserver (). removeOnGlobalLayoutListener (this); }
Daniel Wilson

17
Verwenden Sie view.post () anstelle von VTO! Es ist viel einfacher.
eine Person

Noch mehr ugh, verwenden Sie Klammern auch für einzeilige Anweisungen ifs
r3flss ExlUtr

1. Bei Verwendung des Typs In Kotlin hat das angegebene Layout des Fehlerklassifizierers kein Begleitobjekt . 2. Funktion gab 0 zurück . Bitte helfen Sie mirLayoutgetEllipsisCount
NIKUNJ GADHIYA

31

Ich denke, die einfachste Lösung für diese Frage ist der folgende Code:

String text = "some looooong text";
textView.setText(text);
boolean isEllipsize = !((textView.getLayout().getText().toString()).equalsIgnoreCase(text));

Dieser Code setzt voraus, dass die Textansicht in Ihrem XML ein maxLineCount:) gesetzt hat


3
faul aber effektiv :-D
msamardzic

4
Ihr Test schlägt fehl, wenn eine Großschreibung festgelegt ist. Fügen Sie beiden Zeichenfolgen toLowerCase () -Aufrufe hinzu.
Yarh

1
Wenn Ihr textView.getLayout () null zurückgibt, sollten Sie Folgendes verwenden: final ViewTreeObserver vto = tv.getViewTreeObserver (); vto.addOnGlobalLayoutListener (neuer ViewTreeObserver.OnGlobalLayoutListener () {@Override public void onGlobalLayout () {tv.getViewTreeObserver (). removeOnGlobalLayoutListener (this); Layout layout = tv. toString ()). equalsIgnoreCase (text))) {// ellipsized} else {// NOT ellipsized}}});
Royz

3
Sie müssen dies tun, nachdem textView den Text gerendert hat. textView.post (() -> {// mach es hier})
Sarith NOB

Seltsamerweise ist die Länge beider Objekte gleich, aber sie unterscheiden sich von dem, was sichtbar ist.
Sufian

6

Das hat bei mir funktioniert:

textView.post(new Runnable() {
                        @Override
                        public void run() {
                            if (textView.getLineCount() > 1) {
                                //do something
                            }
                        }
                    });

hat meinen Tag gerettet, weil ViewTreeObserver in RecyclerView nicht gut funktioniert
kilian eller

4

public int getEllipsisCount (int line) :

Gibt die Anzahl der Zeichen zurück, die entfernt werden sollen, oder 0, wenn keine Auslassungspunkte vorhanden sein sollen.

Rufen Sie einfach an:

int lineCount = textview1.getLineCount();

if(textview1.getLayout().getEllipsisCount(lineCount) > 0) {
   // Do anything here..
}

Da getLayout () nicht aufgerufen werden kann, bevor das Layout festgelegt wurde, verwenden Sie Folgendes:

ViewTreeObserver vto = textview.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
       Layout l = textview.getLayout();
       if ( l != null){
          int lines = l.getLineCount();
          if ( lines > 0)
              if ( l.getEllipsisCount(lines-1) > 0)
                Log.d(TAG, "Text is ellipsized");
       }  
    }
});

Und schließlich vergessen Sie nicht, removeOnGlobalLayoutListener zu entfernen, wenn Sie es nomore benötigen.


Sie können die Antwort mit der richtigen bearbeiten. @FrancescoDonzello
amalBit

Könnte sein, dass der Code nicht hervorragend ist, aber der Ansatz ist es sicher. Dies löste mein Problem bei der Feststellung, ob der Text elippsized wurde. Dieser Ansatz ist sehr nützlich, wenn Sie dem Fenster über den Fenstermanager Ansichten hinzufügen.
Yoraco Gonzales

Leider scheint es so, als würde die Ellipse, wenn sie direkt in einer leeren Zeile ("\ n") auftritt, auch 0 zurückgeben, was richtig ist, da sie im 0-Indexzeichen vorkommt. In diesem Fall scheint es also keine Möglichkeit zu sein, dies zu sagen ...
Shyri,

3
lateinit var toggleMoreButton: Runnable
toggleMoreButton = Runnable {
  if(reviewTextView.layout == null) { // wait while layout become available
       reviewTextView.post(toggleMoreButton) 
       return@Runnable
  }
  readMoreButton.visibility = if(reviewTextView.layout.text.toString() != comment) View.VISIBLE else View.GONE
}
reviewTextView.post(toggleMoreButton)

Es ist ein typischer Fall:

  1. Kommentar in 'reviewTextView'
  2. Kommentar kann durch einige Kriterien reduziert werden
  3. Wenn der Kommentar zusammengebrochen ist, wird die Schaltfläche 'readMoreButton' angezeigt.

Diese Antwort kann mit einer kurzen
Texterklärung

Ich muss sagen, es war kurz präzise und es wurde in Kotlin geschrieben.
Raykud

3

Der Kotlin-Weg:

textView.post {
   if (textView.lineCount > MAX_LINES_COLLAPSED) {
   // text is not fully displayed
   }
}

View.post()Wird tatsächlich ausgeführt, nachdem die Ansicht gerendert wurde, und führt die bereitgestellte Funktion aus


1

es funktioniert für mich

if (l != null) {
    int lines = l.getLineCount();
     if (lines > 0) {
     for (int i = 0; i < lines; i++) {
     if (l.getEllipsisCount(i) > 0) {
      ellipsize = true;
      break;
     }
    }
   }
  }

1

Einfache Kotlin-Methode. Ermöglicht android:ellipsizeund android:maxLinesverwendet werden

fun isEllipsized(textView: TextView, text: String?) = textView.layout.text.toString() != text

Hallo, ich verstehe, dass Sie es in Kotlin konvertiert haben, aber es scheint bereits eine Antwort zu geben, die genau das gleiche tut, was Sie in Java getan haben. Beim nächsten Mal können Sie möglicherweise die vorhandene Antwort bearbeiten oder eine Änderung im Kommentar zur Antwort vorschlagen, anstatt eine völlig neue Antwort hinzuzufügen. Viel Spaß beim Codieren !!
weil_im_batman

0

Arbeiten Sie also wirklich so, dass Sie beispielsweise vollständige Daten von RecyclerView an den Dialog übergeben:

holder.subInfo.post(new Runnable() {
                @Override
                public void run() {
                    Layout l = holder.subInfo.getLayout();
                    if (l != null) {
                        final int count = l.getLineCount();
                        if (count >= 3) {
                            holder.subInfo.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    final int c = holder.subInfo.getLineCount();
                                    if (c >= 3) {
                                        onClickToShowInfoDialog.showDialog(holder.title.getText().toString(), holder.subInfo.getText().toString());
                                    }
                                }
                            });
                        }
                    }
                }
            });

0

Hier ist die Kotlin-Version, die @Thorstenvv awnser mit @Tiano fix kombiniert:

val layout = textView.layout ?: return@doOnLayout
val lines = layout.lineCount
val hasLine = lines > 0
val hasEllipsis = ((lines - 1) downTo 0).any { layout.getEllipsisCount(it) > 0 }
if (hasLine && hasEllipsis) {
    // Text is ellipsized
}

0

In Kotlin können Sie den folgenden Code verwenden.

var str= "Kotlin is one of the best languages."
textView.text=str
textView.post {
val isEllipsize: Boolean = !textView.layout.text.toString().equals(str)

if (isEllipsize) {
     holder.itemView.tv_viewMore.visibility = View.VISIBLE
} else {
     holder.itemView.tv_viewMore.visibility = View.GONE
}    
}

-1

Die Verwendung getEllipsisCountfunktioniert nicht mit Text, der leere Zeilen enthält. Ich habe den folgenden Code verwendet, damit es funktioniert:

message.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {

            if(m.isEllipsized == -1) {
                Layout l = message.getLayout();
                if (message.getLineCount() > 5) {
                    m.isEllipsized = 1;
                    message.setMaxLines(5);
                    return false;
                } else {
                    m.isEllipsized = 0;
                }
            }
            return true;
        }
    });

Stellen Sie sicher, dass maxLineCountin Ihrem XML kein Wert festgelegt ist. Anschließend können Sie lineCountin Ihrem Code nach dem suchen. Wenn dieser Wert größer als eine bestimmte Zahl ist, können Sie false zurückgeben, um das Zeichnen des Codes abzubrechen, TextViewund die Zeilenanzahl sowie ein Flag festlegen, um zu speichern, ob die Textansicht zu lang ist oder nicht . Die Textansicht wird erneut mit der richtigen Zeilenanzahl gezeichnet und Sie wissen, ob sie mit der Flagge ellipsiert ist oder nicht.

Sie können dann die isEllipsizedFlagge verwenden, um alles zu tun, was Sie benötigen.


-1

Erstellen Sie eine Methode in Ihrer TextViewUtils- Klasse

public static boolean isEllipsized(String newValue, String oldValue) {
    return !((newValue).equals(oldValue));
}

Rufen Sie diese Methode auf, wenn dies erforderlich ist, z.

        if (TextViewUtils.isEllipsized(textviewDescription.getLayout().getText().toString(), yourModelObject.getDescription()))
            holder.viewMore.setVisibility(View.VISIBLE);//show view more option
        else
            holder.viewMore.setVisibility(View.GONE);//hide 

aber textView.getLayout () kann nicht aufrufen , bevor der Ansicht (Layout) gesetzt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.