Detect touch position on UiScrollView - ios

I need to get the touch position from a UIScrollView. But when I create a subclass for my scrollview :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSArray *touchesArray = [touches allObjects];
UITouch *touch = (UITouch *)[touchesArray objectAtIndex:0];
CGPoint point = [touch locationInView:self];
self.position = point;}
The function touchesBegan isn't always called.
If I swipe fast, touchesBegan is never called, but scrollViewDidScroll gets directly called instead.
I can't use UIGesture (UITapGestureRecognizer, ... ) because users don't tap or swipe.
Are there others methods to get the position from UIScrollView ?
EDIT :
Thanks ThXou : https://stackoverflow.com/a/15763450/1752843
UIScrollView subclass :
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
self.position = point;
return self;
}

To detect the touch location inside scrollview, try this code
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[scrollView addGestureRecognizer:singleTap];
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint=[gesture locationInView:scrollView];
}

You could alternatively use scrollview.panGestureRecognizer's locationInView method to get the coordinates of a touch in your view. This could be in any of scrollView's delegate method depending on your requirements.

I saw an answer in SO that I think that it can solve you problem. It seems that the SDK doesn't pass the touch handling methods to the UIScrollView subclasses anymore. So, you should to perform a hitTest: to pass the touches to your subclass.
See the answer for more information.

scrollView.delaysContentTouches = NO;
It will makes that touchesBegan and other touch events will be triggered before scrollViewDidScroll.
The hitTest is a hack and should not be preferred solution.

Related

UIScrollView UIPangestureRecognizer dead zone on top edge of screen

as shown in the picture below the UIPanGestureRecognizer will not pan when the drag started inside the "dead zone" on the top of the screen. This is most likely caused by the notification center.
The touchesMoved:withEvent: method however does get called, so there should be a way to get pan gestures recognized in this area.
Has anyone else came across this issue, are there any workarounds out there yet? Thanks for any help!
It is possible that on the top edge of the screen you have multiple gesture recognisers that interferes. It could be that the the other gesture recogniser that interferes is added by system with some UIElement.
Try to implement UIGestureRecognizerDelegate on your gesture recogniser delegate.
Especially this method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
NSLog(#"1st recognizer class: %# ; 2nd recognizer class: %#", NSStringFromClass([gestureRecognizer class]), NSStringFromClass([otherGestureRecognizer class]));
return YES;
}
https://developer.apple.com/library/ios/documentation/uikit/reference/UIGestureRecognizerDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIGestureRecognizerDelegate/gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
Solved the problem. The touchesMoved:withEvent: should be implemented this way:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches.allObjects objectAtIndex:0];
CGPoint location = [touch locationInView:self];
CGPoint previousLocation = [touch previousLocationInView:self];
CGPoint contentOffset = self.contentOffset;
contentOffset.x -= location.x - previousLocation.x;
[self setContentOffset:contentOffset animated:NO];
}

Can't Detect UIView Children Touches Correctly when Parent UIView is Being Animated

I'm working on an iOS app.
I have a UIView that is being animated. It keeps moving from left to right.
This view has several UIView children. They move within their parent when this is being animated.
When I try to capture user touches on the children (by using a UITapGestureRecognizer), it doens't work as expected. It sort of detect some touches on the children, but not in the position where they currently are.
I've been struggling with this for a while now. Any ideas about how to solve this? I really need to detect which children the user is touching.
Thanks!
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self];
// Check every child subview
for (UIView *tickerItem in self.subviews)
{
// Check collision
if ([tickerItem.layer.presentationLayer hitTest:touchLocation])
{
MKTickerItemView *v = (MKTickerItemView*)tickerItem;
NSLog(#"Selected: %#", v.title);
// This button was hit whilst moving - do something with it here
break;
}
}
}
There is a UIViewAnimationOptions value...
UIViewAnimationOptionAllowUserInteraction
You can use this in the [UIView animateWithDuration... code.
This will enable the touch.

Trying to drag a UIImageView up and down a UITableView

I have a UITableView that has a UIImageView which traverses it one row at a time at the click of a button (up/down). What I would like to do now is allow the user to drag the UIImageView up or down the table ONLY (i.e. no sideways movement). If majority of the UIImageView is over a particular cell, then when the user lets go of their finger, then I want the UIImageView to link to that row. Here is an image of the UITableView, with the UIImageView:
The scroll bar is the UIImageView that needs to move or down. I realize that I am supposed to implement the following methods:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// We only support single touches, so anyObject retrieves just that touch from touches.
UITouch *touch = [touches anyObject];
if ([touch view] != _imageView) {
return;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch view] == _imageView) {
return;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
//here is where I guess I need to determine which row contains majority of the scrollbar. This would only measure the y coordinate value, and not the x, since it will only be moving up or down.
return;
}
}
However, I am not sure HOW to achieve this functionality. I have tried to find similar examples online, and I have looked at the MoveMe example code from Apple, but I am still stuck. Please also note that my scroll bar is NOT the exact same size as a row in the table, but rather, a bit longer, but with the same height.
Thanks in advance to all who reply
Try adding a UIPanGestureRecognizer to the UIImageView. Start by getting the image view's current location, then use the translationInView method to determine where to move the image view.
From Apple's documentation:
If you want to adjust a view's location to keep it under the user's
finger, request the translation in that view's superview's coordinate
system... Apply the translation value to the state of the view when the gesture is first recognized—do not concatenate the value each time the handler is called.
Here's the basic code to add the gesture recognizer:
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panView:)];
[imageView addGestureRecognizer:panGesture];
Then, do the math to determine where to move the view.
- (void)panView:(UIPanGestureRecognizer*)sender
{
CGPoint translation = [sender translationInView:self];
// Your code here - change the frame of the image view, and then animate
// it to the closest cell when panning finishes
}

How to detect someone tapping outside of a UIImageView

I have a UIImageView that is added as a subview. It shows up when a button is pressed.
When someone taps outside of the UIImageView in any part of the application, I want the UIImageView to go away.
#interface SomeMasterViewController : UITableViewController <clip>
<clip>
#property (strong, nonatomic) UIImageView *someImageView;
There are some hints in stackoverflow and Apple's documentation that sound like what I need.
Apple's : Gesture Recognizers
Apple's : UIView hitTest:withEvent
Apple's : UITouch Class Reference
Stackoverflow: Listening to UITouch event along with UIGestureRecognizer
(not likely needed but..) - CGRectContainsPoint as mentioned in the following post titled: Comparing a UITouch location to UIImageView rectangle
However, I want to check my approach here. It's my understanding that the code needs to
Register a UITapGestureRecognizer to get all touch events that can happen in an application
UITapGestureRecognizer should have its cancelsTouchesInView and
delaysTouchesBegan and delaysTouchesEnded set to NO.
Compare those touch events with the someImageView (how? Using UIView hitTest:withEvent?)
Update: I am registering a UITapGestureRecognizer with the main UIWindow.
Final Unsolved Part
I have a handleTap:(UITapGestureRecognizer *) that the UITapGestureRecognizer will call. How can I take the UITapGestureRecognizer that is given and see if the tap falls outside of the UIImageView? Recognizer's locationInView looks promising, but I do not get the results I expect. I expect to see a certain UIImageView when I click on it and not see the UIImageView when I click in another spot. I get the feeling that the locationInView method is being used wrong.
Here is my call to the locationInView method:
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
NSLog(#"handleTap NOT given UIGestureRecognizerStateEnded so nothing more to do");
return;
}
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
CGPoint point = [gestureRecognizer locationInView:mainWindow];
NSLog(#"point x,y computed as the location in a given view is %f %f", point.x, point.y);
UIView *touchedView = [mainWindow hitTest:point withEvent:nil];
NSLog(#"touchedView = %#", touchedView);
}
I get the following output:
<clip>point x,y computed as the location in a given view is 0.000000 0.000000
<clip>touchedView = <UIWindow: 0x8c4e530; frame = (0 0; 768 1024); opaque = NO; autoresize = RM+BM; layer = <UIWindowLayer: 0x8c4c940>>
I think you can just say [event touchesForView:<image view>]. If that returns an empty array, dismiss the image view. Do this in the table view controller's touchesBegan:withEvent:, and be sure to call [super touchesBegan:touches withEvent:event] or your table view will completely stop working. You probably don't even need to implement touchesEnded:/Cancelled:..., or touchesMoved:....
UITapGestureRecognizer definitely seems like overkill in this case.
You can use touch functions to do that:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
when user touch the screen first your touchBegan function is called.
in touchBegan:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pt = [[touches anyObject] locationInView:self];
}
so you have the point that user touched.Then you must find that the point is in your UIImageView or not.
But if you can give tag to your UIImageViews. That will be pretty much easy.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject ];
if( yourImageView.tag==[touch view].tag){
[[self.view viewWithTag:yourImageView.tag] removeFromSuperView];
[yourImageView release];
}
}

Recognize two touches tap on two different subviews

I want to handle in superview a touch event when there are two touches that land on different subviews.
Can I do it somehow by adding UITapGestureRecognizer with numberOfTouchesRequired =2; with a target self to a subviews?
Or I need to go something more complicated?
You could try something like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = touches.anyObject;
CGPoint referencePoint = [touch locationInView:self.view];
if([touch tapCount] == 2){
//Test touch coordinates to see if theres one in each view
}

Resources