webentwicklung-frage-antwort-db.com.de

Wie bekomme ich die Anzahl der TextView-Zeilen?

Ich möchte die Anzahl der Zeilen einer Textansicht ermitteln 

textView.setText("Test line 1 Test line 2 Test line 3 Test line 4 Test line 5.............")

textView.getLineCount(); liefert immer null

Dann habe ich auch versucht:

ViewTreeObserver vto = this.textView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        ViewTreeObserver obs = textView.getViewTreeObserver();
        obs.removeGlobalOnLayoutListener(this);
        System.out.println(": " + textView.getLineCount());

    }
});

Es gibt die genaue Ausgabe zurück.

Dies funktioniert jedoch nur für ein statisches Layout.

Wenn ich das Layout dynamisch aufblase, funktioniert das nicht mehr.

Wie kann ich die Anzahl der Zeilen in einem TextView finden?

50
MAC

Ich konnte getLineCount() dazu bringen, 0 nicht mit einer post zurückzugeben, wie folgt:

textview.setText(“Some text”);
textview.post(new Runnable() {
    @Override
    public void run() {
        int lineCount = textview.getLineCount();
        // Use lineCount here
    }
});
68
Marilia

Wie in diesem post erwähnt, 

getLineCount() gibt Ihnen erst nach .__ die korrekte Zeilenanzahl. ein Layoutpass.

Das bedeutet, dass Sie zuerst die Variable TextView rendern müssen, bevor Sie die Methode getLineCount() aufrufen.

33
aymeric

ViewTreeObserver ist nicht besonders zuverlässig, wenn dynamische Layouts wie ListView verwendet werden.

Nehmen wir an, 1. Sie werden einige Arbeit erledigen, abhängig von den Zeilen von TextView . 2. Die Arbeit ist nicht sehr dringend und kann später erledigt werden.

Hier ist meine Lösung:

public class LayoutedTextView extends TextView {

        public LayoutedTextView(Context context) {
                super(context);
        }

        public LayoutedTextView(Context context, AttributeSet attrs) {
                super(context, attrs);
        }

        public LayoutedTextView(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
        }

        public interface OnLayoutListener {
                void onLayouted(TextView view);
        }

        private OnLayoutListener mOnLayoutListener;

        public void setOnLayoutListener(OnLayoutListener listener) {
                mOnLayoutListener = listener;
        }

        @Override
        protected void onLayout(boolean changed, int left, int top, int right,
                        int bottom) {
                super.onLayout(changed, left, top, right, bottom);

                if (mOnLayoutListener != null) {
                        mOnLayoutListener.onLayouted(this);
                }
        }

}

Verwendungszweck:

    LayoutedTextView tv = new LayoutedTextView(context);
    tv.setOnLayoutListener(new OnLayoutListener() {
            @Override
            public void onLayouted(TextView view) {
                    int lineCount = view.getLineCount();
                    // do your work
            }
    });
21
secnelis

Ich denke, das Entscheidende an dieser Frage ist, dass die Leute die Größe eines TextView-Objekts im Voraus herausfinden möchten, damit es dynamisch skaliert werden kann, um es an den Text anzupassen. Eine typische Verwendung könnte sein, Sprechblasen zu erzeugen (zumindest war das, woran ich gerade gearbeitet habe).

Ich habe verschiedene Lösungen ausprobiert, einschließlich der Verwendung von getTextBounds () und measureText () wie hier hier . Leider sind beide Methoden etwas ungenau und können Zeilenumbrüche und ungenutzte Zeilen nicht berücksichtigen. Also habe ich diesen Ansatz aufgegeben.

Damit bleibt getLineCount () zurück, dessen Problem darin besteht, dass Sie den Text "rendern" müssen, bevor getLineCount () die Anzahl der Zeilen angibt, was zu einer Hühnerei-Situation führt. Ich habe verschiedene Lösungen mit Zuhörern und Layouts gelesen, konnte aber einfach nicht glauben, dass es nichts Einfacheres gab.

Nachdem ich zwei Tage lang gefummelt hatte, fand ich endlich das, wonach ich gesucht hatte (zumindest funktioniert es bei mir). Es kommt darauf an, was es bedeutet, den Text "zu rendern". Das bedeutet nicht, dass der Text auf dem Bildschirm angezeigt werden muss, er muss nur für die interne Anzeige vorbereitet werden. Dies geschieht immer dann, wenn ein Aufruf direkt für invalidate () oder indirekt ausgeführt wird, als wenn Sie setText () für Ihre TextView ausführen, wodurch invalidate () für Sie aufgerufen wird, da die Ansicht ihr Aussehen geändert hat.

Wie auch immer, hier ist der Schlüsselcode (vorausgesetzt, Sie kennen bereits die Zeilenbreite und die Zeilenhöhe einer Sprechblase einer einzelnen Zeile, die auf der Schriftart basiert):

TextView talkBubble;
// No peeking while we set the bubble up.
talkBubble.setVisibility( View.INVISIBLE );
// I use FrameLayouts so my talk bubbles can overlap
// lineHeight is just a filler at this point
talkBubble.setLayoutParams( new FrameLayout.LayoutParams( lineWidth, lineHeight ) );
// setText() calls invalidate(), which makes getLineCount() do the right thing.
talkBubble.setText( "This is the string we want to dynamically deal with." );
int lineCount = getLineCount();
// Now we set the real size of the talkBubble.
talkBubble.setLayoutParams( new FrameLayout.LayoutParams( lineWidth, lineCount * lineHeight ) );
talkBubble.setVisibility( View.VISIBLE );

Jedenfalls ist es soweit. Beim nächsten Neuzeichnen wird eine für Ihren Text maßgeschneiderte Sprechblase angezeigt.

Hinweis: Im eigentlichen Programm verwende ich eine separate Sprechblase zum Bestimmen von Textzeilen, sodass ich meine tatsächliche Sprechblase sowohl in Bezug auf Länge als auch Breite dynamisch skalieren kann. Dadurch kann ich meine Blasen für kurze Anweisungen usw. von links nach rechts verkleinern.

Genießen!

8
Weeman

Basierend auf der Idee von @secnelis gibt es einen noch saubereren Weg, wenn Sie API 11 oder höher als Ziel verwenden.

Anstatt eine TextView zu erweitern, können Sie die bereits integrierte Funktionalität verwenden, wenn View.OnLayoutChangeListener

Zum Beispiel in ListAdapter.getView()

if (h.mTitle.getLineCount() == 0 && h.mTitle.getText().length() != 0) {
    h.mTitle.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(final View v, final int left, final int top,
                final int right, final int bottom, final int oldLeft,
                final int oldTop, final int oldRight, final int oldBottom) {
            h.mTitle.removeOnLayoutChangeListener(this);
            final int count = h.mTitle.getLineCount();
            // do stuff
        }
    });
} else {
    final int count = h.mTitle.getLineCount();
    // do stuff
}
8
 textView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

        @Override
        public boolean onPreDraw() {
            // Remove listener because we don't want this called before _every_ frame
            textView.getViewTreeObserver().removeOnPreDrawListener(this)

            // Drawing happens after layout so we can assume getLineCount() returns the correct value
            if(textView.getLineCount() > 2) {
                // Do whatever you want in case text view has more than 2 lines
            }  

            return true; // true because we don't want to skip this frame
        }
});
4
priti

Sie können die Anzahl der Zeilen auch mit dieser Funktion berechnen:

private fun countLines(textView: TextView): Int {
        return Math.ceil(textView.Paint.measureText(textView.text.toString()) /
                textView.measuredWidth.toDouble()).toInt()
    }

Beachten Sie jedoch, dass dies bei RecyclerView möglicherweise nicht sehr gut funktioniert.

0
4gus71n

Machst du diese onCreate? Die Views sind noch nicht angelegt, so dass getLineCount() für eine Weile 0 ist. Wenn Sie dies später im Windows-Lebenszyklus tun, wird Ihre Zeilenanzahl angezeigt. Sie werden es schwer haben, onCreate, aber onWindowFocusChanged mit hasFocus=true hat normalerweise die Ansichten, die jetzt gemessen werden. 

Der textView.post()-Vorschlag ist auch gut

0
Joe Plante