Информационный портал по безопасности » Программирование » Веб-разработка » Тап жест для скрытия клавиатуры в iOS (Swift 3)

 

Тап жест для скрытия клавиатуры в iOS (Swift 3)

Автор: admin от 26-12-2016, 11:45, посмотрело: 417

В данной статье разберем, как скрывать клавиатуру по нажатию на вьюху от самых основ до реализации в одну строчку или совсем без кода.


Тап жест для скрытия клавиатуры в iOS (Swift 3)


Основы


Достаточно часто встречается следующий кейс: по нажатию на задний фон скрывать клавиатуру.


Базовое решение — имеем ссылку на UITextField, создаем UITapGestureRecognizer с методом, который снимает выделение с текстового поля и выглядит оно так:


В данной статье используется Swift 3, но можно реализовать и на других версиях и на Objective-C

class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture))
        view.addGestureRecognizer(tapGesture)
    }

    func tapGesture() {
        textField.resignFirstResponder()
    }
}

Проблемы данного кода:



  • viewDidLoad грязный и нечитабельный

  • много кода в контроллере

  • не переиспользуемый


Делаем читабельным


Для решения первой проблемы мы можем вынести код создания и добавления жеста в отдельную функцию:


class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        addTapGestureToHideKeyboard()
    }

    func addTapGestureToHideKeyboard() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture))
        view.addGestureRecognizer(tapGesture)
    }

    func tapGesture() {
        textField.resignFirstResponder()
    }
}

Кода стало еще больше, но он стал чище, логичней и приятней глазу.


Уменьшение кода


Для решения второй проблемы у UIView есть метод:


func endEditing(_ force: Bool) -> Bool

Он как раз отвечает за снятие выделения с самой вьюхи или ее subview. Благодаря ему мы можем сильно упростить наш код:


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        addTapGestureToHideKeyboard()
    }

    func addTapGestureToHideKeyboard() {
        let tapGesture = UITapGestureRecognizer(target: view, action: #selector(view.endEditing))
        view.addGestureRecognizer(tapGesture)
    }
}

Если делаете по шагам, то не забудьте удалить textField свойство из IB.
Также поменяйте target с self на view.

Код стал радовать глаз! Но копировать это в каждый контроллер все еще придется.


Решение копирования


Для переиспользуемости вынесем наш метод добавления в extension контроллера:


extension UIViewController {
    func addTapGestureToHideKeyboard() {
        let tapGesture = UITapGestureRecognizer(target: view, action: #selector(view.endEditing))
        view.addGestureRecognizer(tapGesture)
    }
}

И код нашего контроллера будет выглядеть следующим образом:


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        addTapGestureToHideKeyboard()
    }
}

Чисто, одна строчка кода, и она переиспользуема! Идеально!


Несколько вьюх


Решение выше — очень хорошее, но в нем кроется один минус: мы не можем добавить жест на конкретную вьюху.


Для решения данного кейса воспользуемся расширением UIView:


extension UIView {
    func addTapGestureToHideKeyboard() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(endEditing))
        addGestureRecognizer(tapGesture)
    }
}

и соответственно код контроллера будет выглядеть так:


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addTapGestureToHideKeyboard()
    }
}

Тут возникает другая проблема: данное расширение решает проблему только для вьюхи контроллера. Если мы добавить someView на view и на нее повесим жест, то не сработает. Это все из-за того, что метод endEditing работает только для вьюхи, которая содержит активную вьюху или сама таковой является, а нашего текстового поля скорее всего не будет в нем. Решим данную проблему.


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


Получаем view контроллера через расширение UIView:


var topSuperview: UIView? {
    var view = superview
    while view?.superview != nil {
        view = view!.superview
    }
    return view
}

Скажу сразу, изменив селектор на:


#selector(topSuperview?.endEditing)

работать все еще не будет. Нам необходимо добавить метод, который будет вызывать конструкцию выше:


func dismissKeyboard() {
    topSuperview?.endEditing(true)
}

Вот теперь заменяем селектор на:


#selector(dismissKeyboard)

Итак, расширение для UIView будет выглядеть следующим образом:


extension UIView {

    func addTapGestureToHideKeyboard() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
        addGestureRecognizer(tapGesture)
    }

    var topSuperview: UIView? {
        var view = superview
        while view?.superview != nil {
            view = view!.superview
        }
        return view
    }

    func dismissKeyboard() {
        topSuperview?.endEditing(true)
    }
}

Теперь, используя addTapGestureToHideKeyboard() для любой вьюхи мы будем скрывать клавиатуру.


KeyboardHideManager


Тап жест для скрытия клавиатуры в iOS (Swift 3)


Решением выше я пользовался долгое время, но потом стал замечать, что даже одна строка загрязняет функцию установки вьюх. Так же, (редко, но все же бывает) не очень красиво выглядит, когда это единственный метод во viewDidLoad:


override func viewDidLoad() {
    super.viewDidLoad()
    addTapGestureToHideKeyboard()
}

Вместе с пробелом это занимает 5 строк, что сильно сказывается на чистоте контроллера! У меня появилась идея сделать все это без кода, чтобы не было в контроллере и одной лишней строчки. Я создал класс, который можно добавить в IB с помощью Object


Тап жест для скрытия клавиатуры в iOS (Swift 3)


И с помощью @IBOutlet привязать нужные нам вьюхи:


Тап жест для скрытия клавиатуры в iOS (Swift 3)


Реализация данного класса наипростейшая — добавляем жест на каждую вьюху с помощью выше созданных функций:


final public class KeyboardHideManager: NSObject {

    @IBOutlet internal var targets: [UIView]! {
        didSet {
            for target in targets {
                addGesture(to: target)
            }
        }
    }

    internal func addGesture(to target: UIView) {
        let gesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
        target.addGestureRecognizer(gesture)
    }

    @objc internal func dismissKeyboard() {
        targets.first?.topSuperview?.endEditing(true)
    }
}

extension UIView {
    internal var topSuperview: UIView? {
        var view = superview
        while view?.superview != nil {
            view = view!.superview
        }
        return view
    }
}

Чтобы воспользоваться данным классом, нужно три простых действия:



  • 1) Перетащить Object в контроллер


Тап жест для скрытия клавиатуры в iOS (Swift 3)



  • 2) Установить KeyboardHideManager в качестве класса данного объекта


Тап жест для скрытия клавиатуры в iOS (Swift 3)



  • 3) Соединить нужные вьюхи со свойством targets


Тап жест для скрытия клавиатуры в iOS (Swift 3)


Да, больше действий, чем написать одну строку (или несколько строк, если несколько определенных вьюх), за то этой самой строки нету в контроллере.


Кто-то может сказать, что лучше написать строку в коде, так понятнее, и будут правы, с одной стороны. Я за то, чтобы вынести из контроллера, все что можно и тем самым его облегчить.


Данный класс можете подключить через CocoaPods или просто скопировать в проект.


Ссылка на исходный код KeyboardHideManager с полным ReadMe о самой библиотеке и ее подключении.


Итог


Разобрали реализацию популярного кейса, рассмотрели несколько его решений, в одну строку и без кода вообще. Используйте тот способ, который больше нравится.



Источник: Хабрахабр

Категория: Веб-разработка / Game Development / iOS

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
  • bowtiesmilelaughingblushsmileyrelaxedsmirk
    heart_eyeskissing_heartkissing_closed_eyesflushedrelievedsatisfiedgrin
    winkstuck_out_tongue_winking_eyestuck_out_tongue_closed_eyesgrinningkissingstuck_out_tonguesleeping
    worriedfrowninganguishedopen_mouthgrimacingconfusedhushed
    expressionlessunamusedsweat_smilesweatdisappointed_relievedwearypensive
    disappointedconfoundedfearfulcold_sweatperseverecrysob
    joyastonishedscreamtired_faceangryragetriumph
    sleepyyummasksunglassesdizzy_faceimpsmiling_imp
    neutral_faceno_mouthinnocent