iOS x coordinate of finger when tapping on UIButton - ios

I have a UIButton. How can I get the x-coordinate of the finger when the user taps on said button. I'm thinking it will involve touchesBegan but how do I only get the value if the "touchesBegan" occurred on the button? And if there is a way (without just monitoring the x, y, width, and height of the button and checking if my touch was in that region) will I need to disable the button's user interaction so the code can handle it and not the built in xib stuff. Thanks!

A “tap” is generally considered to be a touch-down inside the button followed by a touch-up inside the button. You need to figure out whether you want the touch-down-inside event or the touch-up-inside event (or both).
Let's say you want the touch-down-inside event. Write a method like this in your view controller:
- (IBAction)buttonWasTouched:(UIButton *)button forEvent:(UIEvent *)event {
NSSet *touches = [event touchesForView:button];
NSLog(#"button:%# touches:%#", button, touches);
}
If you're creating the button in a nib, control-click the button and connect its “Touch Down” outlet to the buttonWasTouched:forEvent: action on your view controller (which is probably File's Owner).
If you're creating the button in code, send an addTarget:action:forControlEvents: to the button to connect its UIControlEventTouchDown event to the view controller's buttonWasTouched:forEvent: action.
If you want to catch the touch-up-inside event, connect its “Touch Up Inside” outlet in the nib, or use UIControlEventTouchUpInside in code.

Related

How do I toggle hidden of a label while a button is pressed?

I am trying to figure out how to only display a label while a button is pressed in OS. I know how to operate the touch events but I am not sure how to incorporate the UILongPressGestureRecognizer into this.
The UIButton class, as well as lots of other UIControl subclasses can have numerous actions hooked up to them.
When we are hooking up an action from interface builder to our source code file, if we open the "Event" drop down, we're presented with a long list of options:
In almost every scenario, we're hooking our actions only up to "Touch Up Inside". This allows the user to consider whether or not they want to really press the button. If they drag their finger off the button before letting go, the action doesn't fire, because the "up touch" gesture happened outside the bounds of the object.
But here, we want to actually hook our button's "touch down" event up. This is when we'll display the label.
Let's go ahead and create a "touch down" event and a "touch up inside" event:
Swift
#IBAction func buttonTouchDown(sender: UIButton) {
self.myLabel.hidden = false
}
#IBAction func buttonTouchEnded(sender: UIButton) {
self.myLabel.hidden = true
}
Objective-C
- (IBAction)buttonTouchDown:(UIButton *)sender {
self.myLabel.hidden = NO;
}
- (IBAction)buttonTouchEnded:(UIButton *)sender {
self.myLabel.hidden = YES;
}
So far, buttonTouchEnded is set up completely normally, and buttonTouchDown was set up by selecting "touch down" from the "Event" list.
We can always verify what our control is hooked up to by right clicking it in the interface builder:
But this menu is useful for more than simply checking what we've already hooked up. From here, we can hook up any of the other actions to our existing #IBAction methods simply by clicking in the circle and dragging to the existing method.
So we obviously want the label to disappear if we stop pressing the button, a normal touch up like you'd hook up any other button. The only question remaining is, what exact behavior do you want?
If you want the label to disappear only when the finger is lifted, no matter where the finger goes, then we must also hook up "touch up outside".
If you want the label to disappear when the user drags their finger off the button, then we should hook up the "touch drag exit" action.
We also probably want to hook up the "touch cancel" action, which would occur if some sort of system event (perhaps an incoming phone call) cancels the touch.
This Stack Overflow answer elaborates on the differences between the action options we have, so you can craft the behavior exactly how you need it.
Anyway, once we decide which actions we want to hook up to which methods, bring up that right click menu and click-drag from the circles to the methods:
The easiest thing to do would be to add an action to the touchDown event and a separate action to touchUpInside and touchUpOutside.
Show the label on the touchDown action and hide it on the touchUpInside / touchUpOutside action. (and for completeness, on touchCancel, as suggested by nhgrif in his very thorough answer.)
A long press gesture recognizer won't work in this situation. You could create a custom gesture recognizer that triggered one event on touch and another event on release, and use that. It's actually not that hard to do.
EDIT
I just uploaded a demo project to GitHub called "MorphingButton" (link) that I created for another question here on Stack Overflow.
That project now shows a label on touching the app button and hides the label when you release the button.
The project is a hybrid Swift/Objective-C project that shows how to do the button morphing and label showing/hiding in both languages. It has a tab bar with a Swift tab and an Objective-C tab.

iOS - change animation when user taps screen

Lets say that i have an animation - an image is going from left side of the screen to the right. I would like to make it a little bit interactive - when user taps on a screen i want to change direction of image movement. Whats the best approach to implement it?
What I do in some cases is take the main view of the View Controller, in Storyboard, and change the class type of that UIView to UIControl.
In the code that is accessed as MyViewController.view, which you can write:
var viewAsControl = myViewController.view as UIControl
In Swift or some equivalent of that.
The UIControl subclass of UIView is the hierarchical layer (class) that adds the action/target facilities to a view. For example, UIButton is a UIControl, because it generates events (actions), and it is also a UIView so it can be added as a subview.
Then from the Connections Inspector, accessed via the far right Icon of the far right panel (that is, the panel to the right of the storyboard editor window), I'd select the Touch Up Inside event type or some other event and drag it to an #IBAction tagged function I'd add to the View Controller's source code, to receive the tap event. From that tap notification, you can cancel the current animation and add a new one, etc...
Alternatively, you can create an IBOutlet for the view if you've turned it into a UIControl in IB, and use the addTarget() method to assign an action handler for a specific event, e.g. to make it call a function in your code.
Either way the effect will be that any time the view is tapped, it will generate the event for you to respond to

iOS: UIControl in UIScrollView not registering click events

I have a UIControl within a UIScrollView. I scrollview has a textfield. I want the text field to loose focus when the UIControl is touched.
This is the method the UIControl is hooked up to:
- (IBAction) clickedBackground
{
[self.view endEditing:YES]; //make the view end editing!
}
But, the UIControl doesn't seem to call this event when touched.
I did try this as suggested elsewhere, but to no avail:
[scroller setDelaysContentTouches:YES];
The touch event on your UIControl is getting conflicted with touch event of your UIScrollView.
If you just to loose focus of the text field you can use on a button tap.
[textField resignFirstResponder];
But ideal way is to loose focus when user taps anywhere outside the text field. This answer would help you to achieve this.
However, if you just want to resign the keyboard. Then make use of resignFirstResponder on a button tap. You can also look into UITextField input accessory view in order to display a button on the keyboard input view that user can tap on.

How to detect "Drag Enter" on UIScrollView

Imagine a UIButton and a user who taps somewhere OUTSIDE the button and then slides onto it. If I want the button to detect such touches I can register it for any "Touch Drag Enter" events.
My question: is there some way to achieve the same for a UIScrollView?
I.e., I tap somewhere outside the scrollview, drag my finger onto the scrollview and as soon as I enter the scrollviews frame it starts panning? (Because by default it doesn't, I have to start my touch INSIDE the scrollview in order to pan)
If you want to do this, you will have to do a custom implementation using -touchesBegan, -touchesMoved, and -touchesEnded
The documentation for the UIResponder class (which all ViewControllers inherit from) that allows you to do this is here.
Hopefully you can figure out what to do from here. :)
As an extra hint, you will also most likely need to use this function
bool contains = CGRectContainsPoint(CGRect rect, CGPoint point);
Imagine a UIButton and a user who taps somewhere OUTSIDE the button and then slides onto it. If I want the button to detect such touches I can register it for any "Touch Drag Enter" events
Actually, no you can't. A UIControl will not get any of the control events unless the touch started in the control.
And that's for the same reason that you are seeing a similar effect with the scroll view. This is the entire basis of touch delivery on iOS. A touch "belongs" to the view that was initially touched.
After all, the runtime cannot possibly know that you are going to drag into the scroll view...

iPhone: Multiple touches on a UIButton are not recognized

I have a UIButton (a subclass of one, actually) that interacts with the user via the touchesbegan: and touchesmoved: functions.
What I would like is for the user to be able to press down the button, drag their finger away, and have a second finger touch the button (all while the first finger has never left the screen).
Problem is, the second touch event never calls touchesbegan: unless the first finger has been released.
Is there some way to override this, or am I trying to do the impossible?
Have you tried setting multipleTouchesEnabled to YES?
If the interactions are using touchesbegan: and touchesmoved: then use a UIView instead of a UIButton. A button is a UIControl, and the way to interact with UIControls is
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents.
I'm not sure this two ways of getting events mix well.

Resources