Mac Catalyst 支持 UITextField+UIPickerView 吗?

Is UITextField+UIPickerView supported under Mac Catalyst?

在我的 iOS 应用程序中,我有一个文本字段,其中分配了一个选择器视图,它是 inputView。在 iOS 设备上,只要用户点击文本字段,选择器视图就会弹出。但是,当我 运行 它作为 Mac/Catalyst 应用程序时,相同的代码不会这样做。到目前为止,我的调试工作表明根本没有调用选择器视图方法,所以如果 Mac 需要额外的文本字段委托方法来将焦点从 Mac 的键盘上移开?知道如何在 Mac 上进行这项工作吗?下面是准系统示例代码。

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
@IBOutlet weak var myTextField: UITextField!

var myPickerView : UIPickerView!
var pickerData = ["Alpha" , "Bravo" , "Charlie" , "Delta"]

override func viewDidLoad() {
    super.viewDidLoad()

    self.myPickerView = UIPickerView(frame:CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 300))
    self.myPickerView.delegate = self
    self.myPickerView.dataSource = self

    self.myTextField.delegate = self
    self.myTextField.inputView = self.myPickerView

}

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return pickerData.count
 }
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return pickerData[row]
}
}

这看起来像是 Mac Catalyst 中的错误。尝试使用嵌入在 UIActionSheet 中的 UIPickerActionSheetPicker-3.0 是现成的解决方案。在 UITextFieldtextFieldDidBeginEditing 中显示 ActionSheetPicker

这有点坑爹,但还是让我分享一下吧。如果你监听 NSNotification UIKeyboardWillChangeFrameNotification 这将在 -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField 之前触发 所以你可以设置一个 BOOL 来查看这个方法是否触发。如果没有,您可以告诉您没有软件键盘,然后可以显示警报控制器或上下文菜单,或者您希望以不同方式处理它。

ViewController

class ViewController : UIViewController {

    // MARK: - Properties -
        
    var tableView : UITableView?

    var currentTextfield : UITextField?

    var gendersArray : Array<String> = ["Male", "Female"]

    var pickerView : UIPickerView?

    // MARK: - Lifecycle -

    override func viewDidLoad() {
    
        super.viewDidLoad()

        // get the size of the iOS device
    
        let screenRect : CGRect = UIScreen.main.bounds
        let screenWidth : CGFloat = screenRect.size.width
        let screenHeight : CGFloat = screenRect.size.height

        // add the picker view
    
        var pickerViewFrame = CGRect(x: 0.0,
                                 y: screenHeight - 162.0,
                                 width: screenWidth,
                                 height: 162.0)
    
        // set pickerview frame for macOS Catalyst

        #if targetEnvironment(macCatalyst)

        pickerViewFrame = CGRect(x: 0, y: 0, width: 269, height: 240)

        #endif

        pickerView = UIPickerView.init(frame: pickerViewFrame)
    
        pickerView?.delegate = self
        pickerView?.dataSource = self

        // ... set tableview

    }

}

UIAlertController 函数

// MARK: - UIAlertController -

@objc func textfieldInputAction(pickerView: UIPickerView, textfield: UITextField?) {

    print("textfieldInputAction")
    
    // alertController
    
    let alertController = UIAlertController(title: "Title of Action Sheet", message: "", preferredStyle: UIAlertController.Style.actionSheet)

    // reload components
            
    pickerView.reloadAllComponents()

    // add the picker to the alert controller

    alertController.view.addSubview(pickerView)

    // set height of Action sheet
    
    let height : NSLayoutConstraint = NSLayoutConstraint(item: alertController.view!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 350)

    alertController.view.addConstraint(height)

    // okAction
    
    let okAction = UIAlertAction(title: "Done", style: .default, handler: {
        (alert: UIAlertAction!) -> Void in

        // end editing
        
        DispatchQueue.main.async {

            textfield?.resignFirstResponder()
            
            DispatchQueue.main.async {
                UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
            }

        }

    })
    
    alertController.addAction(okAction)
    
    // popoverController
    
    if let popoverController = alertController.popoverPresentationController {

        popoverController.sourceView = textfield //to set the source of your alert
        
        popoverController.sourceRect = textfield?.bounds ?? CGRect(x: 0, y: 0, width: 0, height: 0 )
        popoverController.permittedArrowDirections = [.down, .up]
                    
    }

    // present alertController
            
    self.present(alertController, animated: true, completion: nil)

}

表格视图

// MARK: - Tableview -

extension ViewController : UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell : TextFieldCell = tableView.dequeueReusableCell(withIdentifier: "TextFieldCell", for: indexPath) as! TextFieldCell
        
        // textfield
        
        cell.textField?.delegate = self
        
        cell.textField?.inputView = pickerView
                    
        return cell
        
    }
}

UITextField 委托

// MARK: - UITextField -

extension ViewController : UITextFieldDelegate {
    
    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {

        print("textFieldShouldBeginEditing")
        
        #if targetEnvironment(macCatalyst)

        if textField.inputView == self.pickerView {

            self.currentTextfield = textField
            self.textfieldInputAction(pickerView: self.pickerView!, textfield: self.currentTextfield!)

            return false
            
        }
        
        #endif
        
        return true
        
    }
}

UIPickerView 委托

// MARK: - PickerView Delegates -

extension ViewController : UIPickerViewDelegate, UIPickerViewDataSource {
    
    // components
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        
        return 1
        
    }
    
    // rows
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        
        print("numberOfRowsInComponent")
                
        return gendersArray.count
        
    }
    
    // title
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
                
        return gendersArray[row]
        
    }
    
    // select row
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        
        print("pickerView: didSelectRow: \(row)")
        
        currentTextfield?.text = gendersArray[row]

        self.tableView?.reloadData()

    }

}

在 UIPickerViewMioPicker.swift

class UIPickerViewMio : NSObject, UIPickerViewDataSource, UIPickerViewDelegate {

private var uiTextField : UITextField?
private var oggetto = ["Uno", "Due", "Tre", "Quattro", "Cinque"]    

required init(uiTextField : UITextField?) {
    self.uiTextField = uiTextField
}

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return 5
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
    {
    if let textField = self.uiTextField {
        textField.text = self.oggetto[row]
        textField.tag = row
    }
}
... omissis ...}

在 UIViewController 上

@IBOutlet var textMioText : UITextField?
var uiPickerViewMioPicker : UIPickerViewMioPicker?

override func viewDidLoad() {
    ... omissis ...
    self.uiPickerViewMio = UIPickerViewMioPicker(uiTextField: self.textMioText)
    let pickerM = UIPickerView()
    pickerM.delegate = self.uiPickerViewMioPicker
    pickerM.dataSource = self.uiPickerViewMioPicker
    self.textMioText?.inputView = pickerM
    ... omissis ...
 }

 func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {

    if textField == self.textMio {
        let picker = textField.inputView as! UIPickerView
        picker.isHidden = false
        if UIDevice.current.systemName == "Mac OS X" {
            let alertPicker = UIAlertController(title: "", message: "", preferredStyle: UIAlertController.Style.actionSheet)
            alertPicker.view.addSubview(picker)
            alertPicker.view.addConstraint(NSLayoutConstraint(item: alertPicker.view!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: picker.bounds.height * 1.1))
            alertPicker.view.addConstraint(NSLayoutConstraint(item: alertPicker.view!, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: picker.bounds.width * 1.1))
            if let popoverController = alertPicker.popoverPresentationController {
                popoverController.sourceView = textField
                popoverController.sourceRect = textField.bounds
                popoverController.permittedArrowDirections = [.down, .up]
            }
            self.present(alertPicker, animated: true, completion: nil)
            return false
        }
    }

    return true}