我有这样的布局(我删除了一些属性,因为它们真的没关系,完整的演示项目是here):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content" (* this is important)
android:layout_height="wrap_content"
android:breakStrategy="balanced" (* this is important)
android:text="@string/long_text" />
</LinearLayout>
文本long_text
很长,所以它会分开几行。
两个重要的行是android:layout_width="wrap_content"
和android:breakStrategy="balanced"
。
我希望TextView
会根据实际的文字宽度来计算宽度,但它不会。
有人知道如何解决这个问题吗?
更新
属性android:breakStrategy="balanced"
仅适用于API 23
及更高版本。在我的示例中,文本需要3行,balanced
策略使每行的宽度大致相同。
我希望在这种情况下,视图宽度本身与最长行相同。
我正在寻找任何解决方法。我需要像环聊聊天一样的解决方案。我无法弄清楚它是如何运作的。
更新2
不幸的是,接受的答案不适用于RTL文本。
答案 0 :(得分:8)
这是因为当TextView计算其宽度时,它会将所有文本测量为1行(在您的情况下),并且在此步骤中它对android:breakStrategy一无所知。因此,它试图利用所有可用空间尽可能多地在第一行上呈现文本。
要了解更多详情,请查看方法int desired(Layout layout)
here
要修复它,您可以使用此类:
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Layout layout = getLayout();
if (layout != null) {
int width = (int) Math.ceil(getMaxLineWidth(layout))
+ getCompoundPaddingLeft() + getCompoundPaddingRight();
int height = getMeasuredHeight();
setMeasuredDimension(width, height);
}
}
private float getMaxLineWidth(Layout layout) {
float max_width = 0.0f;
int lines = layout.getLineCount();
for (int i = 0; i < lines; i++) {
if (layout.getLineWidth(i) > max_width) {
max_width = layout.getLineWidth(i);
}
}
return max_width;
}
}
我带到这里 - Why is wrap content in multiple line TextView filling parent?
答案 1 :(得分:1)
您需要以编程方式测量TextView
中文本的宽度,如下所示:
Rect bounds = new Rect();
textView.getPaint().getTextBounds(textView.getText().toString(), 0, textView.getText().length(), bounds);
现在,您可以在TextView
后面放置一个彩色矩形,并在测量文本后以编程方式设置其宽度(我使用FrameLayout
将视图置于另一个之上,但是您也可以使用RelativeLayout
:
XML:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="+@id/background"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/green" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:breakStrategy="balanced"
android:text="@string/long_text" />
</FrameLayout>
代码:
Rect bounds = new Rect();
textView.getPaint().getTextBounds(textView.getText().toString(), 0, textView.getText().length(), bounds);
View bg = findViewById(R.id.background);
gb.getLayoutParams().width = bounds.width();
代码未经测试,但我确信你明白了。
<强>更新强>
通过将view
宽度设置为匹配TextView
,可以在不使用第二个背景bounds.width()
的情况下执行此操作,但这会触发文本中断方式的更改,因此需要注意不要造成无限循环。