如何获取TextView的行数?

MAC*_*MAC 52 android textview

我想获得文本视图的行数

textView.setText("Test line 1 Test line 2 Test line 3 Test line 4 Test line 5.............")
Run Code Online (Sandbox Code Playgroud)

textView.getLineCount();总是返回

然后我也尝试过:

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

    }
});
Run Code Online (Sandbox Code Playgroud)

它返回确切的输出.

但这仅适用于静态布局.

当我动态地给布局充气时,这不再起作用了.

我如何在TextView中找到行数?

Mar*_*lia 80

我能够getLineCount()使用a返回0 post,如下所示:

textview.setText(“Some text”);
textview.post(new Runnable() {
    @Override
    public void run() {
        int lineCount = textview.getLineCount();
        // Use lineCount here
    }
});
Run Code Online (Sandbox Code Playgroud)


aym*_*ric 34

在本提到的职位,

getLineCount() 只有在布局通过后才会给出正确的行数.

这意味着您需要TextView在调用getLineCount()方法之前渲染第一个.

  • thax for ans但仍有问题 (3认同)
  • 这是对的.您不能正确添加侦听器.将OnGlobalLayoutListener直接添加到TextView实例,而不是父布局. (2认同)

小智 25

ViewTreeObserver不太可靠,特别是在使用ListView等动态布局时.

我们假设:1.您将根据TextView的行进行一些工作.这项工作不是很紧急,可以在以后完成.

这是我的解决方案:

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

}
Run Code Online (Sandbox Code Playgroud)

用法:

LayoutedTextView tv = new LayoutedTextView(context);
tv.setOnLayoutListener(new OnLayoutListener() {
        @Override
        public void onLayouted(TextView view) {
                int lineCount = view.getLineCount();
                // do your work
        }
});
Run Code Online (Sandbox Code Playgroud)

  • 整洁的方法.我在列表视图中使用了这种方法.奇迹般有效. (3认同)
  • @VikashKumarVerma 你能分享一下它在 recyclerView 中如何为你工作吗,它对我不起作用。 (2认同)

pri*_*iti 10

 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
        }
});
Run Code Online (Sandbox Code Playgroud)

  • 不知道为什么没有得到更多的投票。这需要选择的答案。一旦布局完成,使用布局侦听器将提供回调,这意味着在父级权限范围内无法进行任何更改。示例:有孩子的滚动视图。如何使所有孩子适应其中一个孩子发生的事情。因此,OnPreDraw可以更好,更有效地工作。 (3认同)

Wee*_*man 9

我认为这个问题的症结在于人们希望能够提前找出TextView的大小,以便他们可以动态调整大小以适应文本.一个典型的用途可能是创建谈话泡泡(至少这是我正在处理的).

我尝试了几种解决方案,包括使用getTextBounds()和measureText()的讨论在这里.不幸的是,这两种方法都有些不精确,无法解释换行符和未使用的行间距.所以,我放弃了这种方法.

这使得getLineCount(),它的问题是,你要"渲染" getLineCount之前的文本()会给你的行数,这使得它一个鸡和蛋的问题.我阅读了涉及听众和布局的各种解决方案,但却无法相信没有更简单的东西.

摆弄了两天之后,我终于找到了我想要的东西(至少它对我有用).这一切都归结为"渲染"文本的意义.这并不意味着文本必须出现在屏幕上,只是必须准备好在内部显示.出现这种情况,只要一个电话是直接向无效(),或间接地,当你在你的TextView,自认为已经改变了外观,调用无效()为你做的setText()作为.

无论如何,这是关键代码(假设您已经知道基于字体的谈话气泡的lineWidth和lineHeight的单行):

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 );
Run Code Online (Sandbox Code Playgroud)

无论如何,就是这样.下一次重绘将为您的文本量身定制一个泡泡.

注意:在实际程序中,我使用单独的气泡来确定文本行,以便我可以在长度和宽度方面动态调整我的真实气泡.这允许我从左到右缩小我的气泡用于简短陈述等.

请享用!

  • 我想这对你有用,因为你在代码中使用固定的线宽,或者是预先计算的.但是,对于换行内容或匹配父对象,这不起作用,因为仍然必须计算这些值. (3认同)

Yar*_*lyk 8

基于@secnelis的想法,如果您的目标是API 11或更高版本,甚至会有更简洁的方法.

如果TextView您可以使用已有的内置功能,而不是扩展View.OnLayoutChangeListener

例如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
}
Run Code Online (Sandbox Code Playgroud)


BVa*_*tur 6

您还可以PrecomputedTextCompat用于获取行数。常规方法:

fun getTextLineCount(textView: TextView, text: String, lineCount: (Int) -> (Unit)) {
    val params: PrecomputedTextCompat.Params = TextViewCompat.getTextMetricsParams(textView)
    val ref: WeakReference<TextView>? = WeakReference(textView)

    GlobalScope.launch(Dispatchers.Default) {
        val text = PrecomputedTextCompat.create(text, params)
        GlobalScope.launch(Dispatchers.Main) {
            ref?.get()?.let { textView ->
                TextViewCompat.setPrecomputedText(textView, text)
                lineCount.invoke(textView.lineCount)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

调用这个方法:

getTextLineCount(textView, "Test line 1 Test line 2 Test line 3 Test line 4 Test line 5.............") { lineCount ->
     //count of lines is stored in lineCount variable
}
Run Code Online (Sandbox Code Playgroud)

或者你可以像这样为它创建扩展方法:

fun TextView.getTextLineCount(text: String, lineCount: (Int) -> (Unit)) {
    val params: PrecomputedTextCompat.Params = TextViewCompat.getTextMetricsParams(this)
    val ref: WeakReference<TextView>? = WeakReference(this)

    GlobalScope.launch(Dispatchers.Default) {
        val text = PrecomputedTextCompat.create(text, params)
        GlobalScope.launch(Dispatchers.Main) {
            ref?.get()?.let { textView ->
                TextViewCompat.setPrecomputedText(textView, text)
                lineCount.invoke(textView.lineCount)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你这样称呼它:

textView.getTextLineCount("Test line 1 Test line 2 Test line 3 Test line 4 Test line 5.............") { lineCount ->
     //count of lines is stored in lineCount variable
}
Run Code Online (Sandbox Code Playgroud)