Where's the difference between UIControlEventTouchDragOutside and UIControlEventTouchDragExit? - iphone

Both appear to have the exact same effect. They come both when the finger is far enough away from the control. The "bounds" is not really the criteria for UIControlEventTouchDragExit. It gets fired only if it's far away enough...

I came here looking for the same thing and the answer from eOgas did not seem accurate. I did my own test case and here are my results for those who want a detailed answer without having to test it for themselves:
UIControlEventTouchDragExit
gets called only once as the user leaves the control they pressed. Once the user breaks the 'magical boundary'* outside a UIButton (for instance) this event gets called once. If, while still dragging, the user drags back into the control and back out again, this event gets called once again. The reverse can apply to UIControlEventTouchDragEnter.
UIControlEventTouchDragOutside
gets called after UIControlEventTouchDragExit and gets called repeatedly every time the user drags their finger while still holding down the original touch that was used to enter the control. For those familiar with the touchesMoved method of UIView, it works similarly. The reverse can apply to UIControlEventTouchDragInside however this can obviously get called without having to leave the control first.
To understand or remember better, you can compare these events to a person leaving (and coming to) their house wherein they only exit the house once but then proceed to move outside repeatedly. Also, a person only enters their house once but then proceeds to move inside repeatedly.
*the extra space around a UIControl object that takes into consideration the user's potential for imprecise touches.

UIControlEventTouchDragOutside
An event where a finger is dragged just outside the bounds of the control.
UIControlEventTouchDragExit
An event where a finger is dragged from within a control to outside its bounds.
It sounds like with UIControlEventTouchDragOutside is fired when the user touches just outside the bounds, regardless of whether or not the finger was ever within the bounds. UIControlEventTouchDragExit is only fired when the finger is dragged from within the bounds to outside the bounds.
So, UIControlEventTouchDragOutside would be used when resizing a control (an edge tap, then drag), whereas UIControlEventTouchDragExit would be used to move the control around (tap inside and drag).

.touchDragOutside is continous, while .touchDragExit is not.
.touchDragOutside gets called on every drag movement that happens outside bounds (similar to DragGesture.onChanged(_:)), while
.touchDragExit gets called once as the drag leaves the bounds.
They both (!) get called only when the drag is initiated within the view.
In addition, they are only fired when the finger is "far away" (~70 pt) from the control. They won't get fired as soon as the finger leaves the bounds (same goes .touchUpOutside). They seem to be designed for the users to deliberately cancel ongoing touches.

Related

button highlight state and gestures

I've been struggling with this for a while already and some
help would be useful.
Imagine I have a UIButton, which starts in highlighted/selected state.
If a user taps it, then highlighted/selected state changes.
I've implemented this and it works fine. Problems start
for example if user taps inside the button region,
does not release her/his finger, and moves mouse
outside the button area -- at this time my Button
would usually lose highlighted/selected state.
Anyway, I have solved this issue too, by overriding UIControlEventTouchUpOutside
and making button keep the state it had before...
But now another problem comes in, similar to the above,
if a user taps the button, does not release his/her
finger, and moves the finger to the right say (horizontally,
which also makes my dialog for instance go to the right),
then I again lose "selected/highlighted" state....
I believe again some kind of gesture similar to - but different -
than UIControlEventTouchUpOutside is being called which
removes my selected state...
Do you know what can be going in here? Any advice appreciated.
ps. I have fixed all the issues by just setting different images
for normal/selected states using the interface builder.
For the highlighted effect you can use the: setHighlighted of UIButton class.
When you start touching the button set the highlighted property of button to YES.
when you start touch:
yourButton.highlighted = YES;
When you stop touch:
yourButton.highlighted = NO;
I have fixed all the issues by just setting different images for normal/selected states using the interface builder.

How to cancel UITapGestureRecognizer?

I noticed that the single tap happens when the touch dragging is performed quickly.
I want to cancel the single tap if the user moves the touch.
How can I do this?
I noticed that the single tap happens when the touch dragging is performed quickly.
My suggestion is to do nothing. Assuming you have everything set up properly then what you are going to end up doing is creating an app specific behavior for dragging simply to accommodate your personal preference. This could confuse your customers and possibly prevent your app from getting approved.
If the problem you are experience cannot be duplicated in other apps then I would guess that you are doing something incorrectly with respect to the responder chain, and you should focus on fixing that first.
I'm going to assume that you don't want to cancel the tap gesture itself (once the tap gesture has fired, I don't think you can cancel the gesture, it's already done!), but rather the code fired from it.
What you could do is create a timer, and delay the action created by the tap gesture by a second or two. You then have that time interval to cancel the action.

ccTouchesMoved and selector:#selector(ButtonTapped:)

Ill try and keep this as simple as possible.
I have a guy which you drag around the screen
I have a shoot button which fires bullets
To drag the guy around the screen im using ccTouchesMoved, basically get the users finger movement and set the guy to that place. Done.
I have a button which is a CCMenuItemImage and if it is tapped then is called a selector to run a method. The method simply fires some bullets. Done.
Now my problem is i cant have these two things work at the same time. I would like the player to be able to drag around the guy and shoot at the same time. Im assuming the button is not being tapped becuase the user is touching and dragging around the player.
How can i fix this? Still be able to drag around with one finger and press the shoot button with the other and they both work together?
You might want to implement your fire button using a sprite. You can handle ccTouchesBegan and ccTouchesEnded to check for a press within the bounds of your button, to swap it with a pressed state (on begin) or to implement the fire action (on end).
In your ccTouchesMoved handler, you can iterate over the set of touches and determine if the touch that moved is the one over the button, or the touch that should change the character position.

How do I properly clean up a UIButton

I am having issues with UIButton with the iPhone SDK. I've determined that when I have a UIButton held down when the parent is removed (and the uibutton subsequently removed), I get some strange behavior. In my case, the app stops receiving any input whatsoever, as if the cleaned up held-down button has hijacked the input system somehow.
Does anyone know if there is an appropriate way to clean up the UIButton that would release what I'm guessing is the framework thinking the released button is still held down?
Update: Adding detail to my issue
Basically, the simplified situation is that I have a root view with two characters (actors, not letter characters) and a number of buttons, among other views. The user can use the buttons to affect direction of movement, and when the characters are close to each other, the scene moves forward immediately into another mode, i.e. the buttons slide off, the view cleans up, and I construct a new one.
What this necessitates is the ability to immediately move on and clean up even if the button is still held down. I figured I could pull some tricks to delay cleaning the button up, but I would be surprised if there isn't simply some way to properly clean up the button for removal regardless of what state it is currently in. Hope that clarifies.
It might help if you would explain what behavior you are expecting. If you are calling -removeFromSuperview while holding down the view you want to remove (or its parent), I would suggest you instead hide the view and set some flag you can look for when the user finishes holding that will at that point call -removeFromSuperview.
It turned out the problem wasn't a button being held down but rather a call to set the center coordinate of a mapview with animation on, i.e.
[mMapView setCenterCoordinate:mCoordinates animated:YES];
If the view was cleaned up while the animation was still moving, the app would no longer respond to user input. I'm not certain why this is the case, still, but setting the animated flag to NO ensured the problem didn't arise.

UIControlEventTouchDragEnter doesn't seem to work for catching a tap that slides into a control

I wanted to allow for a method to get called, if a finger was dragged from outside into the bounds of a control. I thought UIControlEventTouchDragEnter would do it, but it doesn't seem to. Does anyone know if there is a way to trigger an action based on a tap sliding into a control?
This is what I was trying, but got no calls to my -fingerSlidIn:
[aButton addTarget:self action:#selector(fingerSlidIn:withEvent: ) forControlEvents: UIControlEventTouchDragEnter];
Thanks!
This is by design. All events belonging to a continuous touch (from touch down until touch up) go to the view that received the first touch down event. So you will never receive a UIControlEventTouchDragEnter unless the user moved the finger away from the control and back.
To do what you want, you would have to capture the touches on the control's container view and determine manually when the touch coordinates enter your control's frame rect (possibly by calling pointInside:withEvent: for every touch you receive).