我想获得文本视图的行数
textView.setText("Test line 1 Test line 2 Test line 3 Test line 4 Test line 5.............")
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());
}
});
它返回确切的输出。
但这仅适用于静态布局。
当我动态地给布局充气时,这不再起作用了。
如何在TextView中找到行数?
答案 0 :(得分:70)
我能够getLineCount()
使用post
不返回0,如下所示:
textview.setText(“Some text”);
textview.post(new Runnable() {
@Override
public void run() {
int lineCount = textview.getLineCount();
// Use lineCount here
}
});
答案 1 :(得分:33)
答案 2 :(得分:21)
ViewTreeObserver不太可靠,特别是在使用ListView等动态布局时。
我们假设: 1.您将根据TextView的行进行一些工作。 2.工作不是很紧急,可以在以后完成。
这是我的解决方案:
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);
}
}
}
用法:
LayoutedTextView tv = new LayoutedTextView(context);
tv.setOnLayoutListener(new OnLayoutListener() {
@Override
public void onLayouted(TextView view) {
int lineCount = view.getLineCount();
// do your work
}
});
答案 3 :(得分:8)
我认为这个问题的症结在于人们希望能够提前找出TextView的大小,以便他们可以动态调整大小以适应文本。一个典型的用途可能是创建谈话泡泡(至少这是我正在处理的)。
我尝试了几种解决方案,包括使用getTextBounds()和measureText()来讨论here。不幸的是,这两种方法都有些不精确,无法解释换行符和未使用的行间距。所以,我放弃了这种方法。
留下了getLineCount(),其问题在于你必须在getLineCount()之前“渲染”文本,这将为你提供行数,这使得它成为鸡与蛋的情况。我阅读了涉及听众和布局的各种解决方案,但却无法相信没有更简单的东西。
在摆弄了两天之后,我终于找到了我想要的东西(至少它对我有用)。这一切都归结为“渲染”文本的意义。这并不意味着文本必须出现在屏幕上,只是必须准备好在内部显示。只要直接调用invalidate()或间接调用TextView上的setText(),就会发生这种情况,因为视图的外观已经改变,所以会调用invalidate()。
无论如何,这是关键代码(假设你已经知道谈话气泡的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 );
无论如何,就是这样。下一次重绘将为您的文字量身定制一个泡泡。
注意:在实际程序中,我使用单独的气泡来确定文本行,以便我可以在长度和宽度方面动态调整我的真实气泡。这允许我从左到右缩小我的气泡用于简短陈述等。
享受!
答案 4 :(得分:8)
基于@secnelis idea,如果你的目标是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
}
答案 5 :(得分: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
}
});
答案 6 :(得分:1)
您还可以使用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)
}
}
}
}
调用此方法:
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
}
或者也许您可以像这样创建扩展方法:
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)
}
}
}
}
然后您这样称呼它:
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
}
答案 7 :(得分:0)
你这样做onCreate
吗?视图尚未布局,因此getLineCount()
暂时为0。如果您稍后在Window LifeCycle中执行此操作,您将获得行数。您将很难执行此操作onCreate
,但onWindowFocusChanged
hasFocus=true
通常会暂时测量视图。
textView.post()
建议也很好
答案 8 :(得分:0)
您还可以通过此函数计算行数:
private fun countLines(textView: TextView): Int {
return Math.ceil(textView.paint.measureText(textView.text.toString()) /
textView.measuredWidth.toDouble()).toInt()
}
请记住,尽管它在RecyclerView
上可能无法很好地工作。
答案 9 :(得分:0)
textview.getText().toString().split(System.getProperty("line.separator")).length
获取TextView的行数对我来说很好。