简体   繁体   中英

iOS adding tapGesture to multiple Views

I have multiple views defined in my main view. I want to add single tap gesture to all these views. Below is the code I have written, but this registers a tap gesture to the last view that I add. So in the code below, tap is registered only for messagesView & not for other views. I have 2 questions:

  1. How do I register the same tapGesture to multiple Views?

  2. Lets assume I get this working, now all single taps from these views goto the same function called oneTap . In this function how do I distinguish from which view the tap is coming?

Code:

@synthesize feedsView, peopleView, messagesView, photosView;

- (void)viewDidLoad
{
    [super viewDidLoad];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(oneTap:)];
    [singleTap setNumberOfTapsRequired:1];
    [singleTap setNumberOfTouchesRequired:1];
    [feedsView addGestureRecognizer:singleTap];
    [peopleView addGestureRecognizer:singleTap];
    [messagesView addGestureRecognizer:singleTap];
    //[photosView addGestureRecognizer:singleTap];
    [singleTap release];

    return;
}

I had the same problem where it only added to the last view. There might be a better solution, but I just created a tag gesture for each view and linked them to the same selector method ( oneTap: in your case). In order to distinguish which view activated the method, you can just tag your views, feedsView.tag = 0; peopleView.tag = 1; feedsView.tag = 0; peopleView.tag = 1; and so on. Then when the method is called:

- (void)oneTap:(UIGestureRecognizer *)gesture {
    int myViewTag = gesture.view.tag;  // now you know which view called
    // use myViewTag to specify individual actions;
}
  1. Can you attach a UIGestureRecognizer to multiple views? No.

  2. Two options:

    a) Give every UIGestureRecognizer its own action. Pluses of this approach: strong decoupling. Minuses: more code reuse. But, you can mitigate code reuse by creating methods for common functionalities and just call the methods in the different actions.

    b) Give every view to which you add a UIGestureRecognizer a unique tag. Then, use a switch statement in the common action with the sender's view's tag as the case. Pluses: less code reuse. Minuses: tighter coupling. Something like this:

     UIGestureRecognizer *singleTap = [[UIGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction:)]; [feedsView addGestureRecognizer:singleTap]; feedsView.tag = 33;

    Then:

     - (void)singleTapAction:(UIGestureRecognizer *)singleTap { UIView *view = singleTap.view; switch (view.tag) { case 33 // view is feedsView break; default: break; } }

    Although it's usually best to go with the option that decouples, if all of your actions are very similar, which seems to be the case here, and you are quite sure that they'll remain very similar in the future, then option b) with the tags is probably the better choice.

PS It's unnecessary to explicitly set numberOfTapsRequired & numberOfTouchesRequired to 1 since they're both set to 1 by default. You can confirm this by holding Command and clicking on numberOfTapsRequired in Xcode.

Add one tap gesture to multiple views (in this case UILabel), using computed properties. It creates new recognizer for every call.

    var recognizer: UITapGestureRecognizer {
        get {
            return UITapGestureRecognizer(target: self, action: #selector(self.labelTapped(_:)))
        }
    }

    label1.addGestureRecognizer(recognizer)
    label2.addGestureRecognizer(recognizer)
    label3.addGestureRecognizer(recognizer)
    label4.addGestureRecognizer(recognizer)

and labelTapped function

@objc func labelTapped(_ sender: UITapGestureRecognizer) {
    let tappedLabel:UILabel = (sender.view as! UILabel)
}

1 use hitTest:

CGPoint location = [singleTap locationInView:self.view];
id testView = [self.view hitTest:location withEvent:nil];

2 add THE Single TapGesture to multi views, only last view worked.

// Add tap gesture in swift 4

    let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
    view.addGestureRecognizer(tap)
    view.isUserInteractionEnabled = true
    self.view.addSubview(view)

// function which is triggered when handleTap is called
@objc func handleTap(_ sender: UITapGestureRecognizer) {
    if sender.view == view1 {
       // do something
    }
    else{
       // do next thing
    }
}

//USE in view did load: tapGestures(view: view1) tapGestures(view: view2) tapGestures(view: view3)

to attach multiple views to same gesture you can reinitialize the gesture before affecting to your view

here is an example in swift

override func viewDidLoad() {
    super.viewDidLoad()

    var tap = UITapGestureRecognizer(target: self, action: #selector(infoTapped(sender:)))
    tap.numberOfTapsRequired = 1
    info1Btn.addGestureRecognizer(tap)
    info1Btn.tag = 1

    tap = UITapGestureRecognizer(target: self, action: #selector(infoTapped(sender:)))
    info2Btn.addGestureRecognizer(tap)
    info2Btn.tag = 2

    tap = UITapGestureRecognizer(target: self, action: #selector(infoTapped(sender:)))
    info3Btn.addGestureRecognizer(tap)
    info3Btn.tag = 3

}


  @objc func infoTapped(sender: UITapGestureRecognizer){
    let view:UIView = sender.view!
    switch (view.tag) {
    case 1:
        print(view.tag) //  info 1 tapped
    case 2:
        print(view.tag) //  info2 tapped

    case 3:
        print(view.tag) //  info 3 tapped

    default:
        break;
    }
}
for index in 0..3 {
       let view = UIView()
       view.tag = index
       let gestureRecognizer = UITapGestureRecognizer(target: self, action:  #selector(self.viewTapped(_:)))
       view.addGestureRecognizer(gestureRecognizer)
       myViews.append(view)
    }

@objc func viewTapped( _ sender: UITapGestureRecognizer) { 
    guard let tappedView = sender.view as? SelectableFeeIKEABtnView else { return }
    for view in myViews {
        if tappedView.tag == view.tag {
          //Do something
        }
    }
}

In this example there is a loop that creates 4 different views, assigns them the same tap gesture and appends them in an array called myViews . Besides, it is important to set a different tag to each of them, in this case I'm using their position in the array (index) as the tag.

Once you have the differentiated with the tags you can compare in the function @objc func viewTapped( _ sender: UITapGestureRecognizer) if the view tapped is the view you are interested in.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM