如何从资源文件使用自定义Transition?自定义Rotate转场定义咨询
嘿,我来帮你搞定这个自定义Rotate Transition的问题,让它能正常在XML转场资源里使用~
要让自定义Transition支持XML资源文件解析,核心是要满足系统的实例化规则,同时补全转场逻辑的必要方法。下面是完整的实现步骤和代码:
第一步:完善自定义Rotate Transition类
必须实现带Context和AttributeSet参数的构造方法(这是XML解析时系统实例化类的关键入口),同时补全转场所需的属性捕获、动画创建逻辑:
public class Rotate extends Transition { // 定义转场属性的唯一标识,用于保存状态 private static final String PROPNAME_ROTATION = "com.your.package:rotate:rotation"; private static final String[] TRANSITION_PROPERTIES = {PROPNAME_ROTATION}; // 可配置的旋转参数 private float mStartAngle = 0f; private float mEndAngle = 360f; private float mPivotX = 0.5f; // 默认以视图中心为旋转轴X private float mPivotY = 0.5f; // 默认以视图中心为旋转轴Y // 代码中直接实例化时用的空构造 public Rotate() {} // 关键:XML解析时的构造方法,必须实现 public Rotate(Context context, AttributeSet attrs) { super(context, attrs); // 解析XML中的属性(包括系统自带和自定义属性) TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RotateTransition); // 复用系统的duration和interpolator属性 setDuration(a.getInt(R.styleable.RotateTransition_android_duration, (int) getDuration())); int interpolatorId = a.getResourceId(R.styleable.RotateTransition_android_interpolator, 0); if (interpolatorId != 0) { setInterpolator(AnimationUtils.loadInterpolator(context, interpolatorId)); } // 解析自定义的旋转参数 mStartAngle = a.getFloat(R.styleable.RotateTransition_startAngle, mStartAngle); mEndAngle = a.getFloat(R.styleable.RotateTransition_endAngle, mEndAngle); mPivotX = a.getFloat(R.styleable.RotateTransition_pivotX, mPivotX); mPivotY = a.getFloat(R.styleable.RotateTransition_pivotY, mPivotY); a.recycle(); } @Override public String[] getTransitionProperties() { return TRANSITION_PROPERTIES; } // 捕获转场开始时的视图状态 @Override public void captureStartValues(TransitionValues transitionValues) { transitionValues.values.put(PROPNAME_ROTATION, transitionValues.view.getRotation()); } // 捕获转场结束时的视图状态 @Override public void captureEndValues(TransitionValues transitionValues) { transitionValues.values.put(PROPNAME_ROTATION, mEndAngle); } // 创建实际的旋转动画 @Override public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) { if (startValues == null || endValues == null) return null; View targetView = endValues.view; float startRotation = (float) startValues.values.get(PROPNAME_ROTATION); float endRotation = (float) endValues.values.get(PROPNAME_ROTATION); if (startRotation == endRotation) return null; // 设置旋转轴心(基于视图自身尺寸的比例) targetView.setPivotX(targetView.getWidth() * mPivotX); targetView.setPivotY(targetView.getHeight() * mPivotY); // 创建属性动画 ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(targetView, View.ROTATION, startRotation, endRotation); rotateAnim.setDuration(getDuration()); rotateAnim.setInterpolator(getInterpolator()); return rotateAnim; } }
第二步:定义自定义属性(可选但推荐)
在res/values/attrs.xml中声明自定义属性,这样可以在XML里配置旋转角度、轴心等参数:
<resources> <declare-styleable name="RotateTransition"> <!-- 复用系统自带的duration和interpolator属性 --> <attr name="android:duration"/> <attr name="android:interpolator"/> <!-- 自定义旋转参数 --> <attr name="startAngle" format="float"/> <attr name="endAngle" format="float"/> <attr name="pivotX" format="float"/> <attr name="pivotY" format="float"/> </declare-styleable> </resources>
第三步:修改XML转场资源文件
有两种方式让系统识别你的自定义Transition:
方式1:直接使用全类名(简单直接)
修改res/transition/rotate_transition.xml,用自定义类的完整包路径作为标签名:
<?xml version="1.0" encoding="utf-8"?> <com.your.package.Rotate xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:duration="275" android:interpolator="@android:interpolator/accelerate_decelerate" app:startAngle="0" app:endAngle="360"/>
方式2:注册别名,继续用<rotate>标签
如果你想保留原来的<rotate>标签,可以在Application的onCreate方法中注册Transition工厂:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); TransitionInflater inflater = TransitionInflater.from(this); inflater.setFactory((className, context, attrs) -> { // 当系统解析<rotate>标签时,实例化我们的自定义类 if ("rotate".equals(className)) { return new Rotate(context, attrs); } // 其他转场交给系统处理 return TransitionInflater.from(context).createTransition(className, context, attrs); }); } }
这样你就可以继续使用原来的XML写法:
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="275" android:interpolator="@android:interpolator/accelerate_decelerate"/>
第四步:使用自定义转场
在Activity或Fragment中加载并使用这个转场:
// Activity转场示例 Transition rotateTransition = TransitionInflater.from(this).inflateTransition(R.transition.rotate_transition); getWindow().setExitTransition(rotateTransition); // Fragment转场示例 MyFragment fragment = new MyFragment(); fragment.setEnterTransition(rotateTransition); getSupportFragmentManager().beginTransaction() .replace(R.id.container, fragment) .commit();
内容的提问来源于stack exchange,提问作者Vladimir Petrovski
相关产品推荐
相关产品推荐

