UIKeyCommand не отключается при наборе текста в текстовом поле (Swift)
Я сделал приложение для калькулятора (swift) и настроил некоторые UIKeyCommands так, чтобы, если у пользователя есть клавиатура Bluetooth, он мог вводить цифры / символы в калькулятор.
Они работают так:
UIKeyCommand(input: "4", modifierFlags: [], action: "TypeFourInCalculator:")
func TypeFourInCalculator(sender: UIKeyCommand) {
btn4Press(UIButton)
}
Это все работало хорошо, добавив четверку в калькулятор, когда пользователь нажал клавишу "четыре" (хотя сам калькулятор не имеет текстового поля). Однако: у меня также есть пара стандартных текстовых полей, и я хочу, чтобы команды UIKeyCommands останавливались, когда пользователь входит в одно из этих текстовых полей (чтобы они могли регулярно печатать с клавиатуры BT снова). Без отключения UIKeyCommands, ввод результатов в функции калькулятора и нет ввода в текстовое поле.
Я попытался отключить UIKeyCommands, когда текстовое поле становится первым респондентом:
let globalKeyCommands = [UIKeyCommand(input: "4", modifierFlags: [], action: "TypeFourInCalculator:"), UIKeyCommand(input: "5", modifierFlags: [], action: "TypeFiveInCalculator:")]
override var keyCommands: [UIKeyCommand]? {
if powertextfield.isFirstResponder() == false { // if the user isn't typing into that text field
return globalKeyCommands // use key commands
} else { // if the user is typing
return nil // disable those UIKeyCommands
}
Это работает иногда, но часто не работает. Если пользователь еще ничего не печатал на клавиатуре BT (т.е., я полагаю, не активировал клавишные команды), он может печатать на клавиатуре BT как обычно в текстовое поле. Но если они уже набирали числа в калькулятор через UIKeyCommand, они не могут вводить текстовое поле (ну, иногда это работает с нормальным поведением, иногда происходит сбой, как это было до того, как я добавил этот предупредительный код). Напечатанный текст просто не появляется в этом текстовом поле, и вместо этого он просто вызывает команду калькулятора.
Итак, что я могу сделать, чтобы отключить эти UIKeyCommands, когда пользователь начинает вводить в обычном текстовом поле?
1 ответ
Вместо того, чтобы делать keyCommands
вычисленное свойство, вы можете использовать addKeyCommand(_:)
а также removeKeyCommand(_:)
методы для UIViewController
s. Подкласс вашего текстового поля, как это:
class PowerTextField: UITextField {
var enableKeyCommands: (Bool->())?
override func becomeFirstResponder() -> Bool {
super.becomeFirstResponder()
enableKeyCommands?(false)
return true
}
override func resignFirstResponder() -> Bool {
super.resignFirstResponder()
enableKeyCommands?(true)
return true
}
}
Тогда в вашем UIViewController
:
override func viewDidLoad() {
super.viewDidLoad()
// globalKeyCommands is a view controller property
// Add key commands to be on by default
for command in globalKeyCommands {
self.addKeyCommand(command)
}
// Configure text field to callback when
// it should enable key commands
powerTextField.enableKeyCommands = { [weak self] enabled in
guard let commands = self?.globalKeyCommands else {
return
}
if enabled {
for command in globalKeyCommands {
self?.addKeyCommand(command)
}
} else {
for command in globalKeyCommands {
self?.removeKeyCommand(command)
}
}
}
}
Вместо необязательной хранимой процедуры, которая настраивается UIViewController
Вы можете настроить протокол делегата для UITextField
что UIViewController
примет.
Кроме того, если вам нужно остановить эти ключевые команды, когда UIAlertController
всплывает, вы можете сделать подкласс UIAlertController
который реализует viewWillAppear(_:)
а также viewWillDisappear(_:)
методы событий, аналогичные тем, которые вы реализовали becomeFirstResponder()
а также resignFirstResponder()
позвонив enableKeyCommands(_:)
дополнительная хранимая процедура, которая настраивается вашим главным контроллером представления во время его viewDidLoad()
,
Что касается объяснения того, почему это происходит, возможно, наиболее вероятным объяснением является то, что это ошибка. Я не уверен, почему это нерегулярно в вашем тестировании, хотя. Я думаю, вы могли бы попытаться изолировать, при каких условиях это работает или нет. Непонятно, почему это может произойти только для клавиатур Bluetooth, но есть множество крайних случаев, которые могут закрасться, когда вы начнете внедрять беспроводные технологии.
Итак, я столкнулся с той же проблемой и нашел действительно хорошее и простое решение.
Я нашел способ выяснить, является ли текущий firstResponder текстовым полем или аналогичным.
extension UIResponder {
private weak static var _currentFirstResponder: UIResponder? = nil
public static var isFirstResponderTextField: Bool {
var isTextField = false
if let firstResponder = UIResponder.currentFirstResponder {
isTextField = firstResponder.isKind(of: UITextField.self) || firstResponder.isKind(of: UITextView.self) || firstResponder.isKind(of: UISearchBar.self)
}
return isTextField
}
public static var currentFirstResponder: UIResponder? {
UIResponder._currentFirstResponder = nil
UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
return UIResponder._currentFirstResponder
}
@objc internal func findFirstResponder(sender: AnyObject) {
UIResponder._currentFirstResponder = self
}
}
А затем просто использовал это логическое значение, чтобы определить, какие UIKeyCommands возвращать при переопределении keyCommands var:
override var keyCommands: [UIKeyCommand]? {
var commands = [UIKeyCommand]()
if !UIResponder.isFirstResponderTextField {
commands.append(UIKeyCommand(title: "Some title", image: nil, action: #selector(someAction), input: "1", modifierFlags: [], propertyList: nil, alternates: [], discoverabilityTitle: "Some title", attributes: [], state: .on))
}
commands.append(UIKeyCommand(title: "Some other title", image: nil, action: #selector(someOtherAction), input: "2", modifierFlags: [.command], propertyList: nil, alternates: [], discoverabilityTitle: "Some title", attributes: [], state: .on))
return commands
}