TextView错误的breakStrategy =" balanced"和layout_width =" wrap_content"

时间:2017-01-05 09:44:47

标签: android textview

我有这样的布局(我删除了一些属性,因为它们真的没关系,完整的演示项目是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会根据实际的文字宽度来计算宽度,但它不会。

screenshot

有人知道如何解决这个问题吗?

更新

属性android:breakStrategy="balanced"仅适用于API 23及更高版本。在我的示例中,文本需要3行,balanced策略使每行的宽度大致相同。

我希望在这种情况下,视图宽度本身与最长行相同。

我正在寻找任何解决方法。我需要像环聊聊天一样的解决方案。我无法弄清楚它是如何运作的。

更新2

不幸的是,接受的答案不适用于RTL文本。

2 个答案:

答案 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()的情况下执行此操作,但这会触发文本中断方式的更改,因此需要注意不要造成无限循环。