按按钮显示新视图 Swift UI
Show a new View from Button press Swift UI
我希望能够在我的其中一个视图上按下按钮时显示新视图。
从我看过的教程和其他已回答的问题来看,似乎每个人都在导航视图中使用导航按钮,除非我误认为导航视图是给我菜单栏右箭头的那个应用程序,所以我不想要那个。当我将不是 NavigationView 子项的导航按钮放在我的视图中时,它只是在 UI 上被禁用并且我无法单击它,所以我想我不能使用它。
我看到的其他示例似乎使用了演示文稿链接/按钮,它们似乎显示了一种弹出式视图。
我只是在寻找如何单击一个常规按钮并显示另一个全屏视图,就像执行用于执行旧方法的 segue 一样。
对于简单的示例,您可以使用如下所示的东西
import SwiftUI
struct ExampleFlag : View {
@State var flag = true
var body: some View {
ZStack {
if flag {
ExampleView().tapAction {
self.flag.toggle()
}
} else {
OtherExampleView().tapAction {
self.flag.toggle()
}
}
}
}
}
struct ExampleView: View {
var body: some View {
Text("some text")
}
}
struct OtherExampleView: View {
var body: some View {
Text("other text")
}
}
但是如果你想展示更多视图,这种方式看起来很讨厌
您可以在没有 NavigationView 的情况下使用堆栈来控制视图状态
例如:
class NavigationStack: BindableObject {
let didChange = PassthroughSubject<Void, Never>()
var list: [AuthState] = []
public func push(state: AuthState) {
list.append(state)
didChange.send()
}
public func pop() {
list.removeLast()
didChange.send()
}
}
enum AuthState {
case mainScreenState
case userNameScreen
case logginScreen
case emailScreen
case passwordScreen
}
struct NavigationRoot : View {
@EnvironmentObject var state: NavigationStack
@State private var aligment = Alignment.leading
fileprivate func CurrentView() -> some View {
switch state.list.last {
case .mainScreenState:
return AnyView(GalleryState())
case .none:
return AnyView(LoginScreen().environmentObject(state))
default:
return AnyView(AuthenticationView().environmentObject(state))
}
}
var body: some View {
GeometryReader { geometry in
self.CurrentView()
.background(Image("background")
.animation(.fluidSpring())
.edgesIgnoringSafeArea(.all)
.frame(width: geometry.size.width, height: geometry.size.height,
alignment: self.aligment))
.edgesIgnoringSafeArea(.all)
.onAppear {
withAnimation() {
switch self.state.list.last {
case .none:
self.aligment = Alignment.leading
case .passwordScreen:
self.aligment = Alignment.trailing
default:
self.aligment = Alignment.center
}
}
}
}
.background(Color.black)
}
}
struct ExampleOfAddingNewView: View {
@EnvironmentObject var state: NavigationStack
var body: some View {
VStack {
Button(action:{ self.state.push(state: .emailScreen) }){
Text("Tap me")
}
}
}
}
struct ExampleOfRemovingView: View {
@EnvironmentObject var state: NavigationStack
var body: some View {
VStack {
Button(action:{ self.state.pop() }){
Text("Tap me")
}
}
}
}
在我看来这种方式很糟糕,但在 SwiftUI 中导航更糟糕
可能的解决方案
1.if 你想在当前视图的顶部呈现(例如:UIKit 中的呈现样式)
struct ContentView: View {
@State var showingDetail = false
var body: some View {
Button(action: {
self.showingDetail.toggle()
}) {
Text("Show Detail")
}.sheet(isPresented: $showingDetail) {
DetailView()
}
}
}
2.if 你想重置当前 window 场景堆栈(例如:登录后显示主屏幕)
Button(action: goHome) {
HStack(alignment: .center) {
Spacer()
Text("Login").foregroundColor(Color.white).bold()
Spacer()
}
}
func goHome() {
if let window = UIApplication.shared.windows.first {
window.rootViewController = UIHostingController(rootView: HomeScreen())
window.makeKeyAndVisible()
}
}
3.push 新视图(例如:list->detail,UIKit 的导航控制器)
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView()) {
Text("Show Detail View")
}.navigationBarTitle("Navigation")
}
}
}
}
4.update 当前视图基于@state 属性, (ex:show error message on login failure)
struct ContentView: View {
@State var error = true
var body: some View {
...
... //login email
.. //login password
if error {
Text("Failed to login")
}
}
}
我希望能够在我的其中一个视图上按下按钮时显示新视图。
从我看过的教程和其他已回答的问题来看,似乎每个人都在导航视图中使用导航按钮,除非我误认为导航视图是给我菜单栏右箭头的那个应用程序,所以我不想要那个。当我将不是 NavigationView 子项的导航按钮放在我的视图中时,它只是在 UI 上被禁用并且我无法单击它,所以我想我不能使用它。
我看到的其他示例似乎使用了演示文稿链接/按钮,它们似乎显示了一种弹出式视图。
我只是在寻找如何单击一个常规按钮并显示另一个全屏视图,就像执行用于执行旧方法的 segue 一样。
对于简单的示例,您可以使用如下所示的东西
import SwiftUI
struct ExampleFlag : View {
@State var flag = true
var body: some View {
ZStack {
if flag {
ExampleView().tapAction {
self.flag.toggle()
}
} else {
OtherExampleView().tapAction {
self.flag.toggle()
}
}
}
}
}
struct ExampleView: View {
var body: some View {
Text("some text")
}
}
struct OtherExampleView: View {
var body: some View {
Text("other text")
}
}
但是如果你想展示更多视图,这种方式看起来很讨厌
您可以在没有 NavigationView 的情况下使用堆栈来控制视图状态
例如:
class NavigationStack: BindableObject {
let didChange = PassthroughSubject<Void, Never>()
var list: [AuthState] = []
public func push(state: AuthState) {
list.append(state)
didChange.send()
}
public func pop() {
list.removeLast()
didChange.send()
}
}
enum AuthState {
case mainScreenState
case userNameScreen
case logginScreen
case emailScreen
case passwordScreen
}
struct NavigationRoot : View {
@EnvironmentObject var state: NavigationStack
@State private var aligment = Alignment.leading
fileprivate func CurrentView() -> some View {
switch state.list.last {
case .mainScreenState:
return AnyView(GalleryState())
case .none:
return AnyView(LoginScreen().environmentObject(state))
default:
return AnyView(AuthenticationView().environmentObject(state))
}
}
var body: some View {
GeometryReader { geometry in
self.CurrentView()
.background(Image("background")
.animation(.fluidSpring())
.edgesIgnoringSafeArea(.all)
.frame(width: geometry.size.width, height: geometry.size.height,
alignment: self.aligment))
.edgesIgnoringSafeArea(.all)
.onAppear {
withAnimation() {
switch self.state.list.last {
case .none:
self.aligment = Alignment.leading
case .passwordScreen:
self.aligment = Alignment.trailing
default:
self.aligment = Alignment.center
}
}
}
}
.background(Color.black)
}
}
struct ExampleOfAddingNewView: View {
@EnvironmentObject var state: NavigationStack
var body: some View {
VStack {
Button(action:{ self.state.push(state: .emailScreen) }){
Text("Tap me")
}
}
}
}
struct ExampleOfRemovingView: View {
@EnvironmentObject var state: NavigationStack
var body: some View {
VStack {
Button(action:{ self.state.pop() }){
Text("Tap me")
}
}
}
}
在我看来这种方式很糟糕,但在 SwiftUI 中导航更糟糕
可能的解决方案
1.if 你想在当前视图的顶部呈现(例如:UIKit 中的呈现样式)
struct ContentView: View {
@State var showingDetail = false
var body: some View {
Button(action: {
self.showingDetail.toggle()
}) {
Text("Show Detail")
}.sheet(isPresented: $showingDetail) {
DetailView()
}
}
}
2.if 你想重置当前 window 场景堆栈(例如:登录后显示主屏幕)
Button(action: goHome) {
HStack(alignment: .center) {
Spacer()
Text("Login").foregroundColor(Color.white).bold()
Spacer()
}
}
func goHome() {
if let window = UIApplication.shared.windows.first {
window.rootViewController = UIHostingController(rootView: HomeScreen())
window.makeKeyAndVisible()
}
}
3.push 新视图(例如:list->detail,UIKit 的导航控制器)
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView()) {
Text("Show Detail View")
}.navigationBarTitle("Navigation")
}
}
}
}
4.update 当前视图基于@state 属性, (ex:show error message on login failure)
struct ContentView: View {
@State var error = true
var body: some View {
...
... //login email
.. //login password
if error {
Text("Failed to login")
}
}
}