使用Window TransitionManager实现getWindow().setLayout()动画:MATCH_PARENT无动画问题
解决浮动Activity切换全屏无动画的问题
我来帮你梳理下这个问题的核心逻辑和可行的解决方向——其实当你用WRAP_CONTENT或固定数值调用setLayout时,系统能明确感知到窗口尺寸的具体变化差值,所以会触发默认的缩放过渡动画;但MATCH_PARENT是依赖父容器的相对值,系统没法直接获取明确的尺寸变化数据,因此默认不会触发动画。下面给你几个实用的解决思路:
1. 最直接的替代方案:用实际全屏尺寸代替MATCH_PARENT
不用修改TransitionManager,先获取屏幕(或目标父容器)的真实像素尺寸,再用这个固定值调用setLayout,让系统误以为是固定尺寸变化,从而复用默认动画:
// 获取屏幕全屏的实际像素尺寸 DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); int fullScreenWidth = displayMetrics.widthPixels; int fullScreenHeight = displayMetrics.heightPixels; // 切换全屏时使用实际尺寸,而非MATCH_PARENT getWindow().setLayout(fullScreenWidth, fullScreenHeight);
这个方案的优点是简单高效,几乎不需要额外代码;唯一需要注意的是,如果屏幕旋转或父容器尺寸变化,需要重新获取最新尺寸,但大部分浮动窗口场景下完全够用。
2. 自定义TransitionManager适配MATCH_PARENT
如果一定要坚持使用MATCH_PARENT,可以自定义Transition来处理相对尺寸的变化逻辑,核心是手动计算尺寸差值并创建动画:
步骤1:自定义Transition类
public class FullscreenTransition extends Transition { private static final String KEY_WINDOW_RECT = "windowRect"; @Override public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) { if (startValues == null || endValues == null) return null; // 获取起始和目标窗口尺寸 Rect startRect = (Rect) startValues.values.get(KEY_WINDOW_RECT); Rect endRect = (Rect) endValues.values.get(KEY_WINDOW_RECT); // 创建缩放动画(可根据需求添加位移、透明度等效果) View decorView = sceneRoot; ObjectAnimator widthAnim = ObjectAnimator.ofInt(decorView, "width", startRect.width(), endRect.width()); ObjectAnimator heightAnim = ObjectAnimator.ofInt(decorView, "height", startRect.height(), endRect.height()); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(widthAnim, heightAnim); animatorSet.setDuration(300); // 自定义动画时长 return animatorSet; } @Override public void captureStartValues(TransitionValues transitionValues) { super.captureStartValues(transitionValues); // 捕获窗口当前的起始尺寸 View view = transitionValues.view; transitionValues.values.put(KEY_WINDOW_RECT, new Rect(0, 0, view.getWidth(), view.getHeight())); } @Override public void captureEndValues(TransitionValues transitionValues) { super.captureEndValues(transitionValues); // 捕获全屏状态的目标尺寸 WindowManager windowManager = (WindowManager) transitionValues.view.getContext().getSystemService(Context.WINDOW_SERVICE); DisplayMetrics metrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(metrics); transitionValues.values.put(KEY_WINDOW_RECT, new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)); } }
步骤2:绑定TransitionManager到窗口
// 初始化自定义TransitionManager TransitionManager transitionManager = new TransitionManager(); Scene fullscreenScene = new Scene(getWindow().getDecorView()); transitionManager.setTransitionToScene(fullscreenScene, new FullscreenTransition()); getWindow().setTransitionManager(transitionManager); // 切换全屏时触发动画 TransitionManager.beginDelayedTransition(getWindow().getDecorView()); getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
注意:这里的动画目标是Window的DecorView,也可以直接操作Window的LayoutParams来更精准地控制尺寸变化。
3. 用窗口动画风格替代TransitionManager
你也可以通过自定义主题动画来实现过渡效果,绕开TransitionManager的限制:
步骤1:定义动画资源
在res/anim/scale_in.xml中写全屏缩放进入动画:
<scale xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromXScale="0.8" android:fromYScale="0.8" android:pivotX="50%" android:pivotY="50%" android:toXScale="1.0" android:toYScale="1.0"/>
步骤2:在主题中配置窗口动画
<style name="FloatingWindowAnimStyle" parent="@android:style/Animation"> <item name="android:windowEnterAnimation">@anim/scale_in</item> </style>
步骤3:切换状态时触发动画
// 设置窗口动画 getWindow().setWindowAnimations(R.style.FloatingWindowAnimStyle); // 切换全屏 getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
这种方式更适合简单的过渡场景,缺点是动画逻辑和布局切换的耦合度较高。
内容的提问来源于stack exchange,提问作者Michał Klimczak
相关产品推荐
相关产品推荐

