constraintlayout icon indicating copy to clipboard operation
constraintlayout copied to clipboard

MotionLayout animation issue when recyclerview scrolling

Open cloner93 opened this issue 3 years ago • 3 comments

We have been working on an android project, and we faced with a problem in animation into the motionLayout when recyclerView is scrolling (you can see in video).

after scroll in anywhere on screen animation is fine but after scroll recyclerview appBar animation is run but so weird.

I added picture and video from UI architect to avoid confusion.

enter image description here

ProfileFragment.kt

    private fun coordinateMotion() {
        val appBarLayout: AppBarLayout? = binding.appbarLayout
        val motionLayout: MotionLayout = binding.profileHeaderInfo as MotionLayout

        val p = DecimalFormat("0.0");

        val listener = AppBarLayout.OnOffsetChangedListener { unused, verticalOffset ->
            val seekPosition = -verticalOffset / appBarLayout?.totalScrollRange!!.toFloat()
            motionLayout.progress = seekPosition
            Log.d(TAG, "coordinateMotion: $seekPosition")
        }

        appBarLayout?.addOnOffsetChangedListener(listener)
    }

ProfileFragment:

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:fillViewport="true"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <include
                android:id="@+id/profile_include"
                layout="@layout/profile_layout_content" />
        </androidx.core.widget.NestedScrollView>

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appbar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <androidx.constraintlayout.motion.widget.MotionLayout
                android:id="@+id/profile_header_info"
                android:layout_width="match_parent"
                app:motionDebug="SHOW_PATH"
                android:layout_height="wrap_content"
                android:minHeight="80dp"
                android:background="@color/primary"
                app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"
                app:layoutDescription="@xml/fragment_profile_xml_profile_header_info_scene"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent">

                .....

            </androidx.constraintlayout.motion.widget.MotionLayout>
        </com.google.android.material.appbar.AppBarLayout>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

app ui architect

fragment_profile_xml_profile_header_info_scene.xml

<?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/profile_user_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginEnd="24dp"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toEndOf="@+id/profile_image"
            motion:layout_constraintTop_toTopOf="@+id/profile_image">
        </Constraint>
        <Constraint
            android:id="@+id/profile_user_login"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toTopOf="@+id/profile_user_desc"
            motion:layout_constraintEnd_toEndOf="@+id/profile_user_name"
            motion:layout_constraintStart_toStartOf="@+id/profile_user_name"
            motion:layout_constraintTop_toBottomOf="@+id/profile_user_name">
        </Constraint>
        <Constraint
            android:id="@+id/profile_user_desc"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="@+id/profile_image"
            motion:layout_constraintEnd_toEndOf="@+id/profile_user_login"
            motion:layout_constraintStart_toStartOf="@+id/profile_user_login"
            motion:layout_constraintTop_toBottomOf="@+id/profile_user_login" />
        <Constraint
            android:id="@+id/profile_image"
            android:layout_width="75dp"
            android:layout_height="75dp"
            android:layout_marginStart="24dp"
            android:layout_marginTop="24dp"
            android:layout_marginEnd="16dp"
            android:elevation="10dp"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintHorizontal_bias="0.0"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />

    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/profile_user_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            motion:layout_constraintStart_toEndOf="@+id/profile_image"
            motion:layout_constraintTop_toTopOf="@+id/profile_image">
            <CustomAttribute
                motion:attributeName="textSize"
                motion:customDimension="10sp" />
        </Constraint>
        <Constraint
            android:id="@+id/profile_user_login"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="@id/profile_user_name"
            motion:layout_constraintStart_toEndOf="@+id/profile_user_name"
            motion:layout_constraintTop_toTopOf="@id/profile_user_name"
            motion:layout_constraintEnd_toEndOf="parent">

            <CustomAttribute
                motion:attributeName="textSize"
                motion:customDimension="8sp" />
        </Constraint>
        <Constraint
            android:id="@+id/profile_user_desc"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="@+id/profile_image"
            motion:layout_constraintEnd_toEndOf="@+id/profile_user_login"
            motion:layout_constraintStart_toStartOf="@+id/profile_user_name"
            motion:layout_constraintTop_toBottomOf="@+id/profile_user_name" />
        <Constraint
            android:id="@+id/profile_image"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginStart="24dp"
            android:layout_marginEnd="16dp"
            android:layout_marginBottom="16dp"
            android:elevation="10dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintHorizontal_bias="0.0"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
        <Constraint
            android:id="@+id/profile_header_divider"
            android:layout_width="0dp"
            android:layout_height="1dp"
            android:layout_marginTop="0dp"
            motion:layout_constraintEnd_toEndOf="@+id/profile_user_desc"
            motion:layout_constraintStart_toStartOf="@+id/profile_image"
            motion:layout_constraintTop_toBottomOf="@+id/profile_user_desc" />
        <Constraint
            android:id="@+id/profile_header_company_icon"
            android:layout_width="20dp"
            android:layout_height="20dp"
            motion:layout_constraintStart_toStartOf="@+id/profile_header_divider"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <Transition
        motion:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@id/start"
        motion:duration="1000">
        <KeyFrameSet>
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@+id/profile_header_divider" />
        </KeyFrameSet>
        <KeyFrameSet>
<!--            <KeyAttribute-->
<!--                android:alpha="0"-->
<!--                motion:framePosition="100"-->
<!--                motion:motionTarget="@+id/profile_user_desc" />-->
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@+id/profile_header_company" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@+id/profile_header_location" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@+id/profile_header_create_at" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@+id/profile_header_company_icon" />
            <KeyAttribute
                android:alpha="0.0"
                motion:framePosition="100"
                motion:motionTarget="@+id/profile_header_location_icon" />
            <KeyAttribute
                android:alpha="0"
                motion:framePosition="100"
                motion:motionTarget="@+id/profile_header_create_at_icon" />
        </KeyFrameSet>

        <OnSwipe />

    </Transition>
</MotionScene>

cloner93 avatar Nov 14 '21 05:11 cloner93

A few issues KeyFrames are for modifying the behavior between states. You seem to be trying to change the end constraintSet by using KeyFrames. That will lead to bugs. Generally motion:framePosition="100" is a bug except in complex situations. It is creating a difference between the final state (The ConstraintSet) and the transitions final state the (KeyAttributes)

add "android:alpha="0" to the end constraintsets's constraints

Also

You probably do not want the <OnSwipe> CoordnatorLayout is driving the animation. See MotionLayout examples

jafu888 avatar Nov 15 '21 19:11 jafu888

hi @jafu888 thanks for your help.

as you said, I deleted all KeyFrameSets and set android:alpha="0" in constraints. also i delete <OnSwip> , coordnatorLayout is driving the animation. But the problem remains.

ezgif-2-eacca465651b

cloner93 avatar Nov 19 '21 11:11 cloner93

Your code looks almost exactly like the example. The only thing I see odd is you set android:layout_height="wrap_content"

Not match parent
android:layout_height="match_parent"

Try that?

jafu888 avatar Nov 19 '21 20:11 jafu888