单击swiftui中的按钮后如何根据条件显示不同的警报 [英] how to show different alerts based on a condition after clicking a button in swiftui

查看:18
本文介绍了单击swiftui中的按钮后如何根据条件显示不同的警报的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里发布之前做了一些研究,但我无法修复它.

I did some research before posting it here but I was not able to fix it.

在注册视图中我希望用户注册.

In the register View I want the user to register.

我创建了一个链表,当用户注册用户名时,我的程序会检查用户名是否已被占用.

I created a linked list and as user registers a username my program checks whether or not the username is already taken.

如果它被占用,它应该给出一个警告,说用户点击注册按钮时用户名已经被占用.

if it is taken it should give an alert saying that the username is already taken as the user clicks the register button.

如果用户名没有被占用,那么它应该显示一个提示注册成功

if the username is not taken then it should show an alert saying the registration is successful

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)

            }

        }

    }

}

推荐答案

是可以的.尽管您不需要跟踪尽可能多的状态.

It is possible to do. Though you don't need to track as many states as you are.

首先,您只需要跟踪它们是否失败.因此,您的 failedRegister 将跟踪用户是否已成功注册.这意味着我们可以删除 successfulRegister.

Firstly, you only need to track if they have failed or not. So your failedRegister will track if the user has successfully registered or not. That means we can get remove the successfulRegister.

我们需要一个变量来跟踪警报是否显示,为此我们将使用变量 showAlert

We need a variable to track whether an alert is showing or not, for this we will use the variable showAlert

由于您有一个提供用户信息的链表,我们将仅使用一个包含几个用户名的数组来模拟它.

As you have a linked list that provides the userinfo, we will mock that with just an array containing a couple of usernames.

这里是您的代码的简化版本,应该可以工作.

So here is a simplified version of your code that should work.

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 的对象的绑定.


Update using Identifiable

There is an alternative way to show different Alerts on the same View. This is to use a binding to an object that is Identifiable.

如果我们查看在 View 上初始化 Alert 的方法,我们会发现有两种方法.第一个具有以下签名:

If we look at the ways we can initialise an Alert on a View we see there are two ways. The first has the following signature:

.alert(isPresented: Binding<Bool>, content: () -> Alert)

上面例子中使用的是什么.

Which is what is used in the example above.

然而,还有第二种方法具有以下签名:

However there is a second way which has the following signature:

.alert(item: Binding<Identifiable?>, content: (Identifiable) -> Alert)

第二种方式可以允许管理更复杂的警报.为了利用这一点,我们需要一些东西来跟踪警报的状态.我们可以创建一个简单的结构,它符合 Identifiable 并包含我们对警报的不同选择的枚举.

This second way can allow for more complex alerts to be managed. To utilise this we need something to track the state of the alerts. We can create a simple struct that conforms to Identifiable and contains an enum of the different choices that we have for an alert.

然后我们创建一个 @State 变量来跟踪 AlertIdentifier 并初始化为 nil 使其状态为空并且不会显示任何警报,直到更改为止.

We then create an @State variable to track the AlertIdentifier and initialise to nil so that its state is empty and will not show any alerts until it is changed.

然后我们可以将我们的 .alert(item:content:) 添加到我们的 View.

We can then add our .alert(item:content:) to our View.

这是一个简单的例子,展示了它的实际效果.

Here is a simple example showing it in action.

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 设置为结构 AlertIdentifier 的实例,具有我们想要显示的警报类型.在这种情况下,我们有两种类型:成功和失败(但我们可以拥有任意数量的类型,我们不需要使用名称 successfailure).设置后,它将显示相应的警报.

Notice that in the buttons we set the showAlert to be an instance of the struct AlertIdentifier with the type of alert we want to show. In this case we have two types: success and failure (but we could have as many types as we want, and we don't need to use the names success and failure). When that is set, it will show the appropriate alert.

在我们的 .alert(item:content:) 中,我们切换不同的 id 以便我们可以确保为正确的选择显示正确的警报.

In our .alert(item:content:) we switch over the different ids so that we can make sure that the correct alert is shown for the correct choice.

这种方法比有多个布尔值要容易得多,也更容易扩展.

This method is much easier than having multiple booleans, and it is easier to extend.

SheetsActionSheets 在呈现方式上与 Alerts 非常相似.Sheets 有四种呈现方式.

Sheets and ActionSheets are very similar to Alerts in how they are presented. There are four ways to present 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.

For ActionSheets there are two ways, like Alerts.

使用 Bool 绑定:

.actionSheet(isPresented: Binding<Bool>, content: () -> ActionSheet)

使用 Identifiable 绑定:

.actionSheet(item: Binding<Identifiable?>, content: (Identifiable) -> ActionSheet)

我应该使用哪种绑定?

绑定<布尔>

如果您只需要显示一种类型的 AlertSheetActionSheet 然后使用 Bool 绑定,这样您就不必编写一些额外的代码行了.

Which binding should I use?

Binding<Bool>

If you only need to show one type of Alert, Sheet or ActionSheet then use the Bool binding, it saves you having to write some extra lines of code.

如果您要显示多种不同类型的 Alerts、Sheets 或 ActionSheets,则选择 Identifiable> 绑定,因为它更易于管理.

If you many different types of Alerts, Sheets or ActionSheets to show then choose the Identifiable binding as it makes it much easier to manage.

可识别对象的更简单版本是使用枚举而不将其包装在结构中.在这种情况下,我们需要符合 Identifiable 因此我们需要一个计算属性来存储 id 值.我们还需要确保枚举使用 RawRepresentable 以便我们可以获得唯一的 id 值.我建议使用 Int 或 String.在下面的示例中,我使用的是 Int.

A simpler version of the identifiable object would be to use an enum without wrapping it in a struct. In this case we need to conform to Identifiable so we need a computed property to store the id value. We also need to make sure that the enum uses a RawRepresentable so that we can get a value for the id that is unique. I would suggest using an Int or a String. In the example below I am using an Int.

enum Choice: Int, Identifiable {
    var id: Int {
        rawValue
    }

    case success, failure
}

然后在视图中我们可以执行以下操作:

Then in the view we could do the following:

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")))
            }
        }
    }
}

这篇关于单击swiftui中的按钮后如何根据条件显示不同的警报的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆