如何获取TextView的行数?

时间:2022-05-18 15:05:11

I want to get the number of lines of a text view

我想获得文本视图的行数

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

textView.getLineCount(); always returns zero

textView.getLineCount();总是返回零

Then I have also tried:

然后我也尝试过:

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

    }
});

It returns the exact output.

它返回确切的输出。

But this works only for a static layout.

但这仅适用于静态布局。

When I am inflating the layout dynamically this doesn't work anymore.

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

How could I find the number of line in a TextView?

我怎样才能在TextView中找到行数?

7 个解决方案

#1


59  

I was able to get getLineCount() to not return 0 using a post, like this:

我能够让getLineCount()不使用帖子返回0,如下所示:

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

#2


30  

As mentioned in this post,

如本文所述,

getLineCount() will give you the correct number of lines only after a layout pass.

只有布局通过后,getLineCount()才能为您提供正确的行数。

It means that you need to render the TextView first before invoking the getLineCount() method.

这意味着您需要在调用getLineCount()方法之前首先呈现TextView。

#3


17  

ViewTreeObserver is not so reliable especially when using dynamic layouts such as ListView.

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

Let's assume: 1. You will do some work depending on the lines of TextView. 2. The work is not very urgent and can be done later.

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

Here is my solution:

这是我的解决方案:

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

}

Usage:

用法:

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

#4


8  

I think the crux of this question is that people want to be able to find out the size of a TextView in advance so that they can dynamically resize it to nicely fit the text. A typical use might be to create talk bubbles (at least that was what I was working on).

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

I tried several solutions, including use of getTextBounds() and measureText() as discussed here. Unfortunately, both methods are slightly inexact and have no way to account for line breaks and unused linespace. So, I gave up on that approach.

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

That leaves getLineCount(), whose problem is that you have to "render" the text before getLineCount() will give you the number of lines, which makes it a chicken-and-egg situation. I read various solutions involving listeners and layouts, but just couldn't believe that there wasn't something simpler.

这留下了getLineCount(),其问题在于你必须在getLineCount()之前“渲染”文本,这将为你提供行数,这使得它成为鸡与蛋的情况。我阅读了涉及听众和布局的各种解决方案,但却无法相信没有更简单的东西。

After fiddling for two days, I finally found what I was looking for (at least it works for me). It all comes down to what it means to "render" the text. It doesn't mean that the text has to appear onscreen, only that it has to be prepared for display internally. This happens whenever a call is made directly to invalidate() or indirectly as when you do a setText() on your TextView, which calls invalidate() for you since the view has changed appearance.

在摆弄了两天之后,我终于找到了我想要的东西(至少它对我有用)。这一切都归结为“渲染”文本的意义。这并不意味着文本必须出现在屏幕上,只是必须准备好在内部显示。每当直接调用invalidate()或间接调用时,就会发生这种情况,就像在TextView上执行setText()一样,由于视图已更改外观,因此会调用invalidate()。

Anyway, here's the key code (assume you already know the talk bubble's lineWidth and lineHeight of a single line based on the font):

无论如何,这是关键代码(假设您已经知道基于字体的谈话气泡的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 );

Anyway, that's it. The next redraw will give a bubble tailor-made for your text.

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

Note: In the actual program, I use a separate bubble for determining lines of text so that I can resize my real bubble dynamically both in terms of length and width. This allows me to shrink my bubbles left-to-right for short statements, etc.

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

Enjoy!

请享用!

#5


7  

Based on @secnelis idea, there is even a more clean way if you target API 11 or higher.

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

Instead of extending a TextView you can use already built-in functionality if View.OnLayoutChangeListener

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

In ListAdapter.getView(), for instance

例如,在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
}

#6


0  

Are you doing this onCreate? The Views aren't laid out yet, so getLineCount() is 0 for a while. If you do this later in the Window LifeCycle, you'll get your line count. You'll have a hard time doing it onCreate, but onWindowFocusChanged with hasFocus=true usually has the Views measured by now.

你是在创造这个吗?视图尚未布局,因此getLineCount()暂时为0。如果您稍后在Window LifeCycle中执行此操作,您将获得行数。你将很难在onCreate上完成它,但onWindowFocusChanged与hasFocus = true通常现在有测量的视图。

The textView.post() suggestion is also a good one

textView.post()建议也很好

#7


0  

   holder.tv_prayerDesc.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                try {

                    final int lineCount =   holder.tv_prayerDesc.getLayout().getLineCount();
                    Log.e("linecount",lineCount+"");
                    if(lineCount<=5)
                    {
                        holder.show.setVisibility(View.GONE);

                    }

                }catch (Exception e)
                {
                    e.printStackTrace();
                }

                return true;
            }
        });

#1


59  

I was able to get getLineCount() to not return 0 using a post, like this:

我能够让getLineCount()不使用帖子返回0,如下所示:

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

#2


30  

As mentioned in this post,

如本文所述,

getLineCount() will give you the correct number of lines only after a layout pass.

只有布局通过后,getLineCount()才能为您提供正确的行数。

It means that you need to render the TextView first before invoking the getLineCount() method.

这意味着您需要在调用getLineCount()方法之前首先呈现TextView。

#3


17  

ViewTreeObserver is not so reliable especially when using dynamic layouts such as ListView.

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

Let's assume: 1. You will do some work depending on the lines of TextView. 2. The work is not very urgent and can be done later.

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

Here is my solution:

这是我的解决方案:

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

}

Usage:

用法:

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

#4


8  

I think the crux of this question is that people want to be able to find out the size of a TextView in advance so that they can dynamically resize it to nicely fit the text. A typical use might be to create talk bubbles (at least that was what I was working on).

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

I tried several solutions, including use of getTextBounds() and measureText() as discussed here. Unfortunately, both methods are slightly inexact and have no way to account for line breaks and unused linespace. So, I gave up on that approach.

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

That leaves getLineCount(), whose problem is that you have to "render" the text before getLineCount() will give you the number of lines, which makes it a chicken-and-egg situation. I read various solutions involving listeners and layouts, but just couldn't believe that there wasn't something simpler.

这留下了getLineCount(),其问题在于你必须在getLineCount()之前“渲染”文本,这将为你提供行数,这使得它成为鸡与蛋的情况。我阅读了涉及听众和布局的各种解决方案,但却无法相信没有更简单的东西。

After fiddling for two days, I finally found what I was looking for (at least it works for me). It all comes down to what it means to "render" the text. It doesn't mean that the text has to appear onscreen, only that it has to be prepared for display internally. This happens whenever a call is made directly to invalidate() or indirectly as when you do a setText() on your TextView, which calls invalidate() for you since the view has changed appearance.

在摆弄了两天之后,我终于找到了我想要的东西(至少它对我有用)。这一切都归结为“渲染”文本的意义。这并不意味着文本必须出现在屏幕上,只是必须准备好在内部显示。每当直接调用invalidate()或间接调用时,就会发生这种情况,就像在TextView上执行setText()一样,由于视图已更改外观,因此会调用invalidate()。

Anyway, here's the key code (assume you already know the talk bubble's lineWidth and lineHeight of a single line based on the font):

无论如何,这是关键代码(假设您已经知道基于字体的谈话气泡的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 );

Anyway, that's it. The next redraw will give a bubble tailor-made for your text.

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

Note: In the actual program, I use a separate bubble for determining lines of text so that I can resize my real bubble dynamically both in terms of length and width. This allows me to shrink my bubbles left-to-right for short statements, etc.

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

Enjoy!

请享用!

#5


7  

Based on @secnelis idea, there is even a more clean way if you target API 11 or higher.

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

Instead of extending a TextView you can use already built-in functionality if View.OnLayoutChangeListener

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

In ListAdapter.getView(), for instance

例如,在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
}

#6


0  

Are you doing this onCreate? The Views aren't laid out yet, so getLineCount() is 0 for a while. If you do this later in the Window LifeCycle, you'll get your line count. You'll have a hard time doing it onCreate, but onWindowFocusChanged with hasFocus=true usually has the Views measured by now.

你是在创造这个吗?视图尚未布局,因此getLineCount()暂时为0。如果您稍后在Window LifeCycle中执行此操作,您将获得行数。你将很难在onCreate上完成它,但onWindowFocusChanged与hasFocus = true通常现在有测量的视图。

The textView.post() suggestion is also a good one

textView.post()建议也很好

#7


0  

   holder.tv_prayerDesc.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                try {

                    final int lineCount =   holder.tv_prayerDesc.getLayout().getLineCount();
                    Log.e("linecount",lineCount+"");
                    if(lineCount<=5)
                    {
                        holder.show.setVisibility(View.GONE);

                    }

                }catch (Exception e)
                {
                    e.printStackTrace();
                }

                return true;
            }
        });