You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android共享元素过渡:阻止共享元素绘制及自定义可见区域动画问题

解决共享元素过渡期间阻止原视图绘制的问题

这个场景我之前也碰到过!在ScrollView嵌套ConstraintLayout的情况下控制共享元素的绘制,核心是要在过渡期间暂时隐藏原视图,同时保证动画结束后恢复正常状态。给你几个靠谱的实现思路:

方案一:利用Alpha属性临时隐藏原视图

在自定义Transition的onCreateAnimator方法中,我们可以在动画启动时将共享元素的alpha设为0(硬件加速下alpha为0的视图会被跳过绘制),动画结束后再恢复为1。这种方式不会改变视图的布局状态,非常安全:

override fun onCreateAnimator(
    sceneRoot: ViewGroup,
    startValues: TransitionValues?,
    endValues: TransitionValues?
): Animator? {
    val sharedView = endValues?.view ?: return super.onCreateAnimator(sceneRoot, startValues, endValues)
    
    // 动画开始时隐藏原视图
    sharedView.alpha = 0f
    
    // 这里替换成你已经写好的自定义动画逻辑
    val customAnimator = ObjectAnimator.ofFloat(sharedView, "translationY", 0f, 200f)
    customAnimator.duration = 500
    
    // 动画结束后恢复视图可见性
    customAnimator.addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator?) {
            super.onAnimationEnd(animation)
            sharedView.alpha = 1f
        }
    })
    
    return customAnimator
}

方案二:通过Visibility属性控制绘制

如果alpha的方式不符合你的需求,可以尝试直接修改视图的visibility为INVISIBLE(注意不要用GONE,否则会改变布局结构,影响过渡效果),动画结束后恢复原状态:

override fun onCaptureStartValues(values: TransitionValues) {
    super.onCaptureStartValues(values)
    // 保存视图原来的可见性状态
    values.values["original_visibility"] = values.view.visibility
}

override fun onCreateAnimator(
    sceneRoot: ViewGroup,
    startValues: TransitionValues?,
    endValues: TransitionValues?
): Animator? {
    val sharedView = endValues?.view ?: return null
    val originalVisibility = startValues?.values?.get("original_visibility") as Int
    
    // 过渡开始时隐藏原视图
    sharedView.visibility = View.INVISIBLE
    
    val customAnimator = // 你的自定义动画逻辑
    
    customAnimator.addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator?) {
            super.onAnimationEnd(animation)
            // 恢复原来的可见性
            sharedView.visibility = originalVisibility
        }
    })
    
    return customAnimator
}

方案三:通过SharedElementCallback全局控制

如果你需要对所有共享元素过渡统一处理,可以自定义SharedElementCallback,在过渡的开始和结束回调中控制视图状态:

// 在Activity的onCreate方法中设置
window.sharedElementEnterTransition = YourCustomTransition()
window.sharedElementExitTransition = YourCustomTransition()

window.sharedElementCallback = object : SharedElementCallback() {
    override fun onSharedElementStart(
        sharedElementNames: MutableList<String>?,
        sharedElements: MutableList<View>?,
        sharedElementSnapshots: MutableList<View>?
    ) {
        super.onSharedElementStart(sharedElementNames, sharedElements, sharedElementSnapshots)
        // 过渡开始时隐藏所有共享元素原视图
        sharedElements?.forEach { it.alpha = 0f }
    }

    override fun onSharedElementEnd(
        sharedElementNames: MutableList<String>?,
        sharedElements: MutableList<View>?,
        sharedElementSnapshots: MutableList<View>?
    ) {
        super.onSharedElementEnd(sharedElementNames, sharedElements, sharedElementSnapshots)
        // 过渡结束后恢复
        sharedElements?.forEach { it.alpha = 1f }
    }
}

注意事项

  • 不管用哪种方式,一定要确保在动画结束后恢复视图的原始状态,否则会影响页面的正常显示。
  • 如果你的自定义动画已经通过Canvas.clipRect等方式处理了可见区域的裁剪,那么隐藏原视图后,过渡过程中就只会显示你动画处理的可见部分了。

内容的提问来源于stack exchange,提问作者Oscar Méndez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:37:51