How to add a TextField to Alert in SwiftUI?

AlertTextfieldSwiftui

Alert Problem Overview


Anyone an idea how to create an Alert in SwiftUI that contains a TextField?

sample_image

Alert Solutions


Solution 1 - Alert

Alert is quite limited at the moment, but you can roll your own solution in pure SwiftUI.

Here's a simple implementation of a custom alert with a text field.

struct TextFieldAlert<Presenting>: View where Presenting: View {

    @Binding var isShowing: Bool
    @Binding var text: String
    let presenting: Presenting
    let title: String

    var body: some View {
        GeometryReader { (deviceSize: GeometryProxy) in
            ZStack {
                self.presenting
                    .disabled(isShowing)
                VStack {
                    Text(self.title)
                    TextField(self.$text)
                    Divider()
                    HStack {
                        Button(action: {
                            withAnimation {
                                self.isShowing.toggle()
                            }
                        }) {
                            Text("Dismiss")
                        }
                    }
                }
                .padding()
                .background(Color.white)
                .frame(
                    width: deviceSize.size.width*0.7,
                    height: deviceSize.size.height*0.7
                )
                .shadow(radius: 1)
                .opacity(self.isShowing ? 1 : 0)
            }
        }
    }

}

And a View extension to use it:

extension View {

    func textFieldAlert(isShowing: Binding<Bool>,
                        text: Binding<String>,
                        title: String) -> some View {
        TextFieldAlert(isShowing: isShowing,
                       text: text,
                       presenting: self,
                       title: title)
    }

}

Demo:

enter image description here

struct ContentView : View {

    @State private var isShowingAlert = false
    @State private var alertInput = ""

    var body: some View {
        NavigationView {
            VStack {
                Button(action: {
                    withAnimation {
                        self.isShowingAlert.toggle()
                    }
                }) {
                    Text("Show alert")
                }
            }
            .navigationBarTitle(Text("A List"), displayMode: .large)
        }
        .textFieldAlert(isShowing: $isShowingAlert, text: $alertInput, title: "Alert!")
    }
}

Solution 2 - Alert

As the Alert view provided by SwiftUI doesn't do the job you will need indeed to use UIAlertController from UIKit. Ideally we want a TextFieldAlert view that we can presented in the same way we would present the Alert provided by SwiftUI:

struct MyView: View {
  
  @Binding var alertIsPresented: Bool
  @Binding var text: String? // this is updated as the user types in the text field
  
  var body: some View {
    Text("My Demo View")
      .textFieldAlert(isPresented: $alertIsPresented) { () -> TextFieldAlert in
        TextFieldAlert(title: "Alert Title", message: "Alert Message", text: self.$text)
    }
  }
}

We can achieve this writing a couple of classes and adding a modifier in a View extension.

  1. TextFieldAlertViewController creates a UIAlertController (with a text field of course) and presents it when it appears on screen. User changes to the text field are reflected into a Binding<String> that is passed during initializazion.

    class TextFieldAlertViewController: UIViewController {

    /// Presents a UIAlertController (alert style) with a UITextField and a Done button /// - Parameters: /// - title: to be used as title of the UIAlertController /// - message: to be used as optional message of the UIAlertController /// - text: binding for the text typed into the UITextField /// - isPresented: binding to be set to false when the alert is dismissed (Done button tapped) init(title: String, message: String?, text: Binding, isPresented: Binding?) { self.alertTitle = title self.message = message self._text = text self.isPresented = isPresented super.init(nibName: nil, bundle: nil) }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    // MARK: - Dependencies private let alertTitle: String private let message: String? @Binding private var text: String? private var isPresented: Binding?

    // MARK: - Private Properties private var subscription: AnyCancellable?

    // MARK: - Lifecycle override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) presentAlertController() }

    private func presentAlertController() { guard subscription == nil else { return } // present only once

     let vc = UIAlertController(title: alertTitle, message: message, preferredStyle: .alert)
     
     // add a textField and create a subscription to update the `text` binding
     vc.addTextField { [weak self] textField in
       guard let self = self else { return }
       self.subscription = NotificationCenter.default
         .publisher(for: UITextField.textDidChangeNotification, object: textField)
         .map { ($0.object as? UITextField)?.text }
         .assign(to: \.text, on: self)
     }
     
     // create a `Done` action that updates the `isPresented` binding when tapped
     // this is just for Demo only but we should really inject
     // an array of buttons (with their title, style and tap handler)
     let action = UIAlertAction(title: "Done", style: .default) { [weak self] _ in
       self?.isPresented?.wrappedValue = false
     }
     vc.addAction(action)
     present(vc, animated: true, completion: nil)
    

    } }

  2. TextFieldAlert wraps TextFieldAlertViewController using the UIViewControllerRepresentable protocol so that it can be used within SwiftUI.

    struct TextFieldAlert {

    // MARK: Properties let title: String let message: String? @Binding var text: String? var isPresented: Binding? = nil

    // MARK: Modifiers func dismissable(_ isPresented: Binding) -> TextFieldAlert { TextFieldAlert(title: title, message: message, text: $text, isPresented: isPresented) } }

    extension TextFieldAlert: UIViewControllerRepresentable {

    typealias UIViewControllerType = TextFieldAlertViewController

    func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIViewControllerType { TextFieldAlertViewController(title: title, message: message, text: $text, isPresented: isPresented) }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: UIViewControllerRepresentableContext) { // no update needed } }

  3. TextFieldWrapper is a simple ZStack with a TextFieldAlert on the back (only if isPresented is true) and a presenting view on the front. The presenting view is the only one visibile.

    struct TextFieldWrapper: View {

    @Binding var isPresented: Bool let presentingView: PresentingView let content: () -> TextFieldAlert

    var body: some View { ZStack { if (isPresented) { content().dismissable($isPresented) } presentingView } }
    }

  4. The textFieldAlert modifier allows us to smoothly wrap any SwiftUI view in a TextFieldWrapper and obtain the desired behaviour.

    extension View { func textFieldAlert(isPresented: Binding, content: @escaping () -> TextFieldAlert) -> some View { TextFieldWrapper(isPresented: isPresented, presentingView: self, content: content) } }

Solution 3 - Alert

You can simply use UIAlertController directly. No need to roll your own alert dialog UI:

private func alert() {
    let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
    alert.addTextField() { textField in
        textField.placeholder = "Enter some text"
    }
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in })
    showAlert(alert: alert)
}
        
func showAlert(alert: UIAlertController) {
    if let controller = topMostViewController() {
        controller.present(alert, animated: true)
    }
}

private func keyWindow() -> UIWindow? {
    return UIApplication.shared.connectedScenes
    .filter {$0.activationState == .foregroundActive}
    .compactMap {$0 as? UIWindowScene}
    .first?.windows.filter {$0.isKeyWindow}.first
}

private func topMostViewController() -> UIViewController? {
    guard let rootController = keyWindow()?.rootViewController else {
        return nil
    }
    return topMostViewController(for: rootController)
}

private func topMostViewController(for controller: UIViewController) -> UIViewController {
    if let presentedController = controller.presentedViewController {
        return topMostViewController(for: presentedController)
    } else if let navigationController = controller as? UINavigationController {
        guard let topController = navigationController.topViewController else {
            return navigationController
        }
        return topMostViewController(for: topController)
    } else if let tabController = controller as? UITabBarController {
        guard let topController = tabController.selectedViewController else {
            return tabController
        }
        return topMostViewController(for: topController)
    }
    return controller
}

Most of this code is just boilerplate to find the ViewController that should present the alert. Call alert() e.g. from the action of a button:

struct TestView: View {
    var body: some View {
        Button(action: { alert() }) { Text("click me") }
     }
}

Please beware though that there seems to be a bug in beta 5 and onward that can sometimes cause the emulator to freeze once a text field is shown: https://stackoverflow.com/questions/57509557/xcode-11-beta-5-ui-freezes-when-adding-textfields-into-uialertcontroller/57843362#57843362

Solution 4 - Alert

I found modals and alerts in SwiftUI to be lacking several features. For instance, there doesn't seem to be a way of presenting a modal with FormSheet style.

When I need to present a complex alert (such as one with textfields), I create a pure SwiftUI view with all the content of the alert, and then present it as a FormSheet using a UIHostController.

If you do not have a UIViewController around to call present(), you can always use the root view controller.

With this approach you get some nice features, such as the standard alert animation both going in, and out. You can also drag the alert down to dismiss it.

The alert view also moves up when the keyboard appears.

This works nicely on iPad. On iPhone, FormSheet is full screen so you may need to tweak the code to find a solution. I think this will give you a good starting point.

enter image description here

It is something like this:

struct ContentView : View {
    @State private var showAlert = false
    
    var body: some View {
        VStack {
            Button(action: {
                let alertHC = UIHostingController(rootView: MyAlert())
                
                alertHC.preferredContentSize = CGSize(width: 300, height: 200)
                alertHC.modalPresentationStyle = UIModalPresentationStyle.formSheet
                
                UIApplication.shared.windows[0].rootViewController?.present(alertHC, animated: true)
                
            }) {
                Text("Show Alert")
            }
        }
    }
}

struct MyAlert: View {
    @State private var text: String = ""
    
    var body: some View {
        
        VStack {
            Text("Enter Input").font(.headline).padding()

            TextField($text, placeholder: Text("Type text here")).textFieldStyle(.roundedBorder).padding()
            Divider()
            HStack {
                Spacer()
                Button(action: {
                    UIApplication.shared.windows[0].rootViewController?.dismiss(animated: true, completion: {})
                }) {
                    
                    Text("Done")
                }
                Spacer()
                
                Divider()
                
                Spacer()
                Button(action: {
                    UIApplication.shared.windows[0].rootViewController?.dismiss(animated: true, completion: {})
                }) {
                    Text("Cancel")
                }
                Spacer()
            }.padding(0)

            
            }.background(Color(white: 0.9))
    }
}

If you find yourself using this a lot, the button row may be encapsulated in a separate view for easy reuse.

Solution 5 - Alert

Although not exactly the same, if all you're looking for is a native, modal-like view with an edit box, you could use a popover. It works out of the box (minus a sizing bug) without needing to traverse the view hierarchy.

Solution 6 - Alert

Simple native solution for iOS

extension View {

    public func textFieldAlert(
        isPresented: Binding<Bool>,
        title: String,
        text: String = "",
        placeholder: String = "",
        action: @escaping (String?) -> Void
    ) -> some View {
        self.modifier(TextFieldAlertModifier(isPresented: isPresented, title: title, text: text, placeholder: placeholder, action: action))
    }
    
}
public struct TextFieldAlertModifier: ViewModifier {

    @State private var alertController: UIAlertController?

    @Binding var isPresented: Bool

    let title: String
    let text: String
    let placeholder: String
    let action: (String?) -> Void

    public func body(content: Content) -> some View {
        content.onChange(of: isPresented) { isPresented in
            if isPresented, alertController == nil {
                let alertController = makeAlertController()
                self.alertController = alertController
                guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
                    return
                }
                scene.windows.first?.rootViewController?.present(alertController, animated: true)
            } else if !isPresented, let alertController = alertController {
                alertController.dismiss(animated: true)
                self.alertController = nil
            }
        }
    }

    private func makeAlertController() -> UIAlertController {
        let controller = UIAlertController(title: title, message: nil, preferredStyle: .alert)
        controller.addTextField {
            $0.placeholder = self.placeholder
            $0.text = self.text
        }
        controller.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
            self.action(nil)
            shutdown()
        })
        controller.addAction(UIAlertAction(title: "OK", style: .default) { _ in
            self.action(controller.textFields?.first?.text)
            shutdown()
        })
        return controller
    }

    private func shutdown() {
        isPresented = false
        alertController = nil
    }

}

Usage:

struct ContentView: View {

    @State private var isRenameAlertPresented = false
    @State private var title = "Old title"

    var body: some View {
        VStack {
            Button("Rename title") {
                isRenameAlertPresented = true
            }

            Text(title)
        }
        .textFieldAlert(
            isPresented: $isRenameAlertPresented,
            title: "Rename",
            text: "Title",
            placeholder: "",
            action: { newText in
                title = newText ?? ""
            }
        )
    }
}

Solution 7 - Alert

As already was mentioned Alert is provide not many functionality and so almost useless in any non-standard cases when using in SwiftUI.

I ended up with a bit extensive solution - View that may behave as alert with high customisation level.

  1. Create ViewModel for popUp:

    struct UniAlertViewModel {
     
     let backgroundColor: Color = Color.gray.opacity(0.4)
     let contentBackgroundColor: Color = Color.white.opacity(0.8)
     let contentPadding: CGFloat = 16
     let contentCornerRadius: CGFloat = 12
    }
    
  2. we also need to configure buttons, for this purpose let's add one more type:

    struct UniAlertButton {
     
     enum Variant {
         
         case destructive
         case regular
     }
     
     let content: AnyView
     let action: () -> Void
     let type: Variant
     
     var isDestructive: Bool {
         type == .destructive
     }
     
     static func destructive<Content: View>(
         @ViewBuilder content: @escaping () -> Content
     ) -> UniAlertButton {
         UniAlertButton(
             content: content,
             action: { /* close */ },
             type: .destructive)
     }
     
     static func regular<Content: View>(
         @ViewBuilder content: @escaping () -> Content,
         action: @escaping () -> Void
     ) -> UniAlertButton {
         UniAlertButton(
             content: content,
             action: action,
             type: .regular)
     }
     
     private init<Content: View>(
         @ViewBuilder content: @escaping () -> Content,
         action: @escaping () -> Void,
         type: Variant
     ) {
         self.content = AnyView(content())
         self.type = type
         self.action = action
     }
    }
    
  3. add View that can become our customizable popUp:

    struct UniAlert<Presenter, Content>: View where Presenter: View, Content: View {
     
     @Binding private (set) var isShowing: Bool
     
     let displayContent: Content
     let buttons: [UniAlertButton]
     let presentationView: Presenter
     let viewModel: UniAlertViewModel
     
     private var requireHorizontalPositioning: Bool {
         let maxButtonPositionedHorizontally = 2
         return buttons.count > maxButtonPositionedHorizontally
     }
     
     var body: some View {
         GeometryReader { geometry in
             ZStack {
                 backgroundColor()
                 
                 VStack {
                     Spacer()
                     
                     ZStack {
                         presentationView.disabled(isShowing)
                         let expectedWidth = geometry.size.width * 0.7
    
                         VStack {
                             displayContent
                             buttonsPad(expectedWidth)
                         }
                         .padding(viewModel.contentPadding)
                         .background(viewModel.contentBackgroundColor)
                         .cornerRadius(viewModel.contentCornerRadius)
                         .shadow(radius: 1)
                         .opacity(self.isShowing ? 1 : 0)
                         .frame(
                             minWidth: expectedWidth,
                             maxWidth: expectedWidth
                         )
                     }
                     
                     Spacer()
                 }
             }
         }
     }
     
     private func backgroundColor() -> some View {
         viewModel.backgroundColor
             .edgesIgnoringSafeArea(.all)
             .opacity(self.isShowing ? 1 : 0)
     }
     
     private func buttonsPad(_ expectedWidth: CGFloat) -> some View {
         VStack {
             if requireHorizontalPositioning {
                 verticalButtonPad()
             } else {
                 Divider().padding([.leading, .trailing], -viewModel.contentPadding)
                 horizontalButtonsPadFor(expectedWidth)
             }
         }
     }
     
     private func verticalButtonPad() -> some View {
         VStack {
             ForEach(0..<buttons.count) {
                 Divider().padding([.leading, .trailing], -viewModel.contentPadding)
                 let current = buttons[$0]
                 
                 Button(action: {
                     if !current.isDestructive {
                         current.action()
                     }
                     
                     withAnimation {
                         self.isShowing.toggle()
                     }
                 }, label: {
                     current.content.frame(height: 35)
                 })
             }
         }
     }
    
     private func horizontalButtonsPadFor(_ expectedWidth: CGFloat) -> some View {
         HStack {
             let sidesOffset = viewModel.contentPadding * 2
             let maxHorizontalWidth = requireHorizontalPositioning ?
                 expectedWidth - sidesOffset :
                 expectedWidth / 2 - sidesOffset
             
             Spacer()
             
             if !requireHorizontalPositioning {
                 ForEach(0..<buttons.count) {
                     if $0 != 0 {
                         Divider().frame(height: 44)
                     }
                     let current = buttons[$0]
                     
                     Button(action: {
                         if !current.isDestructive {
                             current.action()
                         }
                         
                         withAnimation {
                             self.isShowing.toggle()
                         }
                     }, label: {
                         current.content
                     })
                     .frame(maxWidth: maxHorizontalWidth, minHeight: 44)
                 }
             }
             Spacer()
         }
     }
    }
    
  4. to simplify usage let's add extension to View:

    extension View {
     
     func assemblyAlert<Content>(
         isShowing: Binding<Bool>,
         viewModel: UniAlertViewModel,
         @ViewBuilder content: @escaping () -> Content,
         actions: [UniAlertButton]
     ) -> some View where Content: View {
         UniAlert(
             isShowing: isShowing,
             displayContent: content(),
             buttons: actions,
             presentationView: self,
             viewModel: viewModel)
     }
    }
    

And usage:

struct ContentView: View {
    
    @State private var isShowingAlert: Bool = false
    @State private var text: String = ""
    
    var body: some View {
        VStack {
            Button(action: {
                withAnimation {
                    isShowingAlert.toggle()
                }
            }, label: {
                Text("Show alert")
            })
        }
        .assemblyAlert(isShowing: $isShowingAlert,
                       viewModel: UniAlertViewModel(),
                       content: {
                        Text("title")
                        Image(systemName: "phone")
                            .scaleEffect(3)
                            .frame(width: 100, height: 100)
                        TextField("enter text here", text: $text)
                        Text("description")
                       }, actions: buttons)
        }
   }
 }

Demo:

enter image description here

Solution 8 - Alert

This is an example based on the SwiftUI Sheet class that displays a dialog with a prompt, a text field, and the classic OK and Dismiss button

enter image description here

enter image description here

First lets make our Dialog class, which will pop when user want to edit a value:

import SwiftUI

struct Dialog: View {
    @Environment(\.presentationMode) var presentationMode

    /// Edited value, passed from outside
    @Binding var value: String?

    /// Prompt message
    var prompt: String = ""
    
    /// The value currently edited
    @State var fieldValue: String
    
    /// Init the Dialog view
    /// Passed @binding value is duplicated to @state value while editing
    init(prompt: String, value: Binding<String?>) {
        _value = value
        self.prompt = prompt
        _fieldValue = State<String>(initialValue: value.wrappedValue ?? "")
    }

    var body: some View {
        VStack {
            Text(prompt).padding()
            TextField("", text: $fieldValue)
            .frame(width: 200, alignment: .center)
            HStack {
            Button("OK") {
                self.value = fieldValue
                self.presentationMode.wrappedValue.dismiss()
            }
            Button("Dismiss") {
                self.presentationMode.wrappedValue.dismiss()
            }
            }.padding()
        }
        .padding()
    }
}

#if DEBUG
struct Dialog_Previews: PreviewProvider {

    static var previews: some View {
        var name = "John Doe"
        Dialog(prompt: "Name", value: Binding<String?>.init(get: { name }, set: {name = $0 ?? ""}))
    }
}
#endif

Now we use it this way in the caller View:

import SwiftUI

struct ContentView: View {
    /// Is the input dialog displayed
    @State var dialogDisplayed = false
    
    /// The name to edit
    @State var name: String? = nil
    
    var body: some View {
        VStack {
            Text(name ?? "Unnamed").frame(width: 200).padding()
            Button(name == nil ? "Set Name" : "Change Name") {
                dialogDisplayed = true
            }
            .sheet(isPresented: $dialogDisplayed) {
                Dialog(prompt: name == nil ? "Enter a name" : "Enter a new name", value: $name)
            }
            .onChange(of: name, perform: { value in
                print("Name Changed : \(value)")
            }
            .padding()
        }
        .padding()
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

Solution 9 - Alert

Step1: Make root view as ZStack

Step2: Add variable for show/hide

 @State var showAlert = false

Step 3: Add this custom layout inside root view (ZStack)

  if $showAlert.wrappedValue {
            ZStack() {
                Color.grayBackground
                VStack {
                    //your custom layout text fields buttons 
                   
                }.padding()
            }
            .frame(width: 300, height: 180,alignment: .center)
            .cornerRadius(20).shadow(radius: 20)
        }

Solution 10 - Alert

Based on the idea of tanzolone

import Foundation
import Combine
import SwiftUI

class TextFieldAlertViewController: UIViewController {
    
    /// Presents a UIAlertController (alert style) with a UITextField and a `Done` button
    /// - Parameters:
    ///   - title: to be used as title of the UIAlertController
    ///   - message: to be used as optional message of the UIAlertController
    ///   - text: binding for the text typed into the UITextField
    ///   - isPresented: binding to be set to false when the alert is dismissed (`Done` button tapped)
    init(isPresented: Binding<Bool>, alert: TextFieldAlert) {
        self._isPresented = isPresented
        self.alert = alert
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    @Binding
    private var isPresented: Bool
    private var alert: TextFieldAlert
    
    // MARK: - Private Properties
    private var subscription: AnyCancellable?
    
    // MARK: - Lifecycle
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        presentAlertController()
    }
    
    private func presentAlertController() {
        guard subscription == nil else { return } // present only once
        
        let vc = UIAlertController(title: alert.title, message: alert.message, preferredStyle: .alert)
        // add a textField and create a subscription to update the `text` binding
        vc.addTextField {
            // TODO: 需要补充这些参数
            // $0.placeholder = alert.placeholder
            // $0.keyboardType = alert.keyboardType
            // $0.text = alert.defaultValue ?? ""
            $0.text = self.alert.defaultText
        }
        if let cancel = alert.cancel {
            vc.addAction(UIAlertAction(title: cancel, style: .cancel) { _ in
                //                self.action(nil)
                self.isPresented = false
            })
        }
        let textField = vc.textFields?.first
        vc.addAction(UIAlertAction(title: alert.accept, style: .default) { _ in
            self.isPresented = false
            self.alert.action(textField?.text)
        })
        present(vc, animated: true, completion: nil)
    }
}

struct TextFieldAlert {
    
    let title: String
    let message: String?
    var defaultText: String = ""
    public var accept: String = "好".localizedString // The left-most button label
    public var cancel: String? = "取消".localizedString // The optional cancel (right-most) button label
    public var action: (String?) -> Void // Triggers when either of the two buttons closes the dialog
    
}

struct AlertWrapper:  UIViewControllerRepresentable {
    
    @Binding var isPresented: Bool
    let alert: TextFieldAlert
    
    typealias UIViewControllerType = TextFieldAlertViewController
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<AlertWrapper>) -> UIViewControllerType {
        TextFieldAlertViewController(isPresented: $isPresented, alert: alert)
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: UIViewControllerRepresentableContext<AlertWrapper>) {
        // no update needed
    }
}

struct TextFieldWrapper<PresentingView: View>: View {
    
    @Binding var isPresented: Bool
    let presentingView: PresentingView
    let content: TextFieldAlert
    
    
    var body: some View {
        ZStack {
            if (isPresented) {
                AlertWrapper(isPresented: $isPresented, alert: content)
            }
            presentingView
        }
    }
}

extension View {
    
    func alert(isPresented: Binding<Bool>, _ content: TextFieldAlert) -> some View {
        TextFieldWrapper(isPresented: isPresented, presentingView: self, content: content)
    }
    
}

How to use

xxxView .alert(isPresented: $showForm, TextFieldAlert(title: "添加分组", message: "") { (text) in if text != nil { self.saveGroup(text: text!) } })

Solution 11 - Alert

HostingWindow+present

extension UIWindow {
    public func showAlert(alertController: UIAlertController, placeholder: String, primaryTitle: String, cancelTitle: String, primaryAction: @escaping (String) -> Void) {

        alertController.addTextField { textField in
            textField.placeholder = placeholder
        }

        let primaryButton = UIAlertAction(title: primaryTitle, style: .default) { _ in
            guard let text = alertController.textFields?[0].text else { return }
            primaryAction(text)
        }

        let cancelButton = UIAlertAction(title: cancelTitle, style: .cancel, handler: nil)

        alertController.addAction(primaryButton)
        alertController.addAction(cancelButton)

        self.rootViewController?.present(alertController, animated: true)
    }
}

Solution 12 - Alert

func dialog(){
        
       let alertController = UIAlertController(title: "Contry", message: "Write contrt code here", preferredStyle: .alert)

        alertController.addTextField { (textField : UITextField!) -> Void in
            textField.placeholder = "Country code"
        }

        let saveAction = UIAlertAction(title: "Save", style: .default, handler: { alert -> Void in
            
            let secondTextField = alertController.textFields![0] as UITextField
            print("county code : ",secondTextField)
            
        })

        let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil )

        
        alertController.addAction(saveAction)
        alertController.addAction(cancelAction)

        UIApplication.shared.windows.first?.rootViewController?.present(alertController, animated: true, completion: nil)
        
        
    }

Usage

Button(action: { self.dialog()})
 {
Text("Button")
.foregroundColor(.white).fontWeight(.bold)
 }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCaptain VrilView Question on Stackoverflow
Solution 1 - AlertMatteo PaciniView Answer on Stackoverflow
Solution 2 - AlerttanzoloneView Answer on Stackoverflow
Solution 3 - AlertFabian StreitelView Answer on Stackoverflow
Solution 4 - AlertkontikiView Answer on Stackoverflow
Solution 5 - AlertSensefulView Answer on Stackoverflow
Solution 6 - AlertnightwillView Answer on Stackoverflow
Solution 7 - AlerthbkView Answer on Stackoverflow
Solution 8 - AlertMooseView Answer on Stackoverflow
Solution 9 - AlertRanjithkumarView Answer on Stackoverflow
Solution 10 - AlertLister LeeView Answer on Stackoverflow
Solution 11 - AlerthstdtView Answer on Stackoverflow
Solution 12 - AlerttsnisoView Answer on Stackoverflow