Why is UIView exclusiveTouch property not blocking? - iphone

I am launching a simple UIView with a textField - let's call it orderSetNameView - upon a button tap. I wish to make this view modal, but without using a
[UIViewController presentModalViewContoller:animated:].
It seems I could simply set textInputView.exclusiveTouch = YES to achieve that.
Apple documentation says about exclusiveTouch:
A Boolean value indicating whether the receiver handles touch events
exclusively. If YES, the receiver blocks other views in the same
window from receiving touch events; otherwise, it does not. The
default value is NO.
I assume "same window" means same UIWindow, of which I have only one.
The problem is that when I instantiate my orderSetNameView, add it as a subview, and set exclusiveTouch = YES, touch events happen in all other views of my app, i.e., touch events in other views are not blocked as expected.
// ....
[self.view addSubview:self.orderSetNameView];
[self.orderSetNameView openWithAnimationForAnimationStyle:kMK_AnimationStyleScaleFromCenter];
}
// Set as modal
self.orderSetNameView.exclusiveTouch = YES;
Shouldn't orderSetNameView block touch events in all other views? What am I missing?

From Apple developer forums:
exclusiveTouch only prevents touches in other views during the time in which there's an active touch in the exclusive touch view. That is, if you put a finger down in an exclusive touch view touches won't start in other views until you lift the first finger. It does not prevent touches from starting in other views if there are currently no touches in the exclusiveTouch view.
To truly make this view the only thing on screen that can receive touches you'd need to either add another view over top of everything else to catch the rest of the touches, or subclass a view somewhere in your hierarchy (or your UIWindow itself) and override hitTest:withEvent: to always return your text view when it's visible, or to return nil for touches not in your text view.

Put this in AppDelegate or another file. Use this single time.
// Multi Touch Disable
UIView.appearance().isExclusiveTouch = true
UIButton.appearance().isExclusiveTouch = true

Related

How to recieve touches began event inside a subview?

I have a view containing two subviews(plain UIviews). The parent view recognizes touch events like touchesbegan ,ended, etc. but the sub view is not recognizing the touch event. How to make it recognize the touch event. Specifically i need only sub view to recognize touch events and not parent view. Thanks in advance.
UserInteractionEnabled is set to YES for the views.
There's two ways of dealing with this.
1) Detect the touches in your viewcontroller instead of in a view. You should be able to work out which view contains the point which was touched and from that can decide what to do with the touch (or just throw it away if it wasn't in either view).
2) Create a subclass of UIView and add these to your main view instead of just UIViews. Then you can detect the touches inside your subclass and deal with them accordingly.
Hope that helps.

Can I cancel touch programmatically?

UIScrollView has a canceling mechanism, where it cancels the touch of subviews when it detects 'scrolling'.
I wonder if I can cancel a touch event (which already has begun) programmatically.
I have a draggable view inside a scroll view.
I can let the draggable view receive touches, but I'm wondering how to stop receiving touch events when I want and give touch events to the scroll view.
Have a look at cancelTrackingWithEvent:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIControl_Class/index.html#//apple_ref/occ/instm/UIControl/cancelTrackingWithEvent%3A
You might want to have a look at the UITapGestureRecogniser class's cancelsTouchesInView method
Well I have had a similar problem.
I have solved it by disabling the scroll view when you receive touch event on its subview.
And when you think your event is complete you re-enable the scroll view.
If you do not do enable-disable the scroll view cancels your drag events automatically!

UIButton touch event falls through to underlying view

I have created a small UIView which contains two UIButtons. The view responds to UITapGesture events. The Buttons are supposed to respond to TouchUpInside, however when I tap the buttons the responder is the underlying view and the tap gesture selector is triggered. Looking for advice or suggestions.
You can modify the method that responds to the tap gesture in the orange view:
-(void) handleTapFrom:(UITapGestureRecognizer*) recognizer {
CGPoint location = [recognizer locationInView:orangeView];
UIView *hitView = [orangeView hitTest:location withEvent:nil];
if ([hitView isKindOfClass:[UIButton class]]) {
return;
}
//code that handle orange view tap
...
}
This way if you touch a UIButton, the tap will be ignored by the underlying view.
The right answer (which prevents the tabrecognizer from highjacking any taps and doesn't need you to implement a delegate etc) is found here. I got a lead to this answer via this post.
In short use:
tapRecognizer.cancelsTouchesInView = NO;
"Which prevents the tap recognizer to be the only one to catch all the
taps"
Each UIView has an 'exclusiveTouch' property. If it's set to YES the view won't pass the touch down the responder chain. Try setting this property on your UIButtons and see if that makes a difference.
How are the views ordered in the view hierarchy? Also, are you creating the interface in IB? If you hook up the connections properly, this shouldn't be an issue at all...
The problem with this design is that it's similar to embedding one button into another. While you may have a valid reason to do it, you should be more careful with the event flow.
What happens is the gesture recognizer intercepting touches before they reach subviews (the two buttons in your case). You should implement UIGestureRecognizerDelegate protocol, namely, gestureRecognizer:shouldReceiveTouch: method, and return NO if the touch is inside any of the two buttons. That will prevent the orange view from usurping touches intended for the buttons and the buttons will start to work as expected.
Check out this question.
uibutton-inside-a-view-that-has-a-uitapgesturerecognizer

How to disable multitouch when having several views?

I created my own custom view that extends UIControl. This custom view has its own touch implementation. I implemented touchesBegan, Moved, Ended, and Canceled methods in it.
In the main view controller, I created several instances of this view. So in the screen, there are a number of custom buttons.
I want to disable multitouch in my app. If I click one custom button, then other buttons shouldn't respond.
Actually, it was easy to implement this. While I held some buttons, I could just make other buttons' userInteractionEnabled property to NO until I ended touch.
But the problem is that when I tap these several buttons at the same time, two or more touchesBegan methods work simultaneously, and message passing is messed up.
I tried to set multiTouchEnabled = NO and exclusiveTouch = YES, but it still didn't work.
How can I force to disable multitouch in my app?
Thank you.
You need to set exclusiveTouch to YES, not NO (which is the default anyways). The name of the property refers to the view being the exclusive recipient of any touch events for the duration.

Propagating touches from UIApplication in a custom manner

Is it possible to propagate touches from shared application object to a custom view which has not actually received touches and somewhere at the back of the top view? Assume that I can't use my top view to track touches.
It would be difficult - because the top view receives the event first.
You can't just call userInterActionEnabled on the top view, and pass the event down to a lower layer?
Why can you not use the top view to track touches?
If the top view is a subclass then you can use the touchesBegan: method. To pass this onto another subclass you could just use NSNotificationCenter, passing the set of touches as the object. If you're unfamiliar with this you can check out my explanation on this post:
Hittest event problem