How to detect someone tapping outside of a UIImageView - ios

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];
}
}

Related

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
}

Detect touch position on UiScrollView

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.

Get all touches on screen

I'm having a small issue. I'd like to receive all touches on the screen and for each one spawn a new video. The problem is that once a video is placed then it intercepts the touch points. I tried various values to go in locationInView but without any luck so far. Am I looking in the right place?
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint pointOnScreen = [[touches anyObject] locationInView:self.view];
C4Movie *player = [C4Movie movieNamed:#"inception.mov"];
player.shouldAutoplay = YES;
player.loops = YES;
player.center = pointOnScreen;
[self.canvas addMovie:player];
}
#end
Try setting the userInteractionEnabled property of each video screen (assuming it is held in some sort of UIView) to NO - that way, touch events will pass through it and continue to be received by your handler.
Yes, you're looking in the right place, and Chris has it right about user interaction. You should try:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint pointOnScreen = [[touches anyObject] locationInView:self.view];
C4Movie *player = [C4Movie movieNamed:#"inception.mov"];
player.shouldAutoplay = YES;
player.loops = YES;
player.center = pointOnScreen;
player.userInteractionEnabled = NO;
[self.canvas addMovie:player];
}
However you're going to run into an issue with adding videos. Unfortunately, iOS / hardware only lets you have 4 video pipelines running at one time so you'll hit that pretty quickly.
If you want to add things to the screen as you touch and drag your finger, then you could also do the above code inside of the following method:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
//work your magic here
}

How to move/rearrange position of views on touch event?

Suppose, on my window i have 3 views, main one in the background and 2 up front.
Each view up front contains some content, i'd like to be moved as part of a view upon touch. By "moved" i mean "rearrange positions relative to another view". Upon touch, i'd like to "pick up the view with all of it's content and place it in the position currently occupied by another view"
Where would you get started on something like this?
Something like this:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UIView *touchedView = [[touches anyObject] view];
CGPoint location = [[touches anyObject] locationInView:touchedView];
touchedView.center = location;
}
See also these methods in UIResponder.h:
- (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;
First you need to create a GestureRecognizer. Something along the lines of:
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTap:)];
doubleTap.numberOfTapsRequired = 2;
[self addGestureRecognizer:doubleTap];
and add it to whatever view you want (or all three). From the sounds of it your main background view makes the most sense. Then create the doubleTap method, which will make one of your views move to where the other is:
-(void)doubleTap:(id)sender {
view1.frame = view2.frame;
[self bringSubviewToFrom:view1];
}
I would also make sure all your subview content has its autoresizingMask set according to how you want the subviews to behave.

Resources