Пользовательский вид ввода в Swift
Я потратил часы, пытаясь выяснить, как создать / затем получить кастом inputView
работать. У меня есть сетка TextInputs
(думаю, скрабблборд) что при нажатии должен загружаться кастом inputView
вставить текст.
Я создал файл .xib, содержащий UI elements
для обычая inputView
, Я смог создать CustomInputViewController
и иметь inputView
появляются, но никогда не могут получить фактическое TextInput
обновить его значение / текст.
Документация Apple показала, как заставить это работать, и многие учебники, которые я видел, использовали Obj-C (который я не смог преобразовать из-за мелких вещей, которые сейчас не могут быть выполнены быстро),
Что такое всеобъемлющая архитектура и необходимые фрагменты кода, которые должны быть реализованы для создания customInputView
для нескольких textInputs
(цепочка делегатов, контроллер,.xibs, представления и т. д.)?
2 ответа
Вы не должны проходить через все эти хлопоты. В iOS 8 появился новый класс: UIAlertController
где вы можете добавить TextFields для пользователя для ввода данных. Вы можете оформить его как Alert или ActionSheet.
Пример:
let alertAnswer = UIAlertController(title: "Input your scrabble Answer", message: nil, preferredStyle: .Alert) // or .ActionSheet
Теперь, когда у вас есть контроллер, добавьте в него поля:
alertAnswer.addTextFieldWithConfigurationHandler { (get) -> Void in
getAnswer.placeholder = "Answer"
getAnswer.keyboardType = .Default
getAnswer.clearsOnBeginEditing = true
getAnswer.borderStyle = .RoundedRect
} // add as many fields as you want with custom tweaks
Добавить кнопки действий:
let submitAnswer = UIAlertAction(title: "Submit", style: .Default, handler: nil)
let cancel = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alertAnswer.addAction(submitAnswer)
alertAnswer.addAction(cancel)
Представьте контроллер, когда вы хотите с:
self.presentViewController(alertAnswer, animated: true, completion: nil)
Как видите, у вас есть различные обработчики для передачи пользовательского кода на любом этапе.
Например, вот как это будет выглядеть:
Настройте nib-файл с соответствующим макетом inputView и элементами. В моем случае я установил для каждой кнопки действие с владельцем файла inputViewButtonPressed
,
Настройте раскадровку (или перо, если хотите) для контроллера представления.
Затем, используя следующий код, вы получите то, что ищете:
class ViewController: UIViewController, UITextFieldDelegate {
var myInputView : UIView!
var activeTextField : UITextField?
override func viewDidLoad() {
super.viewDidLoad()
// load input view from nib
if let objects = NSBundle.mainBundle().loadNibNamed("InputView", owner: self, options: nil) {
myInputView = objects[0] as UIView
}
// Set up all the text fields with us as the delegate and
// using our input view
for view in self.view.subviews {
if let textField = view as? UITextField {
textField.inputView = myInputView
textField.delegate = self
}
}
}
func textFieldDidBeginEditing(textField: UITextField) {
activeTextField = textField
}
func textFieldDidEndEditing(textField: UITextField) {
activeTextField = nil
}
@IBAction func inputViewButtonPressed(button:UIButton) {
// Update the text field with the text from the button pressed
activeTextField?.text = button.titleLabel?.text
// Close the text field
activeTextField?.resignFirstResponder()
}
}
В качестве альтернативы, если вы хотите быть более похожим на клавиатуру, вы можете использовать эту функцию в качестве своего действия (она использует новый синтаксис let из Swift 1.2), разбейте ее, если вам нужна совместимость 1.1:
@IBAction func insertButtonText(button:UIButton) {
if let textField = activeTextField, title = button.titleLabel?.text, range = textField.selectedTextRange {
// Update the text field with the text from the button pressed
textField.replaceRange(range, withText: title)
}
}
Это использует UITextInput
протокол для обновления текстового поля по мере необходимости. Обработка удаления немного сложнее, но все же не так уж плохо:
@IBAction func deleteText(button:UIButton) {
if let textField = activeTextField, range = textField.selectedTextRange {
if range.empty {
// If the selection is empty, delete the character behind the cursor
let start = textField.positionFromPosition(range.start, inDirection: .Left, offset: 1)
let deleteRange = textField.textRangeFromPosition(start, toPosition: range.end)
textField.replaceRange(deleteRange, withText: "")
}
else {
// If the selection isn't empty, delete the chars in the selection
textField.replaceRange(range, withText: "")
}
}
}