为何固定宽度的CustomView在MotionLayout旋转动画中尺寸异常?
问题
使用MotionLayout实现礼品卡的rotationY旋转动画效果,卡片是一个内部包含TickerView和两个TextView的CustomView。TextView的文本来自后端,长度不定但最多显示两行。CustomView在MotionScene和Fragment布局中均设置为match_parent宽度。
问题:执行旋转动画时,原本显示在第二行的TextView文字会跑到第一行,目前仅想到固定CustomView内部布局宽高的解决方式,求更优方案。
CustomView布局代码
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/openGiftContainer" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/bg_new_loyalty_rewarding_corners_card" android:gravity="center_horizontal" android:layout_gravity="center_horizontal" android:paddingVertical="@dimen/grid_3" android:orientation="vertical"> <ru.secret.secret.customviews.v3.ticker.TickerView android:id="@+id/ivIconTicker" android:layout_width="@dimen/grid_9" android:layout_height="@dimen/grid_9" tools:srcCompat="@drawable/circle_blue" /> <TextView android:id="@+id/tvTitle" style="@style/H0.TxtIconAlwaysBlack" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/grid_3_5" android:gravity="center" android:maxLines="2" android:ellipsize="end" android:paddingHorizontal="@dimen/grid_2" tools:text="word1 word2 word3 word4 word5 word6 word7 word8 word9 word10" /> <TextView android:id="@+id/tvDescription" style="@style/Body1.Regular.TxtIconNeutrals2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/grid_2_5" android:gravity="center" android:maxLines="2" android:ellipsize="end" android:paddingHorizontal="@dimen/grid_3_5" tools:text="word1 word2 word3 word4 word5 word6 word7 word8 word9 word10" tools:visibility="visible" /> </LinearLayout>
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" motion:defaultDuration="10000"> <Transition android:id="@+id/transitionOpenGiftToCongrats" motion:constraintSetEnd="@+id/endGiftScaleToCenter" motion:constraintSetStart="@id/startGiftScaleToCenter"> <KeyFrameSet> ... <!--CongratsOpenGiftView--> <KeyAttribute android:alpha="0" motion:framePosition="0" motion:motionTarget="@+id/congratsOpenGiftView" /> <KeyAttribute android:alpha="0" motion:framePosition="49" motion:motionTarget="@+id/congratsOpenGiftView" /> <KeyAttribute android:alpha="1" motion:framePosition="50" motion:motionTarget="@+id/congratsOpenGiftView" /> <KeyAttribute android:alpha="1" motion:framePosition="100" motion:motionTarget="@+id/congratsOpenGiftView" /> ... </KeyFrameSet> </Transition> <ConstraintSet android:id="@+id/startGiftScaleToCenter"> ... <Constraint android:id="@+id/congratsOpenGiftView" android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="0" android:rotationY="180" android:layout_marginStart="@dimen/grid_2" android:layout_marginEnd="@dimen/grid_2" motion:layout_constraintVertical_bias="0.5" /> </ConstraintSet> <ConstraintSet android:id="@+id/endGiftScaleToCenter"> ... <Constraint android:id="@+id/congratsOpenGiftView" android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="1" android:rotationY="360" android:layout_marginStart="@dimen/grid_2" android:layout_marginEnd="@dimen/grid_2" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" motion:layout_constraintVertical_bias="0.5" /> </MotionScene>
Fragment布局代码
<?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" android:id="@+id/rootML" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" android:background="@drawable/bg_choice_rewarding_liner_gradient" app:layoutDescription="@xml/open_gift_to_congrats_scene"> ... <ru.broker.feature.loyalty.impl.view.new_views.CongratsOpenGiftView android:id="@+id/congratsOpenGiftView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="@dimen/grid_2" android:layout_marginEnd="@dimen/grid_2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.5"/> </androidx.constraintlayout.motion.widget.MotionLayout>
解决方案
问题根源是动画过程中MotionLayout可能临时调整视图的测量约束,导致TextView可用宽度变大,原本需要换行的文字能一行放下,从而出现换行异常。以下是无需固定宽高的优化方案:
方案一:强制CustomView保持父容器宽度约束
在CustomView的代码中重写onMeasure方法,确保测量阶段始终使用父容器给出的精确宽度,避免动画时测量逻辑变化:
class CongratsOpenGiftView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { // 强制使用父容器提供的精确宽度,防止动画过程中宽度测量波动 val fixedWidthSpec = MeasureSpec.makeMeasureSpec( MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY ) super.onMeasure(fixedWidthSpec, heightMeasureSpec) } }
方案二:在MotionScene中明确宽度稳定性约束
在start和end的ConstraintSet中,给congratsOpenGiftView添加宽度约束的默认值和最大值,确保动画全程宽度约束一致:
<!-- 在startGiftScaleToCenter和endGiftScaleToCenter的Constraint中添加 --> motion:layout_constraintWidth_default="match_parent" motion:layout_constraintWidth_max="match_parent"
修改后的示例Constraint:
<Constraint android:id="@+id/congratsOpenGiftView" android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="0" android:rotationY="180" android:layout_marginStart="@dimen/grid_2" android:layout_marginEnd="@dimen/grid_2" motion:layout_constraintWidth_default="match_parent" motion:layout_constraintWidth_max="match_parent" motion:layout_constraintVertical_bias="0.5" />
方案三:优化TextView的换行稳定性
给两个TextView添加换行策略属性,让文本换行逻辑更稳定,减少因微小宽度变化导致的换行异常:
<TextView android:id="@+id/tvTitle" ... android:breakStrategy="balanced" android:hyphenationFrequency="normal" /> <TextView android:id="@+id/tvDescription" ... android:breakStrategy="balanced" android:hyphenationFrequency="normal" />
内容的提问来源于stack exchange,提问作者Igor Novikov
相关产品推荐
相关产品推荐

