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)
Related
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];
In my UIView subclass I have this:
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView: self];
NSLog(#"touches count: %i",[touches count]); //always shows 1
}
No matter how many fingers I touch the screen with, I only get "1" as the output. I also added the above to touchesMoved with same results.
Have you enabled the multitouch option?
[(your uiview) setMultiTouchEnabled:YES];
This is by default false, that will translate all touches on your view to one single touch in the middle of all other touches.
Setting it to YES will make your view recieve one touch event for each finger (or pen) on screen
I think there's a "multiple touch enabled" checkbox in interface builder... And also a corresponding property you can set.
My problem is quite strange but simple.
I subclassed a my customer UIScrollView: MyScrollView, where i disabled the scroll:
self.scrollEnabled = NO;
that means apart from
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
all other UIScrollViewDelegate method won't be called
and in MyScrollView i do the content scroll by detecting the user touch movement on screen, that is to say no flipping, no bounces, my implementation is in the touchesMoved:withEvent: method
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
// NSLog(#"touch.phase:%d",touch.phase);
CGPoint currentPosition = [touch locationInView:self];
CGPoint lastTouchPosition = [touch previousLocationInView:self];
CGFloat deltaY = lastTouchPosition.y - currentPosition.y;
CGFloat contentYOffset = self.contentOffset.y + deltaY;
[self setContentOffset:CGPointMake(0,contentYOffset) animated:NO];
}
after the user drag movement have been finished, i do my own method according to the content offset of MyScrollView in touchesEnded:withEvent:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//some implementation according to current content offset
}
user moves finger on screen, whenever the finger left the screen surface, the touchesEnded:withEvent: get called and i can implement my own method correctly.
BUT, when user move finger on screen surface from inside the screen to outside either on top or bottom, then lift the finger up, the touchesEnded:withEvent: method never got called, it seems like the ios doesn't treat the move out bounds(top or bottom) event as a touches end event, also ios wouldn't know the what is going on when touch is outside it screen bounds
someone may suggest me to detect the current position in touchesMoved:withEvent: to check out whether it is inbounds or not. this MAY WORK WHEN THE MOVEMENT IS VERY SLOW, but when you move very fast, the system can not detect every point position, it seems like the movement is detected in a certain time interval.
can any one help me out how could i detect if the user finger has moved out of bounds or not
I think the touchesCancelled:withEvent: method will be called !
I have resolved this problem
bcs UIScrollView does too much work that we can not handle some event ourselves, fortunately the UIView can detect the touche move out of bounds and will invoke the touchesEnd:withEvent: method.
considering that replacing MyScrollView's superclass with UIView has too much work to do, so i figured out a simple way to resolve:
i added an TouchActionDetectView subclassed from UIView, whose work is to detect all user touches event and deliver those event to MyScrollView. of course i have to clear the background color of TouchActionDetectView to avoid blocking other view content.
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.
I have a view within a UIScrollView that loads an additional subview when the user presses a certain area. When this additional subview is visible, I want all touch events to be handled by this - and not by the scrollview.
It seems like the first couple events are being handled by the subview, but then touchesCancelled is called and the scrollview takes over the touch detection.
How can I make sure that the subview gets all the events as long as the movement activity is being performed on this view?
This is my implementation on touchesMoved - which I thought would do the job...
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
CGPoint touchPt = [touch locationInView:self];
UIView *hitView = [self hitTest:touchPt withEvent:event];
UIView *mySubView = subviewCtrl.view;
if(hitView == mySubView) {
[subviewCtrl.view touchesMoved:touches withEvent:event];
}
else {
NSLog(#"Outside of view...");
}
}
The responder chain hierarchy "normally" goes from subview to superview, so you shouldn't need to do the hitTest in your superview. The problem that you are having is not that you need the superview to invoke touchesMoved on the subview, but rather that UIScrollView subverts the normal responder chain hierarchy by intercepting touch events in order to deliver a smooth scrolling experience to the user. If you don't want this behaviour, then you can disable this behaviour in the scrollView by sending it the following message:
[scrollView setDelaysContentTouches:NO];
Note that this will make sure that your subview has first crack at handling the events in question (provided that it is in fact the first responder). This can negatively impact the scrolling and zooming performance of the scrollView, however, which is probably why Apple sets it to YES by default.