阻止编辑 UITextField 但不阻止 Swift 中的用户交互

Prevent editing UITextField but not the user interaction in Swift

我想知道如何阻止用户编辑 UITextField 而不是用户交互。我想在这里做的是当用户点击文本字段时,UIPickerView 从底部弹出,用户可以 select 选择器视图中的项目并将其显示在文本字段上。但我不希望用户能够编辑文本字段。我想为下面的 class 执行此操作。

import UIKit

typealias PickerTextFieldDisplayNameHandler = ((Any) -> String)
typealias PickerTextFieldItemSelectionHandler = ((Int, Any) -> Void)

class PickerTextField: UITextField {

    private let pickerView = UIPickerView(frame: .zero)
    private var lastSelectedRow: Int?
    
    public var pickerData: [Any] = []
    public var displayNameHandler: PickerTextFieldDisplayNameHandler?
    public var itemSelectionHandler: PickerTextFieldItemSelectionHandler?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.configureView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.configureView()
    }
    
    override func caretRect(for position: UITextPosition) -> CGRect {
        return .zero
    }
    
    
    
    private func configureView() {
        self.pickerView.delegate = self
        self.pickerView.dataSource = self
        self.inputView = pickerView
        
        let toolbar = UIToolbar()
        toolbar.barStyle = .default
        toolbar.sizeToFit()
        
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneButtonTapped))
        toolbar.setItems([spaceButton, doneButton], animated: false)
        
        self.inputAccessoryView = toolbar
    }
    
    private func updateText() {
        if self.lastSelectedRow == nil {
            self.lastSelectedRow = 0
        }
        if self.lastSelectedRow! > self.pickerData.count {
            return
        }
        let data = self.pickerData[self.lastSelectedRow!]
        self.text = self.displayNameHandler?(data)
    }
    
    @objc func doneButtonTapped() {
        self.updateText()
        self.resignFirstResponder()
    }
    
}

extension PickerTextField: UIPickerViewDelegate {
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        let data = self.pickerData[row]
        return self.displayNameHandler?(data)
    }
}

extension PickerTextField: UIPickerViewDataSource {
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return self.pickerData.count
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        self.lastSelectedRow = row
        self.updateText()
        let data = self.pickerData[row]
        self.itemSelectionHandler?(row, data)
    }
}

根据我的理解,您想实现以下行为:

  1. 您想在文本字段内的选择器视图中显示用户选择的内容。
  2. 但是您不希望用户在文本字段中插入文本后更改文本。

我会使用 UITextFieldUIPickerView 的委托方法。 UIPickerViewDelegate 中有一个方法可以让您知道用户选择了哪一行:

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    textField.text = "Hello \(row)"
}

在这里,您可以将文本设置为解决 (1) 的文本字段。

您还可以使用 UITextFieldDelegate 中的方法来防止用户在文本字段中输入内容。

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    return false
}

这可以防止用户在文本字段中键入任何内容。这解决了(2)。但是,光标仍会显示,这可能会使用户感到困惑。他可能认为他可以通过闪烁的光标向文本字段中输入内容,但实际上他不能。

当然,您必须像这样将文本字段 inputView 添加到您的自定义选择器视图中:

textField.inputView = myPickerView

我希望这能回答您的问题:)