Quantcast
Channel: Active questions tagged uipickerview - Stack Overflow
Viewing all articles
Browse latest Browse all 592

SwiftUI Alert with Picker

$
0
0

I'm trying to create a SwiftUI alert dialog that contains a picker view inside of it, similar to the example here https://github.com/zhiyao92/PickerView-on-AlertController.

This is the code I've built so far in PickerAlert.swift

import SwiftUIpublic struct PickerAlert {    public var title: String = "" // Title of the dialog    public var message: String = "" // Dialog message    public var pickerData: [String] = ["red", "green"] // Data for the picker    public var action: (String?) -> Void // Triggers when either of the two buttons closes the dialog}extension UIAlertController {    convenience init(alert: PickerAlert) {        self.init(title: alert.title, message: alert.message, preferredStyle: .alert)        let pickerFrame = UIPickerView(frame: CGRect(x: 5, y: 20, width: 250, height: 140))        pickerFrame.reloadAllComponents()        // Set the picker view as the accessory view of the alert controller        self.view.addSubview(pickerFrame)        self.view.translatesAutoresizingMaskIntoConstraints = false        self.view.addConstraints([            pickerFrame.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 60),            pickerFrame.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20),            pickerFrame.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -20),            pickerFrame.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -50)        ])        addAction(UIAlertAction(title: "Cancel", style: .destructive) { _ in            alert.action(nil)        })        addAction(UIAlertAction(title: "OK", style: .default) { _ in            alert.action("dummy data")        })    }}struct PickerAlertWrapper<Content: View>: UIViewControllerRepresentable {    @Binding var isPresented: Bool    let alert: PickerAlert    let content: Content    func makeUIViewController(context: UIViewControllerRepresentableContext<PickerAlertWrapper>) -> UIHostingController<Content> {        UIHostingController(rootView: content)    }    final class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {        var alertController: UIAlertController?        let alert: PickerAlert        init(alert: PickerAlert, controller: UIAlertController? = nil) {            self.alert = alert            self.alertController = controller            super.init()            // Create the picker view instance and add it as a subview to the alert controller's view            if let pickerFrame = alertController?.view.subviews.first as? UIPickerView {                pickerFrame.dataSource = self                pickerFrame.delegate = self                pickerFrame.reloadAllComponents()            }        }        func numberOfComponents(in pickerView: UIPickerView) -> Int {            return 1        }        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {            return alert.pickerData.count        }        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {            return alert.pickerData[row]        }    }    func makeCoordinator() -> Coordinator {        let coordinator = Coordinator(alert: alert)        return coordinator    }    func updateUIViewController(_ uiViewController: UIHostingController<Content>, context: UIViewControllerRepresentableContext<PickerAlertWrapper>) {        uiViewController.rootView = content        if isPresented && uiViewController.presentedViewController == nil {            var alert = self.alert            alert.action = {                self.isPresented = false                self.alert.action($0)            }            context.coordinator.alertController = UIAlertController(alert: alert)            uiViewController.present(context.coordinator.alertController!, animated: true)        }        if !isPresented && uiViewController.presentedViewController == context.coordinator.alertController {            uiViewController.dismiss(animated: true)        }    }}extension View {    public func alert(isPresented: Binding<Bool>, _ alert: PickerAlert) -> some View {        PickerAlertWrapper(isPresented: isPresented, alert: alert, content: self)    }}

This is the code of a SwiftUI view that shows the alert with the picker.

struct MyView: View {    @StateObject var viewModel = MyViewModel()    var body: some View {        ZStack {            Text("")                .hidden()                .alert(isPresented: $viewModel.showSelectHomeAlert,                       PickerAlert(                        title: "asdf"                       ) { selection in                           if let selection = selection {                               print("selection: \(selection)")                           }                       }                )            ...        }    }}

This is a screenshot of the output I'm seeing. It doesn't look like the UIPickerView is getting populated with the default values of "red" and "green" that I put. How can I get this to work?

enter image description here


Viewing all articles
Browse latest Browse all 592

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>