簡體   English   中英

單擊 swiftui 中的按鈕后如何根據條件顯示不同的警報

[英]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的一個實例,該實例具有我們想要顯示的警報類型。 在這種情況下,我們有兩種類型:成功和失敗(但我們可以擁有任意數量的類型,並且我們不需要使用名稱successfailure )。 設置后,它將顯示適當的警報。

在我們的.alert(item:content:)中,我們切換不同的id ,以便我們可以確保為正確的選擇顯示正確的警報。

這種方法比擁有多個布爾值要容易得多,並且更容易擴展。

Sheets 和 ActionSheets 的附錄

SheetsActionSheets在呈現方式上與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)

我應該使用哪種綁定?

綁定<布爾>

如果您只需要顯示一種類型的AlertSheetActionSheet然后使用Bool綁定,它可以節省您編寫一些額外的代碼行。

綁定<可識別?>

如果要顯示許多不同類型的AlertSheetActionSheet ,請選擇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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM