How to detect touch end of image view when touches moving - iphone

I have an image view. i detected touch in image view like this
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
int viewTag=[touch view].tag;
if ([[touch view] isKindOfClass:[UIImageView class]])
{
//My code
}
}
and touches moved on image view. whenever my touch moved out off the image view in that particular time i need one alert view. how to detect that touch over from the image view in touches moving?...

I recommend using a UIPanGestureRecognizer and adding it to a larger super-view of the image-view you want to detect on. That way even if the touch starts outside and moves into and out of your image-view you can follow the movement of the touch in your gesture handler.
It's pretty easy, make a method called handlePan: for example, create the gesture recognizer using your handler method, add it to the appropriate super-view. Now whenever the gesture is active and the touch moves your handler method will get called and you can check to see if it is inside your image view.

You should use this method...
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
int viewTag=[touch view].tag;
if ([[touch view] isKindOfClass:[UIImageView class]])
{
//My code
}
else
{
//show the alertView here
}
}
and to check that the initial click was on the imageView you have to set a flag in the touchesBegan method... and check it accordingly in the touchesMoved method

You may add a transparent UIButton of the same size on top of the UIImageViewand track UIControlEventTouchDragOutside
[button addTarget:self action:#selector(draggedOutside:) forControlEvents:UIControlEventTouchDragExit];

Related

Multiple touch on the iPhone issue

How can I make it so that while the user is playing on the joystick to move the character at the centre they can also touch the bottom right of the screen (the second touch) to fire the gun? I have looked at other questions but I still cant figure it out...
this is basically the code....:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//make the touch point...
UITouch *touch = [[event allTouches]anyObject];
CGPoint point = [touch locationInView:touch.view];
if (//touching a certain area (on the joystick)) {
//do stuff
}
else if (point.x > 300 && point.y > 200) {
/fire method
}
}
so basically how do I call touchesBegan again to find the position of CGPoint point, and work out if the fire method should be called?
Thanks
EDIT:
I have tried to do that 2nd option and done this:
in view controller.h I added:
#interface fireView: UIView
#end
and in .m I added:
#implementation fireView -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"hi");
}
#end
....but it doesn't log/print "hi"?
Use 2 UIGestureRecognizers. You can create 2 invisible views of needed size - one for joystick and one for fire button. For every view use single gesture recognizer. And then you will be able to handle taps on these view by in different methods without checking if it was fire or joystick.
Let's think you have 2 views - joystickView and fireView already. Then do it like
UITapGestureRecognizer* fireTapGestureRec= [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(fireTapped:)];
fireTapGestureRec.delegate = self;
fireTapGestureRec.numberOfTapsRequired = 1;
fireTapGestureRec.numberOfTouchesRequired = 1;
[fireView addGestureRecognizer:fireTapGestureRec];
[fireTapGestureRec release];
and write fireTapped: to handle the event. And the same thing for joystick.
EDIT
Second option (suggested in comments)
Make subclasses of UIView, like
#interface fireView: UIView
#interface joystickView: UIView
and for each subclass write it own touchesBegan: or touchesEnded:

UITapGestureRecognizer Stops touchesEnded

I'm trying to make an iPhone app that is controlled by touch. I also want a powerup to be activated when the user double-taps. Here's what I have so far:
UITapGestureRecognizer *powerRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(usePower)];
powerRecognizer.delaysTouchesEnded = NO;
powerRecognizer.numberOfTapsRequired = 2;
powerRecognizer.numberOfTouchesRequired = 1;
[self.view addGestureRecognizer:powerRecognizer];
[powerRecognizer release];
But the problem is, when I double-tap, my touchesEnded:withEvent: method only fires once, but my touchesBegan:withEvent: method fires twice. Since touchesBegan: sets a timer and touchesEnded: invalidates it, then when touchesEnded: only fires once, the timer is still running. How can I fix this?
In Swift, you can avoid the standard behaviour and let the UITouch event propagate to view and its child, even if a gesture is recognized, with
recognizer.cancelsTouchesInView = false
Both touchesBegan and touchesEnded will be called.
Here is my solution for detecting double-taps:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if([touch tapCount] == 2) {
// do sth
}
}
Adding a gesture recognizer to a view changes the behavior of several touch handling methods, including touchesEnded:WithEvent:.
From the above link:
After observation, the delivery of
touch objects to the attached view, or
their disposition otherwise, is
affected by the cancelsTouchesInView,
delaysTouchesBegan, and
delaysTouchesEnded properties.

Force cancel a touch iphone

I have 4-5 uibuttons(also can use uiview instead of button) side by side next to each other.
When user moves touch from one button to other(outside of self view), i want to cancel this touch and start touch for the next button(view).
How to achieve this functionality?
I used uiview instead of buttons kept it next to each other, handled its touches events.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject]; //anyobject
CGPoint touchLocation = [touch locationInView:touch.view];
if(![self pointInside:touchLocation withEvent:nil])
{
//touch is outside of my current view , do something to cancel current touch and i can get touchesmoved for the next view . help me to write something.
}
}
Is there any other way to handle event when we have such UI.
Thanks.
If you are using UIButtons, you can just use the button's events to do this. When you get a touchDown or touchDragInside, then play your note. Stop when you get a touchUpInside or a touchDragOutside.
You need to handle the touches yourself from a UIWindows subclass, or from the UIViewController container (in this case remember to disable the userInteractionEnabled property)

Why doesn't the touch event arrive at my UIImageView?

I have some nested views like this:
First, there is an big UIView. Inside this, there is another UIView. And inside this, there is an MyNiceButtons class that inherits from UIView. So I have:
UIView > UIView > MyNiceButtons (= an UIView).
In detail, the UIView creates an UIImageView and adds it as a child view to itself, which represents an graphical button. So inside the MyNiceButtons class implementation, I have this code to handle a touch event on the fake button image:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject]; // i just need single touches
// just to see which view is affected
UIView *tview = [touch view];
CGRect rect = tview.frame;
rect.origin.x = rect.origin.x + 20.0f;
tview.frame = rect;
[tview setBackgroundColor:[UIColor yellowColor]];
if ([touch view] == self.fakeButtonImageView) {
NSLog(#"touch on fake button detected");
}
}
All views in the hierarchy have userInteractionEnabled=YES. The touch arrives at the first view in the hierarchy (the parent of the parent).
UIView *tview = [touch view];
This returns just the parent of the parent, but not the UIImageView where the user actually tapped on.
What's the trick to recognize if the touch was on the button UIImageView?
I would first suggest that you take a good look at what you can do with a Custom-type UIButton (can set images for various states). 95% of the time, this should address your needs.
If you have some other need, I can help you debug w/ hitTest, etc.

Passing touches through a UIView to a UIScrollView not working

I have a view derived from a UIScrollView controller that I use to page through images in a library. That works fine.
I overlayed a UIView on the right side to handle touches for scrolling quickly through the list of images. My problem is that if I pass the touches through to either 'super' or 'nextResponder' they never make it to the UIScrollView object below.
My question is how can I force the UIScrollView below to handle the touches that I don't need to handle? I'm setting a timer for 0.3 seconds that during that time all touches are passed to the UIScrollView to handle. So if the user started a swipe gesture to turn the page, it will happen.
Here's the code for the touchesBegan method:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
// Start a timer to trigger the display of the slider and the processing of events.
touchesTimer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:#selector(showSlider:) userInfo:nil repeats:NO];
// Where are we at right now?
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
lastPage = [self page:currentPoint.y];
// Pass the event though until we need it.
// [self.nextResponder touchesBegan:touches withEvent:event];
if ([touch.view isKindOfClass:[UIScrollView class]])
{
if (self.nextResponder != nil &&
[self.nextResponder respondsToSelector:#selector(touchesEnded:withEvent:)])
{
[self.nextResponder touchesEnded:touches withEvent:event];
}
}
}
I would try using a regular UIViewController rather than a UIScrollViewController and then add the scroll view object where you need it and put the scroll faster view you want on the right side. This way they are separate and the touches won't get confused.
Here's an easier solutions that worked well for me:
In the UIView on top of the UIScrollview make the width and height both 0 (so that the view is no longer technically on top of the UIScrollView) and set clipsToBounds = NO (so that the contents of the view still show up on top of the UIScrollView).
self.OverlayView.clipsToBounds = NO;
CGRect frame = self.OverlayView.frame;
self.OverlayView.frame = CGRectMake(frame.origin.x, frame.origin.y, 0, 0);
Note that if the UIView contains interactive controls then they will no longer work. You'll need to move it into it's own view above the UIScrollView.