TextView does not work correctly with breakStrategy = "balanced" and layout_width = "wrap_content"

I have such a layout (I deleted some attributes, because they really do not matter, the full demo project 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 quite long, so it will be divided into several lines.

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

I expect TextView to calculate the width according to the actual width of the text , but it is not.

screenshot

Does anyone know how to fix this?

UPDATE

The android:breakStrategy="balanced" attribute only works for API 23 and above. In my example, the text occupies 3 lines, and the balanced strategy makes each line approximately the same width.

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

I am looking for any workaround. I need a solution like in a Hangouts chat. I can’t understand how this works.

UPDATE 2

Unfortunately, the accepted answer does not work with RTL text.

+5
source share
2 answers

This is because when the TextView calculates its width, it measures all the text as 1 row (in your case), and at this point it knows nothing about android: breakStrategy. Therefore, he is trying to use all available space to render as much text as possible on the first line.

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

To fix this, 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 does the contents of the shell in several lines of the TextView fill the parent?

+7
source

You will need to measure the width of the text in the TextView programmatically, for example:

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

Now you can place the colored rectangle behind the TextView and set its width programmatically after measuring the text (I use FrameLayout to put the views on top of each other, but you can use 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> 

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

The code is not verified, but I'm sure you understand.

UPDATE

Perhaps this will be possible without using a second background view , setting the width of the TextView to match bounds.width() , but this will cause a change in the way the text breaks, so you need to be careful not to cause an infinite loop.

0
source

Source: https://habr.com/ru/post/1262341/


All Articles