Activity 转场动画小试牛刀

背景

多个月前需求间隙时,正好注意到我们的图片查看大图功能动画还不够完善,进入和退出的转场动画虽然都有,但是如果查看大图页的图片因左右滑动发生变化了,那么返回时的动画就对不上了,因而需要添加联动的逻辑,这里就简单整理下转场动画所有所需的步骤。

Untitled.gif

简单使用

启动和目标页都要声明

with(window) {
    requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)
}

或 theme 中声明:

<item name="android:windowContentTransitions">true</item>

simple code

// both activity should set transition name
viewBind.searchBar.transitionName = "search_bar"
viewBind.titleBar.transitionName = "title_bar"

// 始发页 jump
val bundle = ActivityOptions
                    .makeSceneTransitionAnimation(
                        activity,
                        Pair(viewBind.searchBar, "search_bar"),
                        Pair(viewBind.titleBar, "title_bar")
                    ).toBundle()
activity.startActivityForResult(Intent(activity, TargetActivity::class.java), requestCode, bundle)

// 目标页 finish
finishAfterTransition()

// 可选,在目标页还可以指定动画
with(window) {
    val transition = TransitionSet().apply {
        addTransition(ChangeBounds())
        addTransition(ChangeImageTransform())
        duration = 200
    }
    sharedElementEnterTransition = transition
    sharedElementExitTransition = transition
}

进入和返回动画定位

如果被开启页返回时动画的view发生了变化怎么处理?比如打开一个相册查看大图页,然后在查看大图时左右滑动到其他图片,返回时动画对应的 view 发生了变化,我们分别来看。

查看大图页

// onCreate 中
setEnterSharedElementCallback(object : SharedElementCallback() {
        // 进入和退出时都会通过 onMapSharedElements 得到要做动画的 View
    override fun onMapSharedElements(
        names: MutableList<String>?,
        sharedElements: MutableMap<String, View>?
    ) {
      (viewBind.viewPager.currentFragment(supportFragmentManager) as? SingleImageFragment)
                ?.getImageView()
                ?.let {
                    sharedElements?.put(TRANSITION_IMAGE, it)
                }
    }
})

// 退出时把当前position返回上一页
override fun finishAfterTransition() {
    setResult(RESULT_OK, intent.putExtra(POSITION, viewBind.viewPager.currentItem))
    super.finishAfterTransition()
}

进入时,通过 setEnterSharedElementCallback 指定做动画的 view;

退出时,将最新的定位通过 setResult 返回给前序页面。
💡 注意:如果图片加载慢,进入大图页可能没有动画,可以使用postponeEnterTransition + startPostponedEnterTransition 自己控制动画执行时机

列表页

var previewPosition = 0

// jump
setExitSharedElementCallback(object : SharedElementCallback() {
        // 当makeSceneTransitionAnimation时或从被打开的页面返回时调用
    override fun onMapSharedElements(names: MutableList<String>?, sharedElements: MutableMap<String, View>?) {
        sharedElements?.put(ImagePreviewActivity.TRANSITION_IMAGE, getImageView(previewPosition))
    }
})
val bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle()
activity.startActivityForResult(Intent(activity, TargetActivity::class.java), requestCode, bundle)

// 获取查看大图页返回时最新position
override fun onActivityReenter(resultCode: Int, data: Intent?) {
    super.onActivityReenter(resultCode, data)
    previewPosition = data?.getIntExtra(POSITION, -1) ?: 0
    viewBind.pictureGallery.scrollToPosition(previewPosition)
    lifecycleScope.launch {
            // scroll需要时间,这里手动延迟动画执行
        postponeEnterTransition()
        // 10ms基本够用
        delay(10)
        // 开启延迟的动画
        startPostponedEnterTransition()
    }
}

从大图页返回时,onActivityReenter 首先被调用,获取 position。随后 onMapSharedElements 调用并指定正确的 View。

在这个例子中,我们使用了 postponeEnterTransition() 和 startPostponedEnterTransition() 来控制动画的执行时机。这样可以确保在滚动到正确位置后再开始动画,从而实现更流畅的用户体验。

小结

本文介绍了如何在 Android 应用中实现流畅的 Activity 转场动画。我们不仅探讨了基本设置和使用方法,还深入了处理动态变化场景的高级技巧。通过巧妙运用 SharedElementCallback、postponeEnterTransition 等 API,我们能在复杂的交互场景中营造一致且流畅的用户体验,显著提升应用的视觉魅力和交互品质。


作者:Aaron_Wang
链接:https://juejin.cn/post/7408384692606844955

© 版权声明
THE END
喜欢就支持以下吧
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容