1

I am trying to make my code more organised and reusable. I have some functions and notification that allows the scroll view to be moved up when keyboard shows up and scroll down when keyboard hides. It is all functioning. However, I would imaging these function will be used in multiple parts of my project that has scrollView inside UIViewcontroller. so I want to create a more resuable code rather than writing the same codes in multiple view controllers.

Currently, inside one of my view controller, I have

var keyboard = CGRect() 

override func viewDidLoad() {

    //  Check notifications of keyboard activity
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PostVC.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PostVC.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)

    // Tap to hide keyboard
    let hideTap = UITapGestureRecognizer(target: self, action: #selector(PostVC.hideKeyboard))
    hideTap.numberOfTapsRequired = 1
    self.view.userInteractionEnabled = true
    self.view.addGestureRecognizer(hideTap)
}

func hideKeyboard() {
        self.view.endEditing(true)
    }


func keyboardWillShow(notification: NSNotification) {

    keyboard = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey]!.CGRectValue())!

    UIView.animateWithDuration(0.4) {
        self.scrollView.contentSize.height = self.view.frame.size.height + self.keyboard.height / 2 + UITabBarController().tabBar.frame.size.height
    }
}

func keyboardWillHide(notification: NSNotification) {

    UIView.animateWithDuration(0.4) {
        self.scrollView.contentSize.height = 0
    }
}

I am abit new to trying to make code more re-usable. I am not sure if I need to create a new class or just create a extension of UIViewcontroller and put it in there. I have tried creating an extension of UIViewcontroller and do something like

func keyboardWillShow(notification: NSNotification, _scrollView: UIScrollView) { }

and pass an instance of the scrollview (@IBOutlet weak var scrollView: UIScrollView!) into the function. However, I then run into trouble with doing #selector(keyboardWillShow(_:, keyboard: keyboard, scrollView: scrollView). It gives me an error saying expected expression in list of expressions (I think it is complaining about _:). I might be on a totally wrong path of doing this. Can anyone please help.

Thanks,

user172902
  • 3,541
  • 9
  • 32
  • 75
  • 1
    If the code may be reused in many places in the app, it's a good idea to create a base class for all of your view controllers that share code. – William Anderson Jun 28 '16 at 15:31
  • Have you looked into creating [class extensions](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html) on things like `UIScrollView`? – ZGski Jun 28 '16 at 15:32

1 Answers1

2

I would recommend creating a protocol and adding the default implementation as a protocol extension. Into the protocol you can add that classes that implement it should have a scrollView and a keyboard. Have in mind that protocol extensions are more flexible than base classes and that's why are often preferred in Swift.

Here is an example

protocol Scrollable : class {

    var scrollView: UIScrollView { get }
    var keyboardRect: CGRect { get set }
}

extension Scrollable where Self : UIViewController {

    func registerForKeyboardNotifications() {

        NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardWillShowNotification, object: nil, queue: nil, usingBlock: { (notification) in

            self.keyboardWillShow(notification)
        })
        NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardWillHideNotification, object: nil, queue: nil, usingBlock: { (notification) in

            self.keyboardWillHide(notification)
        })
    }

    func deregisterForKeyboardNotification() {

        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    func keyboardWillShow(notification: NSNotification) {

        self.keyboardRect = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey]!.CGRectValue())!

        UIView.animateWithDuration(0.4) {
            self.scrollView.contentSize.height = self.view.frame.size.height + self.keyboardRect.height / 2 + UITabBarController().tabBar.frame.size.height
        }
    }

    func keyboardWillHide(notification: NSNotification) {

        UIView.animateWithDuration(0.4) {
            self.scrollView.contentSize.height = 0
        }
    }
}

Have in mind that I've used addObserverForName instead of addObserver because the later cannot be used with protocol extensions easily. More about that you can read here - Swift make protocol extension a Notification observer

Community
  • 1
  • 1
itskoBits
  • 435
  • 4
  • 13