Search code examples
iosobjective-cuiviewuiviewcontrollerobjective-c-category

TapGesture added to UIView+SomeCategory. How can I use this UIView that is added to my UIViewController?


I have a customized UIView. I've added a tapGestureRecognizer into this UIView. Not through UIViewController, but within the UIView+Category class. I'm trying to use presentViewController() when this UIView is tapped. This is a UIView class, it doesn't allow presentViewController(). I'm aware that only UIViewController allows this function to be called. So have I mistakenly architectured my project? Is it better if I just add tapGestureRecognizer to this UIView not using category but just straight off from UIViewController? This UIView is going to be used elsewhere as well so it would save me a lot of code if I can make this happen. Thanks in advance.


Solution

  • There is two straight ways to do that 1) Notification(provided example is written in ObjC) 2) Delegation(provided example is written in Swift)

    1) Use NSNotificationCenter to inform the UIViewController that the view belongs to

    In your UIView+Category where the gesture recognized handler is defined there, post notification and in your UIViewController add an Observer

    In UIViewController

    // Define it at the top of your view controller
    #define kViewDidClick @"ViewDidClick"
    
     - (void)viewDidLoad {
         ...
    
         [[NSNotificationCenter defaultCenter]       
                 addObserver: self 
                    selector: @selector(presentVC:) 
                        name: kViewDidClick 
                      object: nil]; 
    }
    
    - (void)presentVC: (NSNotification *)notification {
        [self.presentViewController: vc animated: false completion: nil];
    }
    

    In your UIView+Category where you handle the gesture(for now I assume it's called handleGesture)

    -(void) handleGesture: (UIGestureRecognizer *)gestureRecognizer {
        [[NSNotificationCenter defaultCenter] postNotificationName: kViewDidClick object: nil];
    }
    

    2) you need to define a class that handle gesture and a protocol. This way you can handle all your gesture easily no need to define some methods in your UIView or UIViewController to handle gestures every time you want to handle gestures

    GestureHandlerHelper.swift

    import UIKit
    
    /**
    Handle gesture recognized by a UIView instance
    */
    
    class GestureHandlerHelper {
    var delegate: SelectionDelegate?
    
    // MARK: Initializer
    init(delegate: SelectionDelegate) {
        self.delegate = delegate
    }
    
    // MARK: Gesture Handler
    
    /**
    Handle gesture recognized by a UIView instance
    */
    @objc func handleGesture(gestureRecongnizer: UIGestureRecognizer) {
        println(self)
        println(__FUNCTION__)
        println(gestureRecongnizer)
    
        if .Ended == gestureRecongnizer.state {
            if nil != delegate? {
                delegate?.didClick(gestureRecongnizer)
            }
        }
      }
    }
    

    SelectionDelegate.swift

    /**
     Define a general rule for classes that handle gesture on views
     */
    protocol SelectionDelegate {
        func didClick(gestureRecognizer: UIGestureRecognizer)
    }
    

    In your UIViewController

    class ViewController : UIViewController {
      ... 
      override func loadView() {
            self.view = View(frame: UIScreen.mainScreen().bounds,
              gestureHandlerHelper: GestureHandlerHelper(delegate: self))
      }
      ... 
    }
    
    extension ViewController : SelectionDelegate {
    
        func didClick(gestureRecognizer: UIGestureRecognizer) {
            self.presentViewController(SomeViewController(), animated: false, completion: nil)
         }
    }
    

    In your UIView

    init(frame: CGRect, gestureHandlerHelper: GestureHandlerHelper) {
          ... 
        var tapGestureRecognizer = UITapGestureRecognizer(target: gestureHandlerHelper, action: "handleGesture:")
          ...
    }