0

I have two adjacent UIScrollViews, both partially covered by a UIButton with a tap gesture recognizer. They are added to the view in this order:

  1. Scrollview #1
  2. Button
  3. Scrollview #2 (added by user interaction)

Both scrollviews are z-positioned "behind" the button, but the button does not receive taps where it overlaps with the newer scrollview.

Is there a way I can declare "keep this button the topmost receiver of taps"?

EDIT: Below is a mockup of the views. The red part of the button is the area that ceases to receive taps after scrollview 2 is added.

mockup of all views

Naftali Beder
  • 1,066
  • 1
  • 10
  • 27
  • I don't understand where the tap gesture recognizer comes into this - could you please elaborate? Why is this required? – John Rogers Apr 27 '15 at 04:15
  • Did you explicitly set the z position to behind the button or did you just assume so because you can see the button above everything else? – Schemetrical Apr 27 '15 at 04:43
  • @JohnRogers Adding a target selector didn't give me the functionality I needed, so I added a gesture recognizer instead - I need to receive both taps and drags on the button. – Naftali Beder Apr 27 '15 at 13:58
  • @Schemetrical Yes, the scrollviews both have z-positions of 20, and the button has a z-position of 40. – Naftali Beder Apr 27 '15 at 13:59
  • @JohnRogers Also, I tried replacing the gesture recognizer with a simple target selector, and it had the same problem of not getting triggered. – Naftali Beder Apr 27 '15 at 14:04

2 Answers2

1

I would suggest that the button is not being placed above the right scroll view properly. I know you've set the zPosition, however you should try bringing the button to the front (and sending the two scroll views to the back) using:

[self.view bringSubviewToFront:button]; [self.view sendSubviewToBack:scrollView1]; [self.view sendSubviewToBack:scrollView2];

If the button is at the top of the view ordering, it should be receiving the touch events first and foremost.

Failing this, it could be an issue with the UIScrollView's gesture recogniser's conflicting with the UIButton's gesture recogniser. Try implementing the following to ensure that both the UIButton and UIScrollView behind it are receiving touch events from their gesture recognisers:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; }

The default return value of the above UIGestureRecognizerDelegate method is NO, which could explain why the button isn't receiving the touch events. You can check out more information on this method and other delegate methods here.

This should ensure that all gesture recognisers are recognising touches within their views.

Hope this helps!

John Rogers
  • 2,192
  • 19
  • 29
  • Thank you for the help! I tried the `bringSubviewToFront` etc. methods, and unfortunately they didn't work. As for overriding the gestureRecognizer method, I wasn't able to - the only method that `UIGestureRecognizerDelegate` gives me access to is `gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool`. However, I tried removing the button and instantly re-adding it when the second scrollview is added. It's an ugly hack, but it works! – Naftali Beder Apr 28 '15 at 00:06
  • 1
    Really? You should be able to implement that method if you are able to implement `gestureRecognizerShouldBegin`. The Swift declaration is `gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool` – John Rogers Apr 28 '15 at 00:07
  • Scratch that - I misunderstood how to access it. I was able to implement it and return true, but it doesn't solve the problem. – Naftali Beder Apr 28 '15 at 00:09
  • 1
    That is very strange. Without being able to debug your program myself, it's very hard to say. Adding the button after the second UIScrollView is added will mean it's brought to the front (which is what bringSubviewToFront: should do...). – John Rogers Apr 28 '15 at 00:10
  • Oh goodness. `sendSubviewToBack` worked - I was trying to send it to back just before creating it, so it had no effect. That's the answer, and it works now without my hack. Thanks for your patience and help! – Naftali Beder Apr 28 '15 at 00:16
  • 1
    You're very welcome. Don't forget to accept the answer if it's helped you out. Good luck and have fun with your app! – John Rogers Apr 28 '15 at 00:16
0

I will give you a solution without writing a lot of code.

I believe your view hierarchy is like this: (z-index ordered)

superview
    scrollview1
    scrollview2
    button

where your button, although is above the scrolls, share the same superview with the scrollviews ... instead of doing this, how about separate the button and the scrollviews on a different container?

superview
    scroll_container
        scrollview1
        scrollview2
    button

And, why are you attaching a gesture recognizer to UIButton if it has it already? You just need to add your selector to the button using:

[button addTarget:yourObject action:@selector(yourMethod:) forControlEvents:UIControlEventTouchUpInside];

Maybe it's the problem with your button, not the z-index ...

Try both and let us know the results.

FormigaNinja
  • 1,571
  • 1
  • 24
  • 36
  • I have a gesture recognizer on the button because it's receiving both taps and drag gestures, and simply adding a target action didn't give me the functionality I needed. As for the hierarchy, it is indeed the first one you described, but it still doesn't make sense that scrollview1 would work but not scrollview2. I don't see how adding them to an intermediate view would change anything. – Naftali Beder Apr 27 '15 at 13:49