Reputation: 979
I am trying to build a motion scene where two textviews are transitioned in a collapsing toolbar style from an expanded state to a collapsed state on dragging up.
The two textviews are positioned with some margins to the left and right side of the screen respectively and should be horizontally aligned to each other.
The first textview on the left side has a margin from the back button arrow on its left and needs to be left aligned in parent.
The second textview on the right side has a margin to its right and between the end of parent.
The two textviews needs to have a transition where the textsize smoothly translates.
How can I achieve the same?
Motionlayout:
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/motion_scene">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
android:paddingTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/space"/>
<View
android:id="@+id/space"
android:layout_width="0dp"
android:layout_height="110dp"
android:background="@color/white"
android:fitsSystemWindows="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:padding="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_view_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="80dp"
android:layout_marginEnd="10dp"
android:elevation="0dp"
android:textAlignment="viewStart"
android:textColor="@color/text_black"
android:text="text view 1"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="@id/space"
app:layout_constraintEnd_toStartOf="@id/text_view_2"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/text_view_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:elevation="0dp"
android:textAlignment="viewEnd"
android:textColor="@color/text_black"
android:text="text view 2"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="@id/space"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/text_view_1" />
</androidx.constraintlayout.motion.widget.MotionLayout>
Motionscene:
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/state_collapsed"
app:constraintSetStart="@id/state_expanded">
<OnSwipe
app:dragDirection="dragUp"
app:touchAnchorId="@id/recyclerview"
app:touchAnchorSide="top" />
<KeyFrameSet>
<KeyAttribute
app:framePosition="50"
app:motionTarget="@id/text_view_1">
<CustomAttribute
app:attributeName="textSize"
app:customFloatValue="20" />
</KeyAttribute>
<KeyAttribute
app:framePosition="50"
app:motionTarget="@id/text_view_2">
<CustomAttribute
app:attributeName="textSize"
app:customFloatValue="20" />
</KeyAttribute>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/state_collapsed">
<Constraint android:id="@id/back">
<CustomAttribute
app:attributeName="elevation"
app:customDimension="6dp" />
</Constraint>
<Constraint
android:id="@id/space"
android:layout_height="?attr/actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="elevation"
app:customDimension="6dp" />
</Constraint>
<Constraint
android:id="@id/text_view_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="80dp"
android:textAlignment="viewStart"
app:layout_constraintBottom_toBottomOf="@id/back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/back">
<CustomAttribute
app:attributeName="textSize"
app:customFloatValue="16" />
<CustomAttribute
app:attributeName="elevation"
app:customDimension="6dp" />
</Constraint>
<Constraint
android:id="@id/text_view_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:textAlignment="viewEnd"
app:layout_constraintBottom_toBottomOf="@id/text_view_1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/text_view_1">
<CustomAttribute
app:attributeName="textSize"
app:customFloatValue="16" />
<CustomAttribute
app:attributeName="elevation"
app:customDimension="6dp" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/state_expanded">
<Constraint android:id="@id/back">
<CustomAttribute
app:attributeName="elevation"
app:customDimension="0dp" />
</Constraint>
<Constraint
android:id="@id/space"
android:layout_height="110dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="elevation"
app:customDimension="0dp" />
</Constraint>
<Constraint
android:id="@id/text_view_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="80dp"
app:layout_constraintBottom_toBottomOf="@id/space"
app:layout_constraintEnd_toStartOf="@id/text_view_1"
app:layout_constraintStart_toStartOf="parent">
<CustomAttribute
app:attributeName="textSize"
app:customFloatValue="24" />
<CustomAttribute
app:attributeName="elevation"
app:customDimension="0dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
Upvotes: 0
Views: 2181
Reputation: 769
I had a similar goal in my project and I used android:scaleX
and android:scaleY
attributes in Constraints, because changing textSize
attr using CustomAttribute, didn't work smoothly. When you use android:scaleX
and android:scaleY
the view is scaled with a pivot in its center. So you may face alignment issues. You have to set android:transformPivotX="..."
and android:transformPivotY="..."
to change the default behavior. As a result, I had something like this in my case:
TextView I want to animate:
<TextView
android:id="@+id/title_tv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Text"
android:transformPivotX="0sp"
android:transformPivotY="24dp"/>
Motion Scene:
<?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">
<Transition
motion:constraintSetEnd="@id/collapsed"
motion:constraintSetStart="@id/expanded">
<OnSwipe
motion:dragDirection="dragUp"
motion:touchAnchorId="@+id/viewpager"
motion:touchAnchorSide="top" />
</Transition>
<ConstraintSet android:id="@+id/expanded">
<Constraint
android:id="@id/toolbar_image_iv"
android:layout_height="200dp"
...>
<CustomAttribute
motion:attributeName="imageAlpha"
motion:customIntegerValue="255" />
</Constraint>
<Constraint
android:id="@id/title_tv"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:scaleX="1.0"
android:scaleY="1.0"
...>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/collapsed">
<Constraint
android:id="@id/toolbar_image_iv"
android:layout_height="?attr/actionBarSize"
...>
<CustomAttribute
motion:attributeName="imageAlpha"
motion:customIntegerValue="0" />
</Constraint>
<Constraint
android:id="@id/title_tv"
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize"
android:scaleX="0.667"
android:scaleY="0.667"
...>
</Constraint>
</ConstraintSet>
</MotionScene>
Upvotes: 2
Reputation: 406
Try with below code and add dummy elements to recycler view for expected behavior.
Motion Layout:
<?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="match_parent"
tools:showPaths="true"
android:id="@+id/motionLayout"
app:layoutDescription="@xml/scene01">
<TextView
android:textColor="@android:color/black"
android:text="TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView1"/>
<ImageView
android:layout_width="40dp"
android:layout_height="40dp" app:srcCompat="@mipmap/ic_launcher"
android:id="@+id/imageView"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="24dp"
android:layout_marginTop="24dp" app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:text="TextView"
android:textColor="@android:color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView2"/>
<View android:layout_width="0dp"
android:layout_height="1dp"
android:id="@+id/view"
android:layout_marginTop="20dp"
app:layout_constraintTop_toBottomOf="@id/textView1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.recyclerview.widget.RecyclerView android:layout_width="0dp"
android:id="@+id/recyclerview"
app:layout_constraintTop_toBottomOf="@id/view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_height="0dp"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
MotionScene:
<?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">
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end">
<OnSwipe
motion:touchAnchorId="@+id/recyclerview"
motion:touchAnchorSide="top"
motion:dragDirection="dragUp"/>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toEndOf="@+id/imageView"
android:layout_marginStart="20dp" android:layout_marginTop="16dp"
motion:layout_constraintTop_toBottomOf="@+id/imageView">
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="25"/>
</Constraint>
<Constraint
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView2"
motion:layout_constraintTop_toTopOf="@+id/textView1"
motion:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="20dp">
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="25"/>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toEndOf="@+id/imageView"
android:layout_marginStart="20dp"
motion:layout_constraintTop_toTopOf="@+id/imageView">
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="15"/>
</Constraint>
<Constraint
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView2"
motion:layout_constraintTop_toTopOf="@+id/textView1"
motion:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="20dp">
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="15"/>
</Constraint>
</ConstraintSet>
</MotionScene>
Upvotes: 1