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!
Related
I have some UIButtons within a UIScrollView, but I do not want to delay the button touches. However, as soon as the scroll view detects a drag/scroll, I want to cancel the UIButton touch and proceed with the scrolling of the UIScrollView.
I have included the following...
_scrollView.delaysContentTouches = NO;
...but (obviously) the button touch does not cancel when dragged. Does anyone have any suggestions as to how I can implement this functionality?
You can override this method of UIScrollView.
-(BOOL)touchesShouldCancelInContentView:(UIView *)view
{
return YES;
}
And in your UIButton, you should add different method for different control events.
show highlight effect for UIControlEventTouchDown.
trigger button for UIControlEventTouchUpInside | UIControlEventTouchUpOutside;
clear highlight effect for UIControlEventTouchCancel.
You could use scrollViewWillBeginDragging to fire off a notification and handle the button canceling by listening for it in your buttons' code. I think this is what you are trying to do, but I'm not sure if I have understood your question correctly.
In my program I have placed a UIButton as a subview of a UIView, both of which have userInteractionEnabled set to true. When the button is tapped, an event is called to handle the button tap, which works as expected. However, the button's UIView superview also handles an event which should not be triggered in this case. Can anybody explain why the UIButton AND UIView are both triggering an event? Any help is appreciated.
Should you resign first responder after the button has done its duty so that the view that the button is in is no longer in control.
How about adding: bringSubviewtoFront:scrollview
to the end of your UIButton code. The idea here is to make your uiview the foremost view; which is what I think is happening when you touch the uiview and thus reactivating the triggering events
I have found a solution: I simply made the button a superview of the view which was handling unwanted events, rather than a subview.
I have a view (parent) and a subview (child). The child is a UIControl, responding to UIControlEventTouchDownInside, the parent has a swipe recogniser. I would like to catch swipes even if they start in the child.
Question: how can I recognise the swipe before the tap? Is there any way to tell iphone that gestures in the parent come before gestures in the child?
Thanks for your help!
Edit
I just changed the child to be a UIControl (instead of using a tap recogniser). I'm not sure this matters much to the answer to this question but I thought I'd mention it anyway.
Edit 2
In response to the two answers I have added the tap recogniser to the child again and tried to delay (and fail) the tap recognition so that I can swipe across the big view (parent) containing the child. No luck so far.
Edit 3
I would really like to keep the child a UIControl and use UITouchDownInside rather than a tap recogniser because I want to use the down event rather than the up event.
Edit 4
Now the swipe gets detected but in the child, none of the following gets detected:
UIControlEventTouchDragOutside, UIControlEventTouchDragExit , UIControlEventTouchCancel
and I need at least one of these to detect when the user doesn't actually mean to tap on the child : /
Check the - (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer in UIGestureRecognizer. To tap, the swipe gesture has to fail.
You can use the [swipeGesture delaysTouchesBegan] message to delay the touch events being delivered to the child control.
I want something similar to how the iPhone homescreen works. I have my scrollview inside my main view, which scrolls to the right, but when you touch on the UIButtons, they become highlighted and dragging means they don't end up getting pressed but also the scrollview doesn't end up scrolling. It doesn't do this on the homescreen. How can i make it similar to this?
A touch-down-drag is a completely different event. Apple doesn't support this directly—you'd have to code it in—start tracking the touches using the gesture responders as soon as a touch-down-inside is detected, then scroll the same amount, and stop scrolling at a touch-up-outside (or inside). This would most likely fall under the category of unusual use of interface elements, and could very well get you rejected.
I think this is a better answer to the question:
UIScrollview with UIButtons - how to recreate springboard?
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