Android 如何获取TextView的行数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12037377/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get number of lines of TextView?
提问by MAC
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 中找到行数?
回答by Marilia
I was able to get getLineCount()
to not return 0 using a post
, like this:
我能够getLineCount()
使用 a 不返回 0 post
,如下所示:
textview.setText(“Some text”);
textview.post(new Runnable() {
@Override
public void run() {
int lineCount = textview.getLineCount();
// Use lineCount here
}
});
回答by aymeric
回答by secnelis
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
.
2. 工作不是很紧急,可以稍后再做。
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
}
});
回答by priti
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
}
});
回答by Weeman
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!
享受!
回答by Yaroslav Mytkalyk
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
如果不扩展,TextView
您可以使用已经内置的功能View.OnLayoutChangeListener
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
}
回答by BVantur
You could also use PrecomputedTextCompat
for getting the number of lines.
Regular method:
您还可以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)
}
}
}
}
Call this method:
调用这个方法:
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
}
Or maybe you can create extension method for it like this:
或者你可以像这样为它创建扩展方法:
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)
}
}
}
}
and then you call it like this:
然后你这样称呼它:
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
}
回答by 4gus71n
You can also calculate the amount of lines through this function:
您还可以通过此函数计算行数:
private fun countLines(textView: TextView): Int {
return Math.ceil(textView.paint.measureText(textView.text.toString()) /
textView.measuredWidth.toDouble()).toInt()
}
Keep in mind that It may not work very well on a RecyclerView
though.
请记住,虽然它可能无法很好地工作RecyclerView
。
回答by Mehedi Hasan Shagor
textview.getText().toString().split(System.getProperty("line.separator")).length
It works fine for me to get number of lines of TextView.
获取 TextView 的行数对我来说很好用。
回答by Joe Plante
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.
你在做这个onCreate
吗?视图尚未布局,因此暂时getLineCount()
为 0。如果稍后在 Window LifeCycle 中执行此操作,您将获得行数。你将有一个很难做onCreate
,但onWindowFocusChanged
与hasFocus=true
通常由现在测量的意见。
The textView.post()
suggestion is also a good one
该textView.post()
建议也是一个很好的