How to `wrap_content` while autosizing an Android TextView?
Asked Answered
O

4

17

Consider this layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:autoSizeTextType="uniform"
        android:gravity="center"
        android:maxLines="1"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_max="50dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>

Because of the height_max constraint this leads to a TextView where the text fills the vertical space but there's a lot of horizontal padding inside of the TextView:

autosized TextView

What I want is for the width of that TextView to be set such that it matches the width of the autosized text content. But when I set android:layout_width="wrap_content" the width gets set based on the non-autosized text content:

non-autosized TextView

Is there any way to get the best of both worlds---have the text autosize based on a known height, and then set the width based on the width of the autosized text?

Overlong answered 13/3, 2018 at 22:13 Comment(1)
First of all replace the ConstraintLayout with a FrameLayout and check if it at least behaves as expected then. Start with simple conditions and add variables if it works.Charles
G
12

Google's developer documentation specifically recommends against using wrap_content with autosized TextViews:

Note: If you set autosizing in an XML file, it is not recommended to use the value "wrap_content" for the layout_width or layout_height attributes of a TextView. It may produce unexpected results.

If you simply want your text to have a height of 50dp instead of 50sp, you could set the textSize to 50dp. But I suspect your goal is to have a textView that will autosize the text smaller based on layout constraints, and that solution won't do the job.

If you really can't have the extra horizontal space on your TextView from using a width of match_parent or 0dp, you could try programmatically setting the textview width layout parameter based on measuring the text with a TextPaint after the layout is created:

textView.post(new Runnable() {
    @Override
    public void run() {
        TextPaint textPaint = new TextPaint();
        textPaint.setTextSize(textView.getTextSize());

        float width = textPaint.measureText(textView.getText().toString());

        ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();
        layoutParams.width = (int)width;
        textView.setLayoutParams(layoutParams);
    }
});

Keep in mind that if you go this route, you'll probably want to add some left and right padding to it. TextViews have a sort of internal padding, even if you set their padding to zero - but that gets overridden when the width parameter is set directly.

Gilleod answered 13/3, 2018 at 23:3 Comment(2)
About the "internal padding" here is an article describing with precision all the different dimension surrounding and including the text: proandroiddev.com/android-and-typography-101-5f06722dd611Yarvis
If I get it right your code measures the width of a text string in a textView and sets the width of the textView to the measured width. So it's a workaround for autoSize + wrap_content. What I want is to measure the width of each word in a text string in a textView and get the maximum width. Then if the maximum width is larger than already set textView width, decrease textSize (or use autoSize) so that the longest word doesn't split. Height should be wrap_content. Does it relates to your answer? I can ask a new question if necessary.Pyuria
I
3

Try using 0dp (which equals MATCH_CONSTRAINT) for the android:layout_width attribute of the TextView.

Indivisible answered 13/3, 2018 at 22:34 Comment(5)
Adding that attribute along with a wrap_content width doesn't seem to have any effectOverlong
@JoshHansen Updated my answer, have a look please.Indivisible
0dp was the width in the first layout pictured, as can be seen in the layout XML I provided.Overlong
I also tried it using the 1.1.0-beta5 version of the constraint layout library, but no luck.Overlong
Perhaps let's try some things in the Stack Overflow Chat?Indivisible
B
0

It sounds like you want the display ratio of the text to change, for the text to act akin to scaleXY for an ImageView. Autosize does not do that. Rasterizing and scaling up is a bad approach as it will result in half-pixels. You could rasterize at the desired width and then squash the height, scaling the height down to minimise the distortion.

Begga answered 10/9, 2021 at 2:39 Comment(0)
R
-4

You can try this

<TextView
android:id="@+id/vName"
android:layout_width="56dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:text="Groupa"
app:autoSizeMinTextSize="12sp"
app:autoSizeMaxTextSize="20sp"
app:autoSizeTextType="uniform"
/>
Rapprochement answered 13/3, 2018 at 22:24 Comment(1)
The provided link doesn't seem to address the question at handOverlong

© 2022 - 2025 — McMap. All rights reserved.