SwiftUI:自定义模态动画
Posted
技术标签:
【中文标题】SwiftUI:自定义模态动画【英文标题】:SwiftUI: Custom Modal Animation 【发布时间】:2019-09-12 08:24:23 【问题描述】:我使用 SwiftUI 制作了一个自定义模式。它工作正常,但动画很不稳定。
慢动作播放时,可以看到ModalContent
的背景在触发ModalOverlay
的点击动作后立即消失。但是,ModalContent
的 Text
视图始终可见。
谁能告诉我如何防止ModalContent
的背景过早消失?
下面的慢动作视频和代码:
import SwiftUI
struct ContentView: View
@State private var isShowingModal = false
var body: some View
GeometryReader geometry in
ZStack
Button(
action: withAnimation self.isShowingModal = true ,
label: Text("Show Modal")
)
ZStack
if self.isShowingModal
ModalOverlay(tapAction: withAnimation self.isShowingModal = false )
ModalContent().transition(.move(edge: .bottom))
.edgesIgnoringSafeArea(.all)
struct ModalOverlay: View
var color = Color.black.opacity(0.4)
var tapAction: (() -> Void)? = nil
var body: some View
color.onTapGesture self.tapAction?()
struct ModalContent: View
var body: some View
GeometryReader geometry in
VStack
Spacer()
VStack(spacing: 16)
Text("Item 1")
Text("Item 2")
Text("Item 3")
.frame(width: geometry.size.width)
.padding(.top, 16)
.padding(.bottom, geometry.safeAreaInsets.bottom)
.background(Color.white)
【问题讨论】:
【参考方案1】:解决方案(感谢@JWK):
这可能是一个错误。似乎在过渡动画期间(当视图消失时)所涉及的两个视图(ModalContent
和ModalOverlay
)中的zIndex
不受尊重。 ModalContent
(应该在ModalOverlay
前面)实际上在动画开始时移动到ModalOverlay
下面。为了解决这个问题,我们可以手动将zIndex
设置为,例如,ModalContent
视图上的 1。
struct ContentView: View
@State private var isShowingModal = false
var body: some View
GeometryReader geometry in
ZStack
Button(
action: withAnimation self.isShowingModal = true ,
label: Text("Show Modal")
)
ZStack
if self.isShowingModal
ModalOverlay(tapAction: withAnimation(.easeOut(duration: 5)) self.isShowingModal = false )
ModalContent()
.transition(.move(edge: .bottom))
.zIndex(1)
.edgesIgnoringSafeArea(.all)
找到解决方案的调查
SwiftUI 中的过渡动画仍然存在一些问题。我认为这是一个错误。我很确定,因为:
1) 您是否尝试将ModalContent
的背景颜色从白色更改为绿色?
struct ModalContent: View
var body: some View
GeometryReader geometry in
VStack
Spacer()
VStack(spacing: 16)
Text("Item 1")
Text("Item 2")
Text("Item 3")
.frame(width: geometry.size.width)
.padding(.top, 16)
.padding(.bottom, geometry.safeAreaInsets.bottom)
.background(Color.green)
这样工作(见下面的 GIF):
2) 另一种使错误发生的方法是将ContentView
的背景颜色更改为例如绿色,而将ModalContent
保留为白色:
struct ContentView: View
@State private var isShowingModal = false
var body: some View
GeometryReader geometry in
ZStack
Button(
action: withAnimation(.easeOut(duration: 5)) self.isShowingModal = true ,
label: Text("Show Modal")
)
ZStack
if self.isShowingModal
ModalOverlay(tapAction: withAnimation(.easeOut(duration: 5)) self.isShowingModal = false )
ModalContent().transition(.move(edge: .bottom))
.background(Color.green)
.edgesIgnoringSafeArea(.all)
struct ModalOverlay: View
var color = Color.black.opacity(0.4)
var tapAction: (() -> Void)? = nil
var body: some View
color.onTapGesture self.tapAction?()
struct ModalContent: View
var body: some View
GeometryReader geometry in
VStack
Spacer()
VStack(spacing: 16)
Text("Item 1")
Text("Item 2")
Text("Item 3")
.frame(width: geometry.size.width)
.padding(.top, 16)
.padding(.bottom, geometry.safeAreaInsets.bottom)
.background(Color.white)
即使在这种情况下,它也能按预期工作:
3) 但是如果您将ModalContent
背景颜色更改为绿色(因此您同时拥有ContentView
和ModalContent
绿色),问题再次出现(我不会发布另一个 GIF,但您可以自己轻松尝试)。
4) 另一个例子:如果你将 iPhone 的外观更改为深色外观(ios 13 的新功能),你的ContentView
将自动变为黑色,并且由于你的ModalView
是白色的,问题不会发生,一切正常。
【讨论】:
欣赏调查工作!我认为你是对的,这是一个错误。这种行为似乎完全出乎意料。也不清楚为什么ModalContent
的背景在某些只指定.move(edge: .bottom)
的情况下对过渡有不透明性。我会向反馈助理提交报告。
原来这里实际上有一个解决方法!它也解释了我之前评论中感知到的不透明度变化。只需在ModalContent
上设置zIndex
:ModalContent().transition(.move(edge: .bottom)).zIndex(1)
。无论出于何种原因,当状态发生变化时,ModalContent
将落后于ModalOverlay
。我仍然同意这是一个错误,但这似乎可以解决问题。
哦,现在我们明白了为什么只有当 ContentView 和子视图具有相同的 bg 颜色时才会出现问题。无论如何,是的,这是一个错误。现在,我将修改我的答案以解释您的发现。如果您愿意,您甚至可以回答自己的问题,然后接受您的回答。以上是关于SwiftUI:自定义模态动画的主要内容,如果未能解决你的问题,请参考以下文章