UIGestureRecognizer that cancels when touchup outside of targetView - iphone

I have a UIView of which I want to know when the user is doing:
touchDownInside (to highlight the view)
touchUpInside (to confirm the action)
touchUpOutside (to cancel and reset the hightlight)
what gestureRecognizer can do this for me?

Please go though these four methods also which your view can override to handle the four distinct touch events:
1) finger or fingers touches the screen
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
2)finger or fingers move across the screens(this message repeatedly as a finger moves.)
-(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event;
3)finger or fingers is removed from the screen
-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;
4) a system event,interrupts a touch before it ends
-(void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event;

You can do this implementing the touches methods itself, why do you need gesture recognizer?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
The above function for touch down.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
The above function for touch up. And the combination of both for cancel.

Related

touchesBegan - Only needs the last touch action - iPhone

In
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
method I am doing some actions and in
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
method I'm doing some other action.
If I'm tapping 3 times the touchesBegan will call 3 times. What I want is if the user continuously taps only the last touch action should perform. Is it possible or not?
You can try a UITapGestureRecognizer instead, and disable it after the first tap.
Otherwise, you can use performSelector:withObject:afterDelay: with a short delay in touchesEnded:withEvent: and cancelPreviousPerformRequestsWithTarget:selector:object: in touchesBegan:withEvent:.
Does that make sense?

What really happens when call setCancelsTouchesInView?

Wondering what really happens when i call setCancelsTouchesInView. It is not covered in the official document http://developer.apple.com/library/ios/#documentation/uikit/reference/UIGestureRecognizer_Class/Reference/Reference.html
Thanks
ACB quoted the UIGestureRecognizer reference. To make it a little more concrete, suppose you have a view with a pan gesture recognizer attached, and you have these methods in your view controller:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touchesBegan");
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touchesMoved");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touchesEnded");
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touchesCancelled");
}
- (IBAction)panGestureRecognizerDidUpdate:(UIPanGestureRecognizer *)sender {
NSLog(#"panGesture");
}
And of course the pan gesture recognizer is configured to send the panGestureRecognizerDidUpdate: message.
Now suppose you touch the view, move your finger enough for the pan gesture to be recognized, and then lift your finger. What does the app print?
If the gesture recognizer has cancelsTouchesInView set to YES, the app will log these messages:
touchesBegan
touchesMoved
touchesCancelled
panGesture
panGesture
(etc.)
You might get more than one touchesMoved before the cancel.
So, if you set cancelsTouchesInView to YES (the default), the system will cancel the touch before it sends the first message from the gesture recognizer, and you won't get any more touch-related messages for that touch.
If the gesture recognizer has cancelsTouchesInView set to NO, the app will log these messages:
touchesBegan
touchesMoved
panGesture
touchesMoved
panGesture
touchesMoved
panGesture
(etc.)
panGesture
touchesEnded
So, if you set cancelsTouchesInView to NO, the system will continue sending touch-related messages for the gesture touch, interleaved with the gesture recognizer's messages. The touch will end normally instead of being cancelled (unless the system cancels the touch for some other reason, like the home button being pressed during the touch).
From the apple developer portal link:
cancelsTouchesInView — If a gesture recognizer recognizes its gesture,
it unbinds the remaining touches of that gesture from their view (so
the window won’t deliver them). The window cancels the previously
delivered touches with a (touchesCancelled:withEvent:) message. If a
gesture recognizer doesn’t recognize its gesture, the view receives
all touches in the multi-touch sequence.
cancelsTouchesInView:
A Boolean value affecting whether touches are
delivered to a view when a gesture is recognized.
#property(nonatomic) BOOL cancelsTouchesInView
Discussion
When this
property is YES (the default) and the receiver recognizes its gesture,
the touches of that gesture that are pending are not delivered to the
view and previously delivered touches are cancelled through a
touchesCancelled:withEvent: message sent to the view. If a gesture
recognizer doesn’t recognize its gesture or if the value of this
property is NO, the view receives all touches in the multi-touch
sequence.

Semi-piano app touch troubles with UIButtons

I am working on a semi-piano app with a diffrent keyboard-layout then a usual one.
I created the view manually with UIButtons,
My problem was I that I didn't know how to slide from a UIButton to another,
I figured that out with addTarget with the option of withEvent, which gave me the access to the touches.
Now, after I added the target like this:
[C addTarget:self action:#selector(outsideOfKey: forEvent:) forControlEvents:UIControlEventTouchDragOutside|UIControlEventTouchDragInside];
[C addTarget:self action:#selector(keyGetsLeft: forEvent:) forControlEvents:UIControlEventTouchUpOutside | UIControlEventTouchUpInside];
(also for all of the other keys),
I maneged to make them slideable,
outsideOfKey:forEvent: is as follows:
-(void) outsideOfKey:(id)sender forEvent:(UIEvent *)event
{
for(UITouch *t in [event allTouches])
{
CGPoint touchPoint = [t locationInView:window];
if(CGRectContainsPoint(C.frame, touchPoint))
{
C.highlighted = YES;
}
else{
C.highlighted = NO;
}
(Done for all the other keys as well)
I can slide from and into other keys, and when I leave them in keyGetsLeft:forEvent: I have just used the same syntx without the else, and the highlighted became NO.
Up to here it's easy,
But then when I try to do multi-touch, I can slide only one of the touches all around and the others must stay in the same position.
And even more, If I take one of the fingers away all of them are becoming non-highlighted,
I know the reasons to all of that, but I don't know how to fix it and make it to work.
I would probably move away from UIButtons altogether and implement my own custom touch tracking code. See Handling Multitouch Events in the docs. Namely, you will be implementing the following methods:
- (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
I would probably just implement hit areas, which you could setup in IB, with perhaps a custom UIView touch overlay (just a UIView with a custom subclass). This would let you setup the view in IB with images, titles, etc., but do all of your touch tracking in your custom subclass.
I am afraid, bensnider is right. But I'd implement it via GestureRecognizer:
https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_uikit_gestures
https://developer.apple.com/documentation/uikit/uigesturerecognizer
Each key has one TapRecognizer, while a parent view has a SwipeRecognizer to detect slides form one key to another.
Very useful, on Apple Developer Video Archivelogin with development account required:
WWDC2010: Session 120 — Simplifying Touch Event Handling with Gesture Recognizers
WWDC2010: Session 121 — Advanced Gesture Recognition
I'd use one view for all buttons and manually implement touch tracking as bensnider said. Manually drawing backgrounds/titles also is not so difficult.
Heres a link to an open source iOS piano app I made https://github.com/meech-ward/iOSPiano
I used CALayers for the piano keys and I used
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
to detect if the user is currently touching a piano key.
It works really well even with multiple touches.

How are objects made draggable in iphone app?

I would like to have objects in my view which can be dragged and dropped.
When they are dropped in a certain area they should disappear and some code should execute.
How are objects made draggable in an iphone app? Is it just a button which can be drag enabled?
How would one detect the position of the draggable object? Would it be as simple as (Psuedo)
if (draggableButton1.xPosition > e.g. && draggableButton1.xPosition < e,g
&& draggableButton1.yPosition > e.g. && draggableButton1.yPosition < e,g) {
do something
}
?
When user touches the object that time following method is called.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
When moved with touched, following method will be called.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
When user end with touch, the following method will be used
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
The NSSet object contain the UITouch object which contain all information for touches on view, which view, position on screen , previous position and so more. You can check documentation for that.
Start your logic from touchesBegan and change the position of your object in touchesMoved event. then when user drop object, touchesEnded event will be called. Check for position in touchesEnded event and excute your code as you have said.
May this three methods will help...
If said object is an UIView you can get its frame origin and size.
Check Apples MoveMe example: http://developer.apple.com/iphone/library/samplecode/MoveMe/Introduction/Intro.html

How can I tell if a button is being pressed in my iPhone app?

How can you tell when a button is being pressed? Specifically, how can you do something while a button is down?
While the screen is touched, there will be touch events. There are also touch up and touch down events.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesBegan");
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesMoved");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesEnded");
}
Then just register your controller as the touchController.
Also check out Apple's GLPaint example:
https://developer.apple.com/iphone/library/samplecode/GLPaint/
You can also do it by creating an IBAction and connecting it IB. Interface builder for iPhone can actually demux different types of events. If you ctrl-click a UIButton in your UI, and release the mouse button instead of dragging a connection you will see an inspector that shows a bunch of different actions you can wire up. When you just drag it defaults to wiring up "Touch Up Inside", but if you want you can wire up "Touch Down" or "Touch Down Repeat" and that action will be cause the appropriate selector to be called.
If you are doing complicated stuff with your own gestures then using the touchController based stuff will definitely be a better approach, but for simple things just using the built in nib based actions may be simpler.