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
中的 UIPicker
。 ActionSheetPicker-3.0 是现成的解决方案。在 UITextField
的 textFieldDidBeginEditing
中显示 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}
在我的 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
中的 UIPicker
。 ActionSheetPicker-3.0 是现成的解决方案。在 UITextField
的 textFieldDidBeginEditing
中显示 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}