Android MotionLayout自定义属性methodName的用法及示例需求
Android MotionLayout 相关问题解答
一、自定义属性methodName的用法及示例
methodName是MotionLayout的扩展能力,用于通过反射调用目标View的公开方法,实现系统默认属性不支持的动画效果。它需要配合<CustomAttribute>标签使用,核心是指定要调用的方法名,并传递方法所需参数。
核心用法
- 在MotionScene的
<ConstraintSet>中,通过<CustomAttribute>设置attributeName="methodName",并用stringValue指定目标View的公开方法名。 - 额外添加
<CustomAttribute>标签传递方法参数,参数的attributeName需与方法参数逻辑对应,值类型要匹配方法参数类型(如intValue对应int参数,stringValue对应String参数)。 - 注意:目标方法必须是public修饰,参数类型需和传递的参数完全匹配。
示例:调用TextView的setHintTextColor实现颜色动画
假设要实现TextView提示文字从灰色到蓝色的过渡动画,MotionScene代码如下:
<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" motion:duration="1000"> <OnSwipe motion:touchAnchorId="@id/hintTextView" motion:touchAnchorSide="top" motion:dragDirection="dragUp" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@id/hintTextView"> <CustomAttribute motion:attributeName="methodName" motion:stringValue="setHintTextColor" /> <CustomAttribute motion:attributeName="hintTextColor" motion:intValue="@color/grey_500" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/hintTextView"> <CustomAttribute motion:attributeName="methodName" motion:stringValue="setHintTextColor" /> <CustomAttribute motion:attributeName="hintTextColor" motion:intValue="@color/blue_500" /> </Constraint> </ConstraintSet> </MotionScene>
动画过程中,MotionLayout会通过反射调用TextView.setHintTextColor(int),自动插值实现颜色平滑过渡。
二、解决MotionLayout不支持fontFamily/gravity属性的方案
MotionLayout默认不支持这两个属性的直接动画,可通过以下两种方案实现:
方案1:用methodName调用View的公开方法
处理fontFamily
封装自定义TextView,添加易调用的字体设置方法:
public class ExtendedTextView extends androidx.appcompat.widget.AppCompatTextView { public ExtendedTextView(Context context) { super(context); } public ExtendedTextView(Context context, AttributeSet attrs) { super(context, attrs); } public void setFontFamilyByName(String fontFamilyName) { Typeface typeface = Typeface.create(fontFamilyName, Typeface.NORMAL); setTypeface(typeface); } }
在MotionScene中调用该方法:
<ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/extendedTextView"> <CustomAttribute motion:attributeName="methodName" motion:stringValue="setFontFamilyByName" /> <CustomAttribute motion:attributeName="fontFamilyByName" motion:stringValue="sans-serif-medium" /> </Constraint> </ConstraintSet>
处理gravity
直接调用TextView的setGravity(int)方法,传递对应常量值:
<ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/textView"> <CustomAttribute motion:attributeName="methodName" motion:stringValue="setGravity" /> <!-- 17对应Gravity.CENTER,也可使用@android:integer/gravity_center --> <CustomAttribute motion:attributeName="gravity" motion:intValue="17" /> </Constraint> </ConstraintSet>
方案2:通过TransitionListener手动控制动画
监听MotionLayout动画进度,根据进度手动更新属性:
MotionLayout motionLayout = findViewById(R.id.motion_layout); TextView targetTextView = findViewById(R.id.target_text); motionLayout.setTransitionListener(new MotionLayout.TransitionListener() { @Override public void onTransitionStarted(MotionLayout motionLayout, int startId, int endId) {} @Override public void onTransitionChange(MotionLayout motionLayout, int startId, int endId, float progress) { // 切换fontFamily if (progress > 0.5f) { targetTextView.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); } else { targetTextView.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL)); } // 切换gravity int gravity = progress > 0.5f ? Gravity.CENTER : Gravity.START; targetTextView.setGravity(gravity); } @Override public void onTransitionCompleted(MotionLayout motionLayout, int currentId) {} @Override public void onTransitionTrigger(MotionLayout motionLayout, int triggerId, boolean positive, float progress) {} });
这种方式适合无需平滑渐变,只需在动画过程中切换状态的场景,也可根据进度实现更精细的控制。
内容的提问来源于stack exchange,提问作者Sharas
相关产品推荐
相关产品推荐

