First of all, I have created a minimal demo to demonstrate the issue.
I have 2 TextView
on the top of my screen. The second one is on the right of the first one, with smaller size. Both display some content returned by API (So I don't know how long it needs to be - i.e. they have to be wrap_content
.)
Now I want to implement a sticky header with transition effect: When user scrolls up, the first TextView
will shrink to almost the same size with the second one, and keep themselves on the top of the screen. To achieve this, MotionLayout
seems to be a perfect fit.
Since I don't know the length of the content, so in order to animate the size of the first TextView
, I can only choose one of the below:
Approach 1 can be done by this solution. However, the animation is not smooth at all so it cannot be used.
So I tried approach 2. The layoutDescription
file transit the first TextView
from
<Constraint
android:id="@+id/tvFirst"
android:layout_width="wrap_content"
android:layout_height="32dp"
app:layout_constraintTop_toBottomOf="@id/vTop"
app:layout_constraintStart_toStartOf="parent"/>
to
<Constraint
android:id="@+id/tvFirst"
android:layout_width="wrap_content"
android:layout_height="24dp"
app:layout_constraintTop_toBottomOf="@id/vTop"
app:layout_constraintStart_toStartOf="parent"
android:transformPivotX="0dp"
android:transformPivotY="0dp"
android:scaleX="0.6"
android:scaleY="0.6"/>
The animation effect is great, but
The width of the TextView
does not change. Only its content scaled down. The problem here is, I want the second TextView
to stick to the end of the content, but now there is a large gap between them.
I tried to combine 2 approaches. i.e. I created a transparent TextView
as a dummy of the first TextView
, which animates using approach 1 (TextSize), and let the second TextView
constraint to the dummy instead. However, the width change occurs only after completing the transition, the second TextView
still stays at the same location during the transition.
How can I animate it smoothly with the second TextView
sticking to the end of the content of the first TextView
?
This is a know problem with out a good solution. By default MotionLayout Blocks relaying out during animation. This can be changed by the flag Transition:
<Transition motion:layoutDuringTransition="honorRequest" \>
This then means the layout is being resolved at every pass (which is slow) but might suit your needs. Another approach would be to use MotionLabel which was designed to do smooth scaling.
Which is designed to mitigate the scaling quantization with an attribute scaleFromTextSize
<androidx.constraintlayout.utils.widget.MotionLabel
app:textPanX="0"
app:scaleFromTextSize="40sp"
android:textSize="90sp"/>
This grabs "outlines" of the text from size and scales them to the desired size.
Long term we are looking for better solutions for this problem.