Search code examples
androidandroid-layoutandroid-linearlayouttextview

Android TextView not wrapping content when system wide font scaled larger


In my app I'm trying to adjust this layout so it's readable when the user scales the system wide font size in Android System settings -> Display -> Font size (or in accessibility settings on some devices). Doing some digging I found out this adjusts the device configuration font scale (getResources().getConfiguration.fontScale) from 1.0 to 1.15.

I'm getting some weird behavior in a LinearLayout where one of the TextViews width gets crushed, when it's set to wrap_content, and also doesn't reflect a set minWidth.

What it looks like normally normal What it looks like when font is scaled scaled

Here is the LinearLayout in question (comments added for context in screenshot)

    <LinearLayout
        android:id="@+id/sectionPaintStatus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:layout_marginTop="20dp"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <!-- () 6 Paint Items -->
        <LinearLayout
            android:id="@+id/sectionPaintItemToggle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clipToPadding="false"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:paddingBottom="5dp">

            <android.support.design.widget.FloatingActionButton
                android:id="@+id/fabExpandPaintItems"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="5dp"
                android:rotation="180"
                android:src="@drawable/ic_collapse"
                app:elevation="2dp"
                app:fabSize="mini"/>

            <TextView
                android:id="@+id/tvPaintItemCount"
                style="@style/Label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="5dp"
                android:text="0 Paint Items"
                android:textSize="16sp"/>

            <ImageView
                android:id="@+id/imgPaintAreaWarning"
                android:layout_width="20dp"
                android:layout_height="match_parent"
                android:layout_marginStart="10dp"
                android:scaleType="centerInside"
                android:src="@drawable/ic_edit_warning2"
                android:visibility="invisible"/>

        </LinearLayout>

        <!-- Inner layout to consume middle width and right align the rest -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="end"
            android:orientation="horizontal">

            <LinearLayout
                android:id="@+id/layoutPaintItemCount"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="end"
                android:orientation="vertical"
                android:visibility="invisible">

                <TextView
                    android:id="@+id/tvPaintItemCountStatus"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="2"
                    android:textSize="16sp"
                    android:textStyle="bold"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Paint Items"
                    android:textSize="16sp"/>

            </LinearLayout>

            <ImageView
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_marginStart="30dp"
                android:scaleType="centerInside"
                android:src="@drawable/ic_time"/>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="end"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tvPaintTime"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="2.5h"
                    android:textSize="16sp"
                    android:textStyle="bold"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Time"
                    android:textSize="16sp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="30dp"
                android:layout_marginEnd="30dp"
                android:minWidth="70dp"
                android:gravity="end"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tvPaintTotal"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="$123.22"
                    android:textSize="16sp"
                    android:textStyle="bold"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Total"
                    android:textSize="16sp"/>

            </LinearLayout>
        </LinearLayout>
    </LinearLayout>

Why is that last LinearLayout containing 2 TextViews not properly wrapping content? I tried removing the minWidth incase that was causing any issues and got the same result. I don't understand why all the other layouts wrap their content properly but the last one doesn't.

And is it possible to add a resource folder for scaled system wide font?

Edit It appears removing margins allow the TextView to wrap the proper width but obviously I need the margins. no margins

Can anyone explain this strange behavior?

Edit Solved It turns out I completely forgot about an invisible element in the layout between the "Paint Items" label and the time icon. It was causing me to run out of horizontal space.


Solution

  • You appear to have used layout_width="match_parent" and gravity="end" to align your elements.

    I assume on small devices (or with large text) you'd like the "0 Paint Items" to ellipsize when not enough space, and have the 'Time' and 'Total' fields to show at full width.

    To do this, we make the following changes:

    First, make the sectionPaintItemToggle have 0dp width and layout_weight="1" - this tells Android "this should fill as much space is available".

    <LinearLayout
        android:id="@+id/sectionPaintItemToggle"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        ... >
    

    I removed all the gravity="end" settings.

    I changed the "inner layout" (as per the comment) to be have wrap_content width.

    I deleted the entire layoutPaintItemCount layout - I feel like you were trying a different way to do the "N paint items" layout.

    In the end, we have something like this (I swapped in an ImageView for the FAB and just used resources I already had - I think I changed some margins too):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        android:id="@+id/sectionPaintStatus"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="20dp"
        android:layout_marginStart="20dp"
        android:layout_marginTop="20dp"
        android:gravity="center_vertical"
        >
    
        <!-- () 6 Paint Items -->
        <LinearLayout
            android:id="@+id/sectionPaintItemToggle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:clipToPadding="false"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:paddingBottom="5dp">
    
            <ImageView
                android:id="@+id/fabExpandPaintItems"
                android:layout_width="48dp"
                android:layout_height="48dp"
                android:layout_margin="5dp"
                android:rotation="180"
                android:src="@drawable/ic_edit_black_24dp"/>
    
            <TextView
                android:id="@+id/tvPaintItemCount"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="5dp"
                android:text="0 Paint Items"
                android:textSize="16sp"/>
    
            <ImageView
                android:id="@+id/imgPaintAreaWarning"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginStart="10dp"
                android:scaleType="centerInside"
                android:src="@drawable/ic_edit_black_24dp"
                android:visibility="invisible"/>
    
        </LinearLayout>
    
        <!-- Inner layout to consume middle width and right align the rest -->
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <ImageView
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:scaleType="centerInside"
                android:src="@drawable/ic_edit_black_24dp"/>
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical">
    
                <TextView
                    android:id="@+id/tvPaintTime"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="2.5h"
                    android:textSize="16sp"
                    android:textStyle="bold"/>
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Time"
                    android:textSize="16sp"/>
    
            </LinearLayout>
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="30dp"
                android:layout_marginStart="30dp"
                android:orientation="vertical">
    
                <TextView
                    android:id="@+id/tvPaintTotal"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="$123.22"
                    android:textSize="16sp"
                    android:textStyle="bold"/>
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Total"
                    android:textSize="16sp"/>
    
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>
    

    The key part was to convince Android that the "N Paint Items" view was the one you wanted to shrink.