SwiftUI - 动画过渡
SwiftUI - Animate transition
我在模式 sheet 上有一个注销按钮,可以让用户返回登录屏幕。为此,我首先关闭 sheet,然后使用 asyncAfter(deadline:) 设置一个环境变量,使登录页面出现。一切正常,但是一旦 sheet 被关闭,从 sheet 下的视图到登录页面的转换就非常不和谐。主要是因为没有。顶视图消失了,显示了登录视图。我知道我可以创建自定义转场,但我不知道将它附加到哪里。比如说,我想淡出 sheet 下面的视图。 (不过,我对任何类型的转变都持开放态度!)
这是引导流量的结构:
struct ConductorView: View {
@EnvironmentObject var tower: Tower
let onboardingCompleted = UserDefaults.standard.bool(forKey: "FirstVisit")
var body: some View {
VStack {
if tower.currentPage == .onboarding {
Onboarding1View()
} else if tower.currentPage == .login {
LoginView()
} else if tower.currentPage == .idle {
LoginView()
}
}.onAppear{
if self.onboardingCompleted {
self.tower.currentPage = .login
} else {
self.tower.currentPage = .onboarding
}
}
}
}
这是 sheet 上的退出按钮:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.tower.currentPage = .login
}
}) {
Text("Sign Out")
}
这是您复制的代码的简化演示(我做了一些更长的延迟以使其模式可见)。当然,您需要通过更改过渡类型或动画等来根据需要调整它。使用 Xcode 12 / iOS 14
进行测试
class Tower: ObservableObject {
enum PageType {
case onboarding, login, idle
}
@Published var currentPage: PageType = .onboarding
}
struct ConductorView: View {
@EnvironmentObject var tower: Tower
let onboardingCompleted = false
var body: some View {
VStack {
if tower.currentPage == .onboarding {
Onboarding1View()
} else if tower.currentPage == .login {
Text("LoginView")
.transition(.move(edge: .trailing)) // << here !!
} else if tower.currentPage == .idle {
Text("IdleView")
}
}
.animation(.default, value: tower.currentPage) // << here !!
.onAppear{
if self.onboardingCompleted {
self.tower.currentPage = .login
} else {
self.tower.currentPage = .onboarding
}
}
}
}
struct Onboarding1View: View {
@EnvironmentObject var tower: Tower
@Environment(\.presentationMode) var presentationMode
@State private var isPresented = true
var body: some View {
Text("Login")
.sheet(isPresented: $isPresented) {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.tower.currentPage = .login
}
}) {
Text("Sign Out")
}
}
}
}
我在模式 sheet 上有一个注销按钮,可以让用户返回登录屏幕。为此,我首先关闭 sheet,然后使用 asyncAfter(deadline:) 设置一个环境变量,使登录页面出现。一切正常,但是一旦 sheet 被关闭,从 sheet 下的视图到登录页面的转换就非常不和谐。主要是因为没有。顶视图消失了,显示了登录视图。我知道我可以创建自定义转场,但我不知道将它附加到哪里。比如说,我想淡出 sheet 下面的视图。 (不过,我对任何类型的转变都持开放态度!)
这是引导流量的结构:
struct ConductorView: View {
@EnvironmentObject var tower: Tower
let onboardingCompleted = UserDefaults.standard.bool(forKey: "FirstVisit")
var body: some View {
VStack {
if tower.currentPage == .onboarding {
Onboarding1View()
} else if tower.currentPage == .login {
LoginView()
} else if tower.currentPage == .idle {
LoginView()
}
}.onAppear{
if self.onboardingCompleted {
self.tower.currentPage = .login
} else {
self.tower.currentPage = .onboarding
}
}
}
}
这是 sheet 上的退出按钮:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.tower.currentPage = .login
}
}) {
Text("Sign Out")
}
这是您复制的代码的简化演示(我做了一些更长的延迟以使其模式可见)。当然,您需要通过更改过渡类型或动画等来根据需要调整它。使用 Xcode 12 / iOS 14
进行测试class Tower: ObservableObject {
enum PageType {
case onboarding, login, idle
}
@Published var currentPage: PageType = .onboarding
}
struct ConductorView: View {
@EnvironmentObject var tower: Tower
let onboardingCompleted = false
var body: some View {
VStack {
if tower.currentPage == .onboarding {
Onboarding1View()
} else if tower.currentPage == .login {
Text("LoginView")
.transition(.move(edge: .trailing)) // << here !!
} else if tower.currentPage == .idle {
Text("IdleView")
}
}
.animation(.default, value: tower.currentPage) // << here !!
.onAppear{
if self.onboardingCompleted {
self.tower.currentPage = .login
} else {
self.tower.currentPage = .onboarding
}
}
}
}
struct Onboarding1View: View {
@EnvironmentObject var tower: Tower
@Environment(\.presentationMode) var presentationMode
@State private var isPresented = true
var body: some View {
Text("Login")
.sheet(isPresented: $isPresented) {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.tower.currentPage = .login
}
}) {
Text("Sign Out")
}
}
}
}