Создание протокола просмотра прокрутки в Swift 2.2

В настоящее время я разрабатываю приложение для iOS с формами входа и регистрации. Чтобы убедиться, что клавиатура не закрывает UITextFields Я реализовал следующее решение, предоставленное Apple, и обсуждал в этом выпуске.

Чтобы кратко подвести итог, это решение использует UIScrollView в котором размещены различные элементы пользовательского интерфейса и UIKeyboardDidShowNotification а также UIKeyboardDidHideNotification перемещать элементы вверх и вниз, когда клавиатура появляется / исчезает, так что UITextFieldс не спрятаны.

Это работает как шарм, за исключением одного: для всех моих UIViewControllerЯ должен повторить тот же код. Чтобы решить мою проблему, я попытался:

  • создать базу UIViewControllerпредоставляя реализацию для различных функций, которые могут быть подклассами другими UIViewControllers;
  • использовать протокол и расширение протокола, чтобы обеспечить реализацию по умолчанию для различных функций и сделать мой UIViewControllerсоответствуют этому.

Оба решения не решили мою проблему. Для первого решения я не смог подключить UIScrollView моего базового класса через Interface Builder, хотя он был объявлен.

@IBOutlet weak var scrollView: UIScrollView!

При попытке реализовать второе решение, UIViewController Реализация моего протокола как-то не распознала заявленные методы и их реализации.

Декларация протокола:

protocol ScrollViewProtocol {
    var scrollView: UIScrollView! { get set }
    var activeTextField: UITextField? { get set }

    func addTapGestureRecognizer()
    func singleTapGestureCaptured()

    func registerForKeyboardNotifications()
    func deregisterForKeyboardNotifications()

    func keyboardWasShown(notification: NSNotification)
    func keyboardWillBeHidden(notification: NSNotification)

    func setActiveTextField(textField: UITextField)
    func unsetActiveTextField()
}

Расширение протокола реализует все функции, ожидаемые для addTapGestureRecognizer() как я хотел бы избежать использования @objc:

extension ScrollViewProtocol where Self: UIViewController {
    // The implementation for the different functions 
    // as described in the provided links expect for the following method

    func registerFromKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardDidShowNotification, object: nil, queue: nil, usingBlock: { notification in
            self.keyboardWasShown(notification)
        })
        NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardDidHideNotification, object: nil, queue: nil, usingBlock: { notification in
            self.keyboardWillBeHidden(notification)
        })
    }
}

У кого-нибудь есть хорошее решение моей проблемы, зная, как можно избежать повторения кода, связанного с перемещением UITextFields вверх и вниз, когда клавиатура появляется / исчезает? Или кто-нибудь знает, почему мои решения не сработали?

1 ответ

Я нашел решение. Я опубликую это на случай, если кто-то однажды сделает то же самое.

Итак, я закончила удаление UIScrollView выход в моем базовом классе и заменяя его простым свойством, которое я установил в своих наследующих классах. Код для моего базового класса выглядит следующим образом:

import UIKit

class ScrollViewController: UIViewController, UITextFieldDelegate {

    // MARK: Properties

    var scrollView: UIScrollView!
    var activeTextField: UITextField?

    // MARK: View cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        let singleTap = UITapGestureRecognizer(target: self, action: #selector(singleTapGestureCaptured))
        scrollView.addGestureRecognizer(singleTap)
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        registerForKeyboardNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        deregisterFromKeyboardNotifications()
    }

    // MARK: Gesture recognizer

    func singleTapGestureCaptured(sender: AnyObject) {
        view.endEditing(true)
    }

    // MARK: Keyboard management

    func registerForKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWasShown), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillBeHidden), name: UIKeyboardWillHideNotification, object: nil)
    }

    func deregisterFromKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }

    func keyboardWasShown(notification: NSNotification) {
        scrollView.scrollEnabled = true

        let info : NSDictionary = notification.userInfo!
        let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size
        let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)

        scrollView.contentInset = contentInsets
        scrollView.scrollIndicatorInsets = contentInsets

        var aRect : CGRect = self.view.frame
        aRect.size.height -= keyboardSize!.height
        if let activeFieldPresent = activeTextField {
            if (!CGRectContainsPoint(aRect, activeFieldPresent.frame.origin)) {
                scrollView.scrollRectToVisible(activeFieldPresent.frame, animated: true)
            }
        }
    }

    func keyboardWillBeHidden(notification: NSNotification) {
        let info : NSDictionary = notification.userInfo!
        let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size
        let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)

        scrollView.contentInset = contentInsets
        scrollView.scrollIndicatorInsets = contentInsets

        view.endEditing(true)
        scrollView.scrollEnabled = false
    }

    // MARK: Text field management

    func textFieldDidBeginEditing(textField: UITextField) {
        activeTextField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        activeTextField = nil
    }
}

А вот и наследующий код класса:

class ViewController: ScrollViewController {

    @IBOutlet weak var scrollViewOutlet: UIScrollView! {
        didSet {
            self.scrollView = self.scrollViewOutlet
        }
    }

    // Your view controller functions

}

Я надеюсь, это поможет!

Другие вопросы по тегам