ios SwiftUI在2个分离视图之间动画过渡

yrdbyhpb  于 2023-05-19  发布在  iOS
关注(0)|答案(1)|浏览(196)

我不知道为什么我的动画过渡在我的情况下不起作用。我有一个登录视图和一个主视图,当我按下一个按钮时,我想平滑地过渡到另一个视图。下面是我使用的代码。
我在这里错过了什么?**
非常感谢!

import SwiftUI

class AppState: ObservableObject {
    @Published var loginScreen: Bool
    
    init(loginScreen: Bool) {
        self.loginScreen = loginScreen
    }
}

@main
struct Test: App {
    @StateObject var appState: AppState = AppState(loginScreen: true)
    var body: some Scene {
        WindowGroup {
            if appState.loginScreen {
                LoginView()
                    .environmentObject(appState)
            } else {
                MainView()
                    .environmentObject(appState)
            }
        }
    }
}

登录视图:

import SwiftUI

struct LoginView: View {
    @EnvironmentObject var appState: AppState
    var body: some View {
        VStack {
            HStack {
                LogInButton().environmentObject(appState)
            }.padding()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let appState = AppState(loginScreen: true)
        LoginView().environmentObject(appState)
    }
}

下面是我的按钮登录视图

import SwiftUI

struct LogInButton: View {
    @EnvironmentObject var appState: AppState
    var body: some View {
        Button(action: {
            appState.loginScreen.toggle()
        }) {
            HStack {
                Text("Log In")  
            }
        }
    }
}

struct LogInButton_Previews: PreviewProvider {
    static var previews: some View {
        let appState = AppState(loginScreen: true)
        LogInButton().environmentObject(appState)
    }
}

以及主视图

import SwiftUI

struct MainView: View {
    @EnvironmentObject var appState: AppState
    var body: some View {
        VStack {
            Spacer()
            Button("Go to login") {
                appState.loginScreen.toggle()
            }
            .font(.title)
        }
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}
20jt8wwn

20jt8wwn1#

主要是,没有动画,因为你没有指定。当你点击一个按钮来切换应用状态的布尔值时,这会触发SwiftUI重建它的视图布局,并且它会尽可能快地完成。
一种控制更改动画方式的方法是向LoginViewMainView的条件调用添加过渡修饰符。为了使这更容易,我将该条件移动到Scene声明之外:

@main
struct LoginAnimationApp: App {
    // this doesn’t need to be a `StateObject` as this struct doesn’t
    // change whenever `appState` changes
    var appState: AppState = AppState(loginScreen: true)

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appState)
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var appState: AppState

    var body: some View {
        ZStack {
            if appState.loginScreen {
                LoginView()
                    .transition(.opacity)
            } else {
                MainView()
                    .transition(.slide)
            }
        }
        // this modifier determines the timing curve of the transitions
        .animation(.default, value: appState.loginScreen)
    }
}

(快速说明:如果你在层次结构的顶部声明了一个.environmentObject,你通常不需要在视图树的更下面重新声明它; SwiftUI会自动为你传递环境变量。您只在需要响应对象更改而更改的视图中选择@EnvironmentObject)。
另一种选择是将登录屏幕设置为fullScreenCover,它将自动动画以覆盖任何其他视图,并且通过绑定到布尔值来管理:

struct ContentView: View {
    @EnvironmentObject var appState: AppState

    var body: some View {
        MainView()
        .fullScreenCover(isPresented: $appState.loginScreen) {
            LoginView()
        }
    }
}

您可以通过将appState.loginScreen的值更改为false来关闭login视图(就像您的代码当前所做的那样)。
这是更干净的,你依靠的SwiftUI基础是相当健壮的。但是,您在如何呈现动画方面没有任何真实的的灵活性:登录屏幕将总是从底部边缘动画显示。但这是iOS用户熟悉的风格,所以可能没问题。

相关问题