Переключение между текстовыми полями при нажатии клавиши возврата в Swift
Я разрабатываю приложение для iOS и хочу, чтобы при нажатии клавиши возврата в моем iPhone он направлял меня в следующее текстовое поле.
Я нашел пару похожих вопросов, с отличными ответами, но все они просто в Objective-C, и я ищу код Swift, теперь это то, что у меня есть до сих пор:
func textFieldShouldReturn(emaillabel: UITextField) -> Bool{
return true
}
Он помещен в файл, который подключен и контролирует к UIView, который содержит текстовые поля, но я не уверен, что это правильное место.
Я в основном новичок в Swift, поэтому объясните каждый маленький шаг, или мне удастся как-то испортить его. Также я использую последнюю версию XCode, если это имеет какое-либо значение.
Итак, я попробовал это и получил эту ошибку:
//could not find an overload for '!=' that accepts the supplied arguments
func textFieldShouldReturn(textField: UITextField) -> Bool {
let nextTag: NSInteger = textField.tag + 1
// Try to find next responder
let nextResponder: UIResponder = textField.superview!.viewWithTag(nextTag)!
if (nextResponder != nil) {
// could not find an overload for '!=' that accepts the supplied arguments
// Found next responder, so set it.
nextResponder.becomeFirstResponder()
} else {
// Not found, so remove keyboard.
textField.resignFirstResponder()
}
return false // We do not want UITextField to insert line-breaks.
}
Заранее спасибо, друзья!
Ответы
Ответ 1
Убедитесь, что ваши делегаты UITextField
установлены и теги правильно увеличены. Это также можно сделать через Интерфейсный Разработчик.
Вот ссылка на сообщение об Obj-C, которое я нашел: Как перемещаться по текстовым полям (кнопки "Далее"/"Готово")
class ViewController: UIViewController,UITextFieldDelegate {
// Link each UITextField (Not necessary if delegate and tag are set in Interface Builder)
@IBOutlet weak var someTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do the next two lines for each UITextField here or in the Interface Builder
someTextField.delegate = self
someTextField.tag = 0 //Increment accordingly
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Try to find next responder
if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
// Not found, so remove keyboard.
textField.resignFirstResponder()
}
// Do not add a line break
return false
}
}
Ответ 2
Swift 5
Вы можете легко переключиться на другое TextField, нажав клавишу возврата на клавиатуре.
- Во-первых, ваш контроллер представления соответствует
UITextFieldDelegate
и добавляет делегированный метод textFieldShouldReturn(_:)
в ViewController. - Перетащите из TextField в ViewController в Интерфейсном Разработчике. Затем выберите опцию
delegate
. Примечание: сделать это для всех TextField -
Создать IBOutlet
для всех TextFields
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var txtFieldName: UITextField!
@IBOutlet weak var txtFieldEmail: UITextField!
@IBOutlet weak var txtFieldPassword: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == txtFieldName {
textField.resignFirstResponder()
txtFieldEmail.becomeFirstResponder()
} else if textField == txtFieldEmail {
textField.resignFirstResponder()
txtFieldPassword.becomeFirstResponder()
} else if textField == txtFieldPassword {
textField.resignFirstResponder()
}
return true
}
}
Ответ 3
Я предлагаю вам использовать оператор switch в textFieldShouldReturn(_:)
.
// MARK: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
switch textField {
case nameTextField:
phoneTextField.becomeFirstResponder()
case phoneTextField:
emailTextField.becomeFirstResponder()
case emailTextField:
descriptionTextField.becomeFirstResponder()
default:
textField.resignFirstResponder()
}
return false
}
Ответ 4
Этот подход нуждается в некоторых изменениях в представлениях таблиц и представлениях коллекции, но это нормально для простых форм, я думаю.
Подключите textFields
к одному IBOutletCollection
, отсортируйте его по координате y и в textFieldShouldReturn(_:)
просто перейдите к следующему текстовому полю, пока не достигнете конца:
@IBOutlet var textFields: [UITextField]!
...
textFields.sortInPlace { $0.frame.origin.y < $1.frame.origin.y }
...
func textFieldShouldReturn(textField: UITextField) -> Bool {
if let currentIndex = textFields.indexOf(textField) where currentIndex < textFields.count-1 {
textFields[currentIndex+1].becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return true
}
Или просто посмотрите образец проекта (xcode 7 beta 4)
Ответ 5
Я пробовал много кодов, и, наконец, это сработало для меня в Swift 3.0 Latest [March 2017]
Класс "ViewController" должен унаследовать "UITextFieldDelegate" для создания этого кода.
class ViewController: UIViewController,UITextFieldDelegate
Добавьте текстовое поле с соответствующим нумером тега, и этот номер тега используется, чтобы взять элемент управления в соответствующее текстовое поле на основе присвоенного ему номера добавочного тега.
override func viewDidLoad() {
userNameTextField.delegate = self
userNameTextField.tag = 0
userNameTextField.returnKeyType = UIReturnKeyType.next
passwordTextField.delegate = self
passwordTextField.tag = 1
passwordTextField.returnKeyType = UIReturnKeyType.go
}
В вышеприведенном коде "returnKeyType = UIReturnKeyType.next", где будет отображаться клавиша возврата клавиши Key, как "Next", у вас также есть другие опции, такие как "Join/Go" и т.д., на основе вашего приложения изменяют значения.
Этот "textFieldShouldReturn" - это метод управления UITextFieldDelegate, и здесь мы имеем следующий выбор полей, основанный на добавлении значения тега
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
return true;
}
return false
}
Ответ 6
Самый простой способ перейти к следующему текстовому полю - это отсутствие необходимости в длинном коде
override func viewDidLoad() {
super.viewDidLoad()
emailTextField.delegate = self
passwordTextField.delegate = self
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == emailTextField {
passwordTextField.becomeFirstResponder()
}else {
passwordTextField.resignFirstResponder()
}
return true
}
Ответ 7
Версия Калеба в Swift 4.0
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextField = self.view.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return false
}
PS textField.superview?
не работает для меня
Ответ 8
Просто используйте метод becomeFirstResponder()
класса UIResponder в вашем методе textFieldShouldReturn
. Каждый объект UIView
представляет собой подклассы UIResponder
.
if self.emaillabel.isEqual(self.anotherTextField)
{
self.anotherTextField.becomeFirstResponder()
}
Дополнительную информацию о методе becomeFirstResponder()
в Apple Doc можно найти в здесь.
Ответ 9
Swift 4.2
Это более общее и простое решение, вы можете использовать этот код с любым количеством TextFields. Просто наследуйте UITextFieldDelegate и обновите тег Textfield в соответствии с порядком и скопируйте эту функцию
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let txtTag:Int = textField.tag
if let textFieldNxt = self.view.viewWithTag(txtTag+1) as? UITextField {
textFieldNxt.becomeFirstResponder()
}else{
textField.resignFirstResponder()
}
return true
}
Ответ 10
Свифт/Программно
class MyViewController: UIViewController, UITextFieldDelegate {
let textFieldA = UITextField()
let textFieldB = UITextField()
let textFieldC = UITextField()
let textFieldD = UITextField()
var textFields: [UITextField] {
return [textFieldA, textFieldB, textFieldC, textFieldD]
}
override func viewDidLoad() {
// layout textfields somewhere
// then set delegate
textFields.forEach { $0.delegate = self }
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let selectedTextFieldIndex = textFields.firstIndex(of: textField), selectedTextFieldIndex < textFields.count - 1 {
textFields[selectedTextFieldIndex + 1].becomeFirstResponder()
} else {
view.endEditing(true) // last textfield, dismiss keyboard directly
}
return true
}
}
Ответ 11
Альтернативный метод для пуристов, которым не нравится использовать теги, и хочет, чтобы делегат UITextField был ячейкой, чтобы компоненты были разделены или однонаправленны...
-
Создайте новый протокол, чтобы связать Cell и TableViewController.
protocol CellResponder {
func setNextResponder(_ fromCell: UITableViewCell)
}
-
Добавьте протокол в свою ячейку, где ваш делегат TextField также является ячейкой (я делаю это в раскадровке).
class MyTableViewCell: UITableViewCell, UITextFieldDelegate {
var responder: CellResponder?
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
responder?.setNextResponder(self)
return true
}
}
-
Сделайте свой TableViewController совместимым с протоколом CellResponder (т.е. class MyTableViewController: UITableViewController, CellResponder
) и реализуйте метод по своему усмотрению. То есть если у вас разные типы ячеек, вы могли бы это сделать, также вы могли бы пройти в IndexPath, использовать тег и т.д. Не забудьте установить cell.responder = self
в cellForRow..
func setNextResponder(_ fromCell: UITableViewCell) {
if fromCell is MyTableViewCell, let nextCell = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? MySecondTableViewCell {
nextCell.aTextField?.becomeFirstResponder()
} ....
}
Ответ 12
Ничего особенного, вот мой в настоящее время используется для изменения textFiled. Таким образом, код в ViewController выглядит хорошо :). # Swift4
final class SomeTextFiled: UITextField {
public var actionKeyboardReturn: (() -> ())?
override init(frame: CGRect) {
super.init(frame: frame)
super.delegate = self
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.resignFirstResponder()
actionKeyboardReturn?()
return true
}
}
extension SomeTextFiled: UITextFieldDelegate {}
class MyViewController : UIViewController {
var tfName: SomeTextFiled!
var tfEmail: SomeTextFiled!
var tfPassword: SomeTextFiled!
override func viewDidLoad() {
super.viewDidLoad()
tfName = SomeTextFiled(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
tfName.actionKeyboardReturn = { [weak self] in
self?.tfEmail.becomeFirstResponder()
}
tfEmail = SomeTextFiled(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
tfEmail.actionKeyboardReturn = { [weak self] in
self?.tfPassword.becomeFirstResponder()
}
tfPassword = SomeTextFiled(frame: CGRect(x: 200, y: 0, width: 100, height: 100))
tfPassword.actionKeyboardReturn = {
/// Do some further code
}
}
}
Ответ 13
Если у вас много компонентов текстового поля, может быть лучше использовать коллекцию розеток, связать текстовые поля и установить Return Key от конструктора интерфейса
@IBOutlet var formTextFields: [UITextField]!
override func viewDidLoad() {
for textField in formTextFields {
textField.delegate = self
}
}
extension RegisterViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let componentIndex = formTextFields.firstIndex(of: textField) {
if textField.returnKeyType == .next,
componentIndex < (formTextFields.count - 1) {
formTextFields[componentIndex + 1].becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
}
return true
}
}
Ответ 14
У меня есть хорошее решение для вашего вопроса.
ШАГ:
1 - Установите ключ возврата из раскадровки.
![enter image description here]()
2 - В вашем быстром файле.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField.returnKeyType == .next {
Email.resignFirstResponder()
Password.becomeFirstResponder()
} else if textField.returnKeyType == .go {
Password.resignFirstResponder()
self.Login_Action()
}
return true
}
3 - Не забудьте установить делегат текстового поля.
Спасибо :)