【发布时间】:2021-02-01 02:20:29
【问题描述】:
因此,我阅读了 Chris Banes here 的这篇很棒的 Medium 帖子,其中解释了如何使用协程或特别挂起函数来协调动画,而不会在将动画链接在一起时陷入“回调地狱”。我设法让onAnimationEnd 侦听器扩展按照他的示例工作,但我似乎无法为onAnimationStart 侦听器做同样的事情,这是我的awaitEnd 方法
suspend fun Animator.awaitEnd() = suspendCancellableCoroutine<Unit> { continuation ->
continuation.invokeOnCancellation { cancel() }
this.addListener(object : AnimatorListenerAdapter() {
private var endedSuccessfully = true
override fun onAnimationCancel(animation: Animator) {
endedSuccessfully = false
}
override fun onAnimationEnd(animation: Animator) {
animation.removeListener(this)
if (continuation.isActive) {
// If the coroutine is still active...
if (endedSuccessfully) {
// ...and the Animator ended successfully, resume the coroutine
continuation.resume(Unit)
} else {
// ...and the Animator was cancelled, cancel the coroutine too
continuation.cancel()
}
}
}
})
}
在下面的代码中,我在异步块中使用它,首先等待动画完成,然后等待协程完成
val anim = async {
binding.splash.circleReveal(null, startAtX = x, startAtY = y).run {
start()
//...doStuff()
awaitEnd()
}
}
anim.await()
这很好用,将日志添加到正确的函数向我表明,一切都被完全按预期调用,现在以相同的方式添加一个启动的扩展......
suspend fun Animator.started() = suspendCancellableCoroutine<Unit> { continuation ->
continuation.invokeOnCancellation { cancel() }
this.addListener(object : AnimatorListenerAdapter() {
private var endedSuccessfully = true
override fun onAnimationCancel(animation: Animator?) {
endedSuccessfully = false
}
override fun onAnimationStart(animation: Animator?) {
Log.d("DETAIL", "Animator.started() onAnimationStart")
animation?.removeListener(this)
if (continuation.isActive) {
// If the coroutine is still active...
if (endedSuccessfully) {
// ...and the Animator ended successfully, resume the coroutine
continuation.resume(Unit)
} else {
// ...and the Animator was cancelled, cancel the coroutine too
continuation.cancel()
}
}
}
})
}
并在启动方法之后从同一个异步块中调用它(这可能与事情有关)
val anim = async {
binding.splash.circleReveal(null, startAtX = x, startAtY = y).run {
start()
started()
//...doStuff()
awaitEnd()
}
}
anim.await()
现在发生的情况是,启动的协程被暂停但从未恢复,如果我添加一些日志记录语句,我可以看到它调用start(),然后它调用started(),但随后不再继续,显然我'已经尝试更改操作顺序无济于事,谁能看到我在这里做错了什么?
非常感谢
编辑
我也试过这个来添加一个 sharedElementEnter 过渡,但它再次对我不起作用,
suspend fun TransitionSet.awaitTransitionEnd() = suspendCancellableCoroutine<Unit> { continuation ->
val listener = object : TransitionListenerAdapter() {
private var endedSuccessfully = true
override fun onTransitionCancel(transition: Transition) {
super.onTransitionCancel(transition)
endedSuccessfully = false
}
override fun onTransitionEnd(transition: Transition) {
super.onTransitionEnd(transition)
Log.d("DETAIL","enterTransition onTransitionEnd")
transition.removeListener(this)
if (continuation.isActive) {
// If the coroutine is still active...
if (endedSuccessfully) {
// ...and the Animator ended successfully, resume the coroutine
continuation.resume(Unit)
} else {
// ...and the Animator was cancelled, cancel the coroutine too
continuation.cancel()
}
}
}
}
continuation.invokeOnCancellation { removeListener(listener) }
this.addListener(listener)
}
再次尝试使用 await 方法
viewLifecycleOwner.lifecycleScope.launch {
val sharedElementEnterTransitionAsync = async {
sharedElementEnterTransition = TransitionInflater.from(context)
.inflateTransition(R.transition.shared_element_transition)
(sharedElementEnterTransition as TransitionSet).awaitTransitionEnd()
}
sharedElementEnterTransitionAsync.await()
}
【问题讨论】:
标签: android kotlin android-animation extension-methods kotlin-coroutines