TextView works wrong with breakStrategy=“balanced” and layout_width=“wrap_content”

£可爱£侵袭症+ 提交于 2020-11-30 06:56:48

问题


I have such layout (I've removed some attributes, cause they really doesn't matter, full demo project is 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>

The text long_text is quite long, so it would be separated for a few lines.

Two important lines are android:layout_width="wrap_content" and android:breakStrategy="balanced".

I expect that TextView will calculate width according to the actual text width, but it doesn't.

Does anybody know how to fix this?

UPDATE

Attribute android:breakStrategy="balanced" works only for API 23 and higher. In my example text takes 3 lines, and balanced strategy makes each line approximately same width.

I expect that in this case width of view itself will be the same as the longest line.

I'm looking for any workaround. I need solution like in Hangouts chat. I can't figure out how it works.

UPDATE 2

Unfortunately, accepted answer doesn't work with RTL text.


回答1:


This happens because when TextView calculates its width it measure all text as 1 line (in your case) and on this step it knows nothing about android:breakStrategy. So it is trying to utilize all available space to render as much text on first line as it can.

To get more details, please check method int desired(Layout layout) here

To fix it you can use this class:

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;
}

}

which I took here - Why is wrap content in multiple line TextView filling parent?




回答2:


You'll need to measure the width of the text in TextView programatically, like so:

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

Now, you can place a colored rectangle behind the TextView, and set its width programatically after measuring the text (I'm using FrameLayout to put the Views one on top of the other, but you can use RelativeLayout as well):

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>

Code:

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

Code is untested, but I'm sure you get the point.

UPDATE

It may be possible to do this without using a second background view, by setting the TextView width to match bounds.width(), but this trigger a change in how the text breaks, so need to be careful not to cause an infinite loop.



来源:https://stackoverflow.com/questions/41481674/textview-works-wrong-with-breakstrategy-balanced-and-layout-width-wrap-conten

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!