MotionLayout causes text in child views to be clipped on resize, how to fix this?

37 Views Asked by At

First time playing with MotionLayout in an attempt to solve some animation bugs in nested RecyclerView when resizing items (expanding/collapsing animation).

In the RecyclerView the default expand animation works just fine, but when it collapses it hides the content instantly and only then moves the bottom items, so I decided to find a way to achieve a proper expand/collapse animation using MotionLayout instead.

Below is an example of what I was able to accomplish so far: enter image description here

I don't want it to animate the width, so I can simply animate the height of the container from 0dp to wrap_content just fine, but for the purpose of this example, and to keep things simple, I let it be a simple animation between visibility gone to visible, but the issue happens on either case.

The problem with either one of the methods I used is the resizing keeps clipping any text in the child views, see below what I mean:

enter image description here

As you can see, the letters are cut off before the bottom of their parent container is actually covering them, and I have discovered that this is because of their views, or parent views, using either padding, margin, or both.

Unfortunately the solution is not a simple "just don't use margins and paddings", because then it becomes impossible to dynamically add spacing around text when each device may have different font scale settings, nor can I simply use specific heights and widths for the same reason.

Sadly, no amount of disabling clipChildren and clipToPadding works, I've set these attributes to the entire hierarchy and made no difference.

I also tried putting the textView inside a container, and adding either margin or padding to each one, but the same problem still occurs.

I also already tried with the motion:layoutDuringTransition="honorRequest" and without, and it made no difference for this case.

Is there no way to prevent the text inside from getting clipped during the animation/transition?

Below is the layout file:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
    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="wrap_content"
    android:clipChildren="false"
    android:clipToPadding="false"
    app:layoutDescription="@xml/item_motion_scene">

    <LinearLayout
        android:id="@+id/headerContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#42A5F5"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        app:layout_constraintBottom_toTopOf="@id/bottom"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/label"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_weight="1"
            android:textColor="@color/white"
            tools:text="my label"/>

        <FrameLayout
            android:id="@+id/toggleSizeContainer"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:clickable="true"
            android:clipChildren="false"
            android:focusable="true">

            <ImageView
                android:id="@+id/toggleSize"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_gravity="center"
                android:contentDescription="@string/app_name"
                android:duplicateParentState="true"
                android:foreground="?selectableItemBackgroundBorderless"
                android:src="@drawable/baseline_expand_more_24"
                app:tint="@color/white"/>

        </FrameLayout>

        <FrameLayout
            android:id="@+id/removeContainer"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:clickable="true"
            android:clipChildren="false"
            android:focusable="true">

            <ImageView
                android:id="@+id/remove"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_gravity="center"
                android:contentDescription="@string/app_name"
                android:duplicateParentState="true"
                android:foreground="?selectableItemBackgroundBorderless"
                android:src="@drawable/baseline_close_24"
                app:tint="@color/white"/>

        </FrameLayout>

    </LinearLayout>

    <LinearLayout
        android:id="@+id/bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#E57373"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:orientation="vertical"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/headerContainer"
        tools:visibility="visible">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:background="#BA68C8">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:clipChildren="false"
                android:clipToPadding="false"
                android:layout_margin="16dp"
                android:text="a"
                tools:ignore="HardcodedText"/>

        </LinearLayout>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#FFB74D"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:padding="16dp"
            android:text="b"
            tools:ignore="HardcodedText"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#81C784"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:padding="16dp"
            android:text="c"
            tools:ignore="HardcodedText"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#FF8A65"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:padding="16dp"
            android:text="d"
            tools:ignore="HardcodedText"/>

    </LinearLayout>

</androidx.constraintlayout.motion.widget.MotionLayout>

and the respective motion file:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/bottom"
            motion:layout_constraintEnd_toEndOf="parent"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            android:visibility="gone"
            motion:layout_constraintTop_toBottomOf="@id/headerContainer"
            motion:layout_constraintStart_toStartOf="parent"/>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/bottom"
            motion:layout_constraintEnd_toEndOf="parent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            android:visibility="visible"
            motion:layout_constraintTop_toBottomOf="@id/headerContainer"
            motion:layout_constraintStart_toStartOf="parent"/>
    </ConstraintSet>

    <Transition
        motion:layoutDuringTransition="ignoreRequest"
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/end">
    </Transition>
</MotionScene>
0

There are 0 best solutions below