【问题标题】:TextView works wrong with breakStrategy="balanced" and layout_width="wrap_content"TextView 与 breakStrategy="balanced" 和 layout_width="wrap_content" 一起工作时出错
【发布时间】:2017-03-14 18:10:42
【问题描述】:

我有这样的布局(我已经删除了一些属性,因为它们真的无关紧要,完整的演示项目是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 文本。

【问题讨论】:

  • 你的意思是什么'我希望 TextView 会根据实际的文本宽度计算宽度,但事实并非如此' 而且你的实际似乎与应该是 like this
  • 我已经更新了问题。
  • @Oleksii Kropachov 您希望如何断行,可以说它比 1.5 行更长.. 那么您的预期输出是什么?

标签: android textview


【解决方案1】:

发生这种情况是因为当 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?

【讨论】:

  • 今天我意识到它不适用于 RTL 文本。
【解决方案2】:

您需要以编程方式测量TextView 中文本的宽度,如下所示:

Rect bounds = new Rect();
textView.getPaint().getTextBounds(textView.getText().toString(), 0, textView.getText().length(), bounds);

现在,您可以在TextView 后面放置一个彩色矩形,并在测量文本后以编程方式设置其宽度(我使用FrameLayout 将视图放在另一个之上,但您可以使用@ 987654325@也一样):

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

代码未经测试,但我相信你明白了。

更新

通过设置TextView 宽度以匹配bounds.width() 可以不使用第二个背景view 来执行此操作,但这会触发文本中断方式的更改,因此需要注意不要导致无限循环。

【讨论】:

  • 我之前试过这个,但textView.getPaint().getTextBounds() 没有按预期工作。
猜你喜欢
  • 2023-03-10
  • 2018-02-02
  • 2020-09-19
  • 2013-04-11
  • 1970-01-01
  • 1970-01-01
  • 2019-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多