Mac Catalyst 下是不是支持 UITextField+UIPickerView?

Posted

技术标签:

【中文标题】Mac Catalyst 下是不是支持 UITextField+UIPickerView?【英文标题】:Is UITextField+UIPickerView supported under Mac Catalyst?Mac Catalyst 下是否支持 UITextField+UIPickerView? 【发布时间】:2020-05-23 22:28:50 【问题描述】:

在我的 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]


【问题讨论】:

你有没有得到这个工作? 【参考方案1】:

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

【讨论】:

【参考方案2】:

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

【讨论】:

【参考方案3】:

视图控制器

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()

    


【讨论】:

【参考方案4】:

在 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

【讨论】:

以上是关于Mac Catalyst 下是不是支持 UITextField+UIPickerView?的主要内容,如果未能解决你的问题,请参考以下文章

关于Cisco Catalyst 2960-S Series SI 交换机支持IP和MAC地址绑定功能吗?

如何修复“读写数据沙箱:使用 Mac Catalyst 时出错”

关于Cisco Catalyst 2960-S Series SI 交换机支持IP和MAC地址绑定功能吗?

Mac Catalyst ITMS-4241 错误上传二进制文件

为 Mac Catalyst 构建 Realm 失败:未找到 Realm.h

如何在 Mac Catalyst 中检测窗口大小调整?