在swift 2.2中创建滚动视图协议

时间:2016-04-13 13:11:11

标签: uiscrollview uitextfield interface-builder swift-protocols swift2.2

我目前正在使用登录和注册表单开发iOS应用程序。为了确保键盘不会覆盖任何UITextField,我实施了Apple提供的以下解决方案,并在此issue中进行了讨论。

简单总结一下,此解决方案使用UIScrollView放置不同的UI元素,UIKeyboardDidShowNotificationUIKeyboardDidHideNotification在键盘出现时上下移动元素/消失,以便UITextField不被隐藏。

除了一件事之外,这就像魅力一样:对于我所有的UIViewController,我必须重复相同的代码。为了解决我的问题,我尝试过:

  • 创建基础UIViewController,为不同的函数提供实现,可以是其他UIViewController的子类;
  • 使用协议和协议扩展为不同的函数提供默认实现,并使UIViewController符合它。

这两种解决方案都没有解决我的问题。对于第一个解决方案,虽然已经声明,但我无法通过Interface Builder连接我的基类的UIScrollView

@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)
        })
    }
}

有没有人能很好地解决我的问题,知道如何避免在键盘出现/消失时重复上下移动UITextField s相关的代码?或者有谁知道为什么我的解决方案不起作用?

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。我会发布它以防万一有人做同样的事情。

所以,我最终删除了我的基类中的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

}

我希望这会有所帮助!