背景
多个月前需求间隙时,正好注意到我们的图片查看大图功能动画还不够完善,进入和退出的转场动画虽然都有,但是如果查看大图页的图片因左右滑动发生变化了,那么返回时的动画就对不上了,因而需要添加联动的逻辑,这里就简单整理下转场动画所有所需的步骤。
简单使用
启动和目标页都要声明
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
暂无评论内容