Программно изменить фокус после ввода текста в UITextfield

У меня есть простое представление, которое имеет два текстовых представления, а также кнопку. Все органы управления расположены вертикально. Я могу переходить от одного элемента управления к другому с помощью пульта дистанционного управления. Тем не менее, я пытаюсь заставить работать следующий сценарий:

  1. Пользователь запускает приложение (фокус находится на первом текстовом поле)
  2. Пользователь вводит текстовое поле и использует полноэкранную клавиатуру, затем нажимает кнопку «Далее».
  3. Приложение показывает второе текстовое поле (полноэкранная клавиатура), вводит текст и нажимает кнопку «Готово».
  4. Приложение покидает полноэкранную клавиатуру и фокусируется на кнопке

В то время как шаг 1-3 работает из коробки, изменение фокуса программно (4) не работает. Вот код:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if(textField == self.textfieldB) {
        self.activeView = self.textfieldB;
        [self setNeedsFocusUpdate];
        [self updateFocusIfNeeded];
        return YES;
    } 
    return NO;
}

и в - (UIView *)preferredFocusedView я возвращаю все, что хранится в self.activeView (да, он вернет экземпляр кнопки). Все методы вызываются, как и ожидалось, однако фокус не меняется. Что я здесь делаю неправильно?

Заранее спасибо!


person Chrizzor    schedule 21.01.2016    source источник


Ответы (4)


Согласно этой ветке форума разработчиков, такое поведение является преднамеренным:

При отклонении представленного контроллера представления, такого как полноэкранная клавиатура, UIKit автоматически вернет фокус обратно туда, где он был, когда этот контроллер представления был впервые представлен, если это представление все еще доступно для фокусировки. Это делается для того, чтобы фокус автоматически возвращался туда, где его ожидает пользователь. В настоящее время нет механизма для переопределения этого поведения.

В похожем случае я переключал фокус с задержкой после возвращения с экрана клавиатуры. Это уродливый хак, я бы хотел, чтобы UIKit не был так самоуверен по этому поводу.

person zoul    schedule 12.04.2016
comment
Я также сталкиваюсь с той же проблемой. Спасибо за ответ - person GAURAV VIG; 19.07.2016

Таким образом, ни одно из предложений, с которыми я столкнулся, действительно не сработало для меня, в том числе для более нового restoresFocusAfterTransition было установлено значение false.

В дополнение к этому, единственное, что сработало, это построение на ответе 6rchid с задержкой, чтобы учесть обновления движка фокуса.

class EmailViewController: UIViewController {

    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var submitButton: UIButton!

    private var focusedEnvironments: [UIFocusEnvironment] = [UIFocusEnvironment]()

    override var preferredFocusEnvironments: [UIFocusEnvironment] {
        return focusedEnvironments
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        restoresFocusAfterTransition = false

        focusedEnvironments = [emailTextField, submitButton]
    }

}

extension EmailViewController: UITextFieldDelegate {

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

        emailTextField.isEnabled = false
        focusedEnvironments = [submitEmailButton]

        submitButton.setNeedsFocusUpdate()

        UIView.transition(with: submitEmailButton, duration: 1.0, options: .transitionCrossDissolve, animations: {
            self.submitButton.isEnabled = true
        }) { (_) in
            // re-enable this once focus updates have completed
            self.emailTextField.isEnabled = true
        }
        return true
    }
}

Если UITextField остается включенным до завершения обновления фокуса, кажется, что фокус всегда хочет сбросить на UITextField. Таким образом, хитрость заключается в том, чтобы отключить его, а затем снова включить, когда захотите.

person PostCodeism    schedule 17.12.2020

Его можно изменить, если для содержащего UIViewController для restoresFocusAfterTransition установлено значение false.

Просто установите restoresFocusAfterTransition = false, а затем переопределите preferenceFocusEnvironments.

person antopenroad    schedule 29.04.2019

Да, вы можете выполнить шаг 4, выполнив следующие действия:

    @IBOutlet weak var loginButton: UIButton!
    var focusedView: UIView?

    override var preferredFocusedView: UIView? {
        return focusedView
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField == passwordTextField {
            focusedView = loginButton
        }
        return true
    }
person 6rchid    schedule 24.04.2020