UIScrollView with UIPinchGesture - objective-c

I have a UIScrollView with a UIPinchGesture attached to it. My problem is though if I do a pinch gesture it moves the UIScrollView's and can see this when NSLogging the UIScrollView's X/Y. I was wondering if anyone has any ideas to prevent this happening on the scrollview?
I already set the minimum and maximum zoom scale:
[scrollView setMaximumZoomScale: 1.0];
[scrollView setMinimumZoomScale: 1.0];
Also I have subclasses the UIScrollView and implemented the touchesBegan and touchesEnded but I am unsure how I would ignore a touch on the scrollview if 2 fingers are used?
Please advise.

you can wisely use ScrollEnabled property.
Also to cancel touch when two fingers are used,
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
if ([allTouches count] > 1)
{
[self touchesCancelled:touches withEvent:event];
}
else
{
//pass touch.
}
}

Related

Touch not detected - subview

I have been trying to figure this out for some time now. I am using auto layout with a scrollview. Inside the scrollview is a UIView, another UIView and then the subview within that. I can't get touch to work with the subview. I have tried touchesbegan along with uitapgesture with no success. Any suggestions? Here is the layout hierarchy.
ScrollView
---- UIView
------- UIView
------ UIView - Need to detect touch here.
EDIT:
Sorry guys, was at work. Here is some code. I have subclassed my scrollview to receive touches as it seems to be working best so far getting down to the subview level of other view subviews.
The following code detects that the view is that class without the pointInside. I am currently having issues receiving the right point for the view.
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UIView *relatedVidsView = [[[touches allObjects] firstObject] view];
for (int i = 0; i < relatedVidsView.subviews.count; i++) {
UIView *view = [relatedVidsView.subviews objectAtIndex:i];
CGPoint touchPoint = [[[touches allObjects] firstObject] locationInView:self];
if ([view isKindOfClass:[RecipeVideoView class]] && [view pointInside:touchPoint withEvent:nil]) {
NSLog(#"TEST");
}
}
[super touchesBegan:touches withEvent:event]; }
EDIT 2:
So I was able to figure this out. I subclassed the view that was containing the subviews that i needed touch events for. What I did was passed the events from the parent to the subviews using touchesBegan. I will post my code later, thanks for the help anyway.

How to make OpenGL view and overlaying UIView react to the same touch event

I have an OpenGL View with sprites in it which have UIViews with the same position and size on top of the OpenGL view, to make them accessible. The OpenGL View should be able to receive touch events and the UIView on top too. In my UIView class I override the hitTest:withEvent method so the UIViews get the touch input, otherwise only the OpenGL gets the touch:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
NSEnumerator *reverseE = [self.subviews reverseObjectEnumerator];
UIView *iSubView;
while ((iSubView = [reverseE nextObject]))
{
UIView *viewWasHit = [iSubView hitTest:[self convertPoint:point toView:iSubView] withEvent:event];
if (viewWasHit)
{
return viewWasHit;
}
}
return [super hitTest:point withEvent:event];
}
Now my UIViews receive touch-input but the OpenGL elements underneath don't. How can I change that so both of them receive the touch.
In my opinion in such cases it is best if only your main view receives touches in which you then check if any of the subviews was touched using CGRectContainsPoint for instance. If you really want to override the subviews then I suggest you override the touch methods to call the superview touch methods, for instance to override touchesBegin:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.superview touchesBegan:touches withEvent:event];
//do additional stuff
}
This will work with touches but probably not with gestures since they cancel touch events and have a different pipeline.

Forward touch events of UIScrollView to parent view by not blocking the UIScrollView

I have multiple UIViews in a UIViewController and every UIView has UIScrollViews. I have to move UIViews horizontal by touch events. UIScrollViews should scroll only vertical. But UIScrollViews are swallowing touch events and so UIView is not moving. I made a custom UIScrollView class to forward touch events like below, but on that way UIScrollView doesn't scroll.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *result = nil;
for (UIView *child in self.subviews)
if ([child pointInside:point withEvent:event])
if ((result = [child hitTest:point withEvent:event]) != nil)
break;
return result;
}
How can I pass touches from UIScrollView to it's parent view by also making UIScrollView work?
Why don't you put your views with scrollviews to big scrollview with only horisontal scrolling enabled? I tried it once, works for me

Retrieve and change the point at which touchUpInside changes to touchUpOutside

I have made a UISlider work just like the "slide to unlock" slider.
What I need to do is determine the point at which lifting your finger off is classed as touchUpOUTSIDE and not touchUpINSIDE. This is the point where you slide your finger past the end of the slider too far.
I guess it's the same as with a UIButton, you can press the button then slide your finger off the button and depending how far you go, it can still be classed as touchUpInside.
If possible, i'd like to mark the target area with a circle.
Once i've managed to find where this point is, is it possible to change it? So I could have a bigger target area?
I really don't know where to start with this. Thanks
According to the docs, the UIControlEventTouchUpOutside event is triggered when the finger is outside the bounds of the control. If you're trying to change that area, the slider will scale with it. Why not just tie the action for UIControlEventTouchUpOutside to the same as UIControlEventTouchUpInside?
It's taken me a few hours, but i've managed to sort this.
I've done a lot of testing overriding touchesMoved, touchesEnded and sendAction:action:target:event and it seems that any touch within 70px of the frame classes as a touch INSIDE. So for a UISlider that's 292x52 any touch from x:-70 to x:362 or y:-70 to 122 will count as an inside touch, even though it's outside the frame.
I have come up with this code that will override a custom class to allow a bigger area of 100px around the frame to count as an inside touch:
#import "UICustomSlider.h"
#implementation UICustomSlider {
BOOL callTouchInside;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
callTouchInside = NO;
[super touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint touchLocation = [[touches anyObject] locationInView:self];
if (touchLocation.x > -100 && touchLocation.x < self.bounds.size.width +100 && touchLocation.y > -100 && touchLocation.y < self.bounds.size.height +100) callTouchInside = YES;
[super touchesEnded:touches withEvent:event];
}
-(void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
if (action == #selector(sliderTouchOutside)) { // This is the selector used for UIControlEventTouchUpOutside
if (callTouchInside == YES) {
NSLog(#"Overriding an outside touch to be an inside touch");
[self sendAction:#selector(UnLockIt) to:target forEvent:event]; // This is the selector used for UIControlEventTouchUpInside
} else {
[super sendAction:action to:target forEvent:event];
}
} else {
[super sendAction:action to:target forEvent:event];
}
}
With a little bit more tweaking I should be able to use it for the opposite also. (Using a closer touch as an outside touch).

How to make a UIView ignore touches without releasing it?

I have a transparent UIView on top of a UIScrollView. The UIView determines whether the scrollview is allowed to scroll or not by checking three touchesMoved events. After the events, I want the view to disable user interaction so scrolling will happen. The user shouldn't even notice the delay.
However, having set the view's userInteractionEnabled to NO, it keeps claiming all touchesMoved events until it is released. This means that the user is forced to let go of the view before being able to scroll.
Using hitTest won't work until the view has been released as well. hitTest does not get called while moving.
I would send the touch events to the UIScrollView, but it happily ignores those due to it having its own hidden touch handling.
Any way to make the UIView stop claiming touch events without having to let go of it?
Make the UIView hidden. According to the docs:
A hidden view disappears visually from its window and does not receive input events
See the class reference for more: http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/uiview/uiview.html
try cancelling the touches:
How to cancel a sequence of UITouch events?
p.s. if necessary I assume you are propagating the touches to next responder:
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[[self nextResponder] touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
[[self nextResponder] touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
[[self nextResponder] touchesEnded:touches withEvent:event];
}