[英]how to show different alerts based on a condition after clicking a button in swiftui
我在這里發布之前做了一些研究,但我無法修復它。
在注冊視圖中我希望用戶注冊。
我創建了一個鏈接列表,當用戶注冊用戶名時,我的程序檢查用戶名是否已被使用。
如果它被占用,它應該在用戶單擊注冊按鈕時發出警報,說明用戶名已被占用。
如果未使用用戶名,則應顯示注冊成功的警報
import SwiftUI
struct registerScreen: View {
@State var username: String = ""
@State var password: String = ""
@State private var sucessfulRegister = false
@State private var failedRegister = false
var body: some View {
VStack {
TextField()
SecureField()
Button(action: {
let userinfo = linkedList()
if (userinfo.contains(value: self.username)){
// self.failedRegister = true
self.failedRegister.toggle()
// show alert that it failed
} else {
userinfo.insert(value: user(username: self.username, password: self.password))
// show alert that it is successfull
self.sucessfulRegister.toggle()
}
})
{
Text("Register")
.font(.headline)
.foregroundColor(.white)
.padding()
.frame(width: 220, height: 60)
.background(Color.green)
.cornerRadius(15.0)
}
}
}
}
這是可能的。 盡管您不需要跟蹤盡可能多的狀態。
首先,您只需要跟蹤它們是否失敗。 因此,您的failedRegister
將跟蹤用戶是否已成功注冊。 這意味着我們可以刪除successfulRegister
的Register。
我們需要一個變量來跟蹤警報是否顯示,為此我們將使用變量showAlert
由於您有一個提供用戶信息的鏈接列表,我們將只使用一個包含幾個用戶名的數組來模擬它。
因此,這是您的代碼的簡化版本,應該可以使用。
struct ContentView: View {
var names: [String] = ["John", "Mike"]
@State var username: String = ""
@State var password : String = ""
@State private var failedRegister = false
// this value is used for tracking whether the alert should be shown
@State private var showAlert = false
var body: some View {
VStack {
TextField("Enter username", text: $username)
Button(action: {
// reset to false as this is the initial state
self.failedRegister = false
if (self.names.contains(self.username)){
self.failedRegister.toggle()
} else {
// insert the value into the user info
}
self.showAlert.toggle()
}) {
Text("Register")
.font(.headline)
.foregroundColor(.white)
.padding()
.frame(width: 220, height: 60)
.background(Color.green)
.cornerRadius(15.0)
}
}.alert(isPresented: $showAlert) {
// it would be nice to set failedRegister back to false in this function but you cannot modify state here.
if self.failedRegister {
return Alert(title: Text("Failed to register"), message: Text("Unfortunately that username is taken"), dismissButton: .default(Text("OK")))
} else {
return Alert(title: Text("Welcome"), message: Text("You have registered"), dismissButton: .default(Text("OK")))
}
}
}
}
有另一種方法可以在同一View
上顯示不同的Alerts
。 這是為了使用與Identifiable
的 object 的綁定。
如果我們看一下我們可以在View
上初始化Alert
的方式,我們會看到有兩種方式。 第一個具有以下簽名:
.alert(isPresented: Binding<Bool>, content: () -> Alert)
這是上面示例中使用的。
但是,還有第二種方法具有以下簽名:
.alert(item: Binding<Identifiable?>, content: (Identifiable) -> Alert)
第二種方式可以允許管理更復雜的警報。 為了利用這一點,我們需要一些東西來跟蹤警報的 state。 我們可以創建一個簡單的結構,該結構符合Identifiable
並包含我們對警報的不同選擇的枚舉。
然后我們創建一個@State
變量來跟蹤AlertIdentifier
並將其初始化為nil
,以便其 state 為空,並且在更改之前不會顯示任何警報。
然后我們可以將.alert(item:content:)
添加到我們的View
中。
這是一個簡單的例子,展示了它的作用。
struct ContentView:View {
private struct AlertIdentifier: Identifiable {
var id: Choice
enum Choice {
case success
case failure
}
}
@State private var showAlert: AlertIdentifier? // init this as nil
var body: some View {
VStack(spacing: 20) {
Button(action: {
self.showAlert = AlertIdentifier(id: .success)
}, label: {
Text("Show success alert")
})
Button(action: {
self.showAlert = AlertIdentifier(id: .failure)
}, label: {
Text("Show failure alert")
})
}
.alert(item: $showAlert) { alert -> Alert in
switch alert.id {
case .success:
return Alert(title: Text("Success"), message: Text("You have successfully registered"), dismissButton: .default(Text("OK")))
case .failure:
return Alert(title: Text("Failure"), message: Text("You have failed to register"), dismissButton: .default(Text("OK")))
}
}
}
}
請注意,在按鈕中,我們將showAlert
設置為 struct AlertIdentifier
的一個實例,該實例具有我們想要顯示的警報類型。 在這種情況下,我們有兩種類型:成功和失敗(但我們可以擁有任意數量的類型,並且我們不需要使用名稱success和failure )。 設置后,它將顯示適當的警報。
在我們的.alert(item:content:)
中,我們切換不同的id
,以便我們可以確保為正確的選擇顯示正確的警報。
這種方法比擁有多個布爾值要容易得多,並且更容易擴展。
Sheets
和ActionSheets
在呈現方式上與Alerts
非常相似。 有四種方式來呈現Sheets
。
這兩個需要Bool
綁定:
.sheet(isPresented: Binding<Bool>, content: () -> View)
.sheet(isPresented: Binding<Bool>, onDismiss: (() -> Void)?, content: () -> Void)
這兩個需要一個Identifiable
綁定:
.sheet(item: Binding<Identifiable?>, content: (Identifiable) -> View)
.sheet(item: Binding<Identifiable?>, onDismiss: (() -> Void)?, content: (Identifiable) -> View)
對於ActionSheets
有兩種方式,例如Alerts
。
使用Bool
綁定:
.actionSheet(isPresented: Binding<Bool>, content: () -> ActionSheet)
使用Identifiable
綁定:
.actionSheet(item: Binding<Identifiable?>, content: (Identifiable) -> ActionSheet)
如果您只需要顯示一種類型的Alert
、 Sheet
或ActionSheet
然后使用Bool
綁定,它可以節省您編寫一些額外的代碼行。
如果要顯示許多不同類型的Alert
、 Sheet
或ActionSheet
,請選擇Identifiable
綁定,因為它更易於管理。
可識別的 object 的更簡單版本是使用枚舉而不將其包裝在結構中。 在這種情況下,我們需要符合 Identifiable,因此我們需要一個計算屬性來存儲 id 值。 我們還需要確保枚舉使用 RawRepresentable,以便我們可以獲得唯一的 id 值。 我建議使用 Int 或 String。 在下面的示例中,我使用的是 Int。
enum Choice: Int, Identifiable {
var id: Int {
rawValue
}
case success, failure
}
然后在視圖中我們可以執行以下操作:
struct ContentView:View {
enum Choice: Int, Identifiable {
var id: Int {
rawValue
}
case success, failure
}
@State private var showAlert: Choice? // init this as nil
var body: some View {
VStack(spacing: 20) {
Button(action: {
self.showAlert = .success
}, label: {
Text("Show success alert")
})
Button(action: {
self.showAlert = .failure
}, label: {
Text("Show failure alert")
})
}
.alert(item: $showAlert) { alert -> Alert in
switch alert {
case .success:
return Alert(title: Text("Success"), message: Text("You have successfully registered"), dismissButton: .default(Text("OK")))
case .failure:
return Alert(title: Text("Failure"), message: Text("You have failed to register"), dismissButton: .default(Text("OK")))
}
}
}
}
與 Andrew 解決方案相同,但枚舉來自 ContentView 的 scope,允許在其他視圖中使用,分組在一個位置
enum Choice {
case success
case failure
}
extension Choice: Identifiable {
var id: Choice { self }
}
struct ContentView:View {
.../...
}
雖然 Andrew 的回答非常翔實,但這里是一個“長話短說”的答案,適用於iOS14 :
struct YourView: View {
enum AlertType: Identifiable {
case first, second
var id: Int {
hashValue
}
}
@State var alertType: AlertType?
var body: some View {
VStack {
Button("Show alert #1") {
alertType = .first
}
Button("Show alert #2") {
alertType = .second
}
}
.alert(item: $alertType) { type in
switch type {
case .first:
return Alert(title: Text("First alert"))
case .second:
return Alert(title: Text("Second alert"))
}
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.