Search code examples
androidandroid-animationandroid-motionlayout

MotionLayout roundPercent only works one time


I have an ImageFilterView view that I am animating using a MotionLayout. It starts as a small square view with roundPercent set to 1.0 (so that it is also a circle) that hides behind a circle and then animates to a full screen square. It works great the very first time it animates but every other time just stays as a rectangle.

You can see a video of the issue here: VIDEO

I'm not sure if it's a bug on the ImageFilterView or MotionLayout or if I'm calling something incorrectly. It's worth mentioning that instead of using an onClick in the Transition I am programatically calling it in the Activity like so

imageBorder.setOnClickListener {
        if (motionContainer.progress > 0.75)
            motionContainer.transitionToStart()
        else
            motionContainer.transitionToEnd()
    }

My motionScene code looks like the following

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
    motion:constraintSetEnd="@+id/end"
    motion:constraintSetStart="@+id/start"
    motion:duration="1000"
    motion:motionInterpolator="easeInOut" />

<ConstraintSet android:id="@+id/start">
    <Constraint android:id="@id/translucentOverlay">
        <Layout
            android:layout_width="5dp"
            android:layout_height="5dp"
            motion:layout_constraintBottom_toBottomOf="@id/imageBorder"
            motion:layout_constraintEnd_toEndOf="@id/imageBorder"
            motion:layout_constraintStart_toStartOf="@id/imageBorder"
            motion:layout_constraintTop_toTopOf="@id/imageBorder" />
        <CustomAttribute
            motion:attributeName="roundPercent"
            motion:customFloatValue="1.0" />
        <Motion motion:motionStagger="2" />
    </Constraint>

    <Constraint android:id="@id/imageBorder">
        <Layout
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
        <CustomAttribute
            motion:attributeName="crossfade"
            motion:customFloatValue="0" />
        <Motion motion:motionStagger="2" />
    </Constraint>

    <Constraint android:id="@id/imageBackground">
        <Layout
            android:layout_width="32dp"
            android:layout_height="32dp"
            motion:layout_constraintBottom_toBottomOf="@id/imageBorder"
            motion:layout_constraintEnd_toEndOf="@id/imageBorder"
            motion:layout_constraintStart_toStartOf="@id/imageBorder"
            motion:layout_constraintTop_toTopOf="@id/imageBorder" />
        <Motion motion:motionStagger="2" />
    </Constraint>
 </ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint android:id="@id/translucentOverlay">
        <Layout
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <CustomAttribute
            motion:attributeName="roundPercent"
            motion:customFloatValue="0.0" />
        <Motion motion:motionStagger="2" />
    </Constraint>

    <Constraint android:id="@id/imageBorder">
        <Layout
            android:layout_width="88dp"
            android:layout_height="88dp"
            motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
            motion:layout_constraintEnd_toEndOf="@id/imageBackground"
            motion:layout_constraintStart_toStartOf="@id/imageBackground"
            motion:layout_constraintTop_toTopOf="@id/imageBackground" />
        <CustomAttribute
            motion:attributeName="crossfade"
            motion:customFloatValue="1" />
        <Motion motion:motionStagger="2" />
    </Constraint>

    <Constraint android:id="@id/imageBackground">
        <Layout
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_marginTop="64dp"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
        <Motion motion:motionStagger="2" />
    </Constraint>
</ConstraintSet>

and my MotionLayout looks like this:

<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/motionContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
app:layoutDescription="@xml/motion_scene">

<androidx.constraintlayout.utils.widget.ImageFilterView
    android:id="@+id/translucentOverlay"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/translucent_background_square"/>

<androidx.constraintlayout.utils.widget.ImageFilterView
    android:id="@+id/imageBorder"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:layout_margin="8dp"
    android:padding="4dp"
    android:src="@drawable/circle_start"
    app:altSrc="@drawable/circle_end" />

<ImageView
    android:id="@+id/imageBackground"
    android:layout_width="32dp"
    android:layout_height="32dp"
    android:importantForAccessibility="no"
    android:tint="@color/primaryDarkColor"
    app:srcCompat="@drawable/circle_opaque" />
</androidx.constraintlayout.motion.widget.MotionLayout>

It's very annoying that it stops working after the first time. I have been trying to solve this circle to square problem for a very long time now and I thought I had finally found the solution but it appears not.


Solution

  • After more fiddling around, this appears to be a bug in ImageFilterView where if you set roundPercent to 0.0, the view will remain rectangle for the rest of the time. I imagine that it is an issue with dividing by 0 or some bug like that. I have reported the issue to Google Developers so hopefully that will get fixed soon.

    In the meantime, you can workaround the issue by setting percentRound to 0.000001 to get around the divide by zero bug.