I'm working with objective-c and I want to detect when the user is tapping a button (not when he tapped it, but the actual moment when is being taped until he stops).
Is there any method? I'm not finding it if there's any.
Thanks
Using touchDown event you can make an action while your button is pressed
Example
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func testing(_ sender: Any) {
label.textColor = UIColor.red
}
#IBAction func testingCancel(_ sender: Any) {
label.textColor = UIColor.black
}
#IBAction func testingUpInside(_ sender: Any) {
label.textColor = UIColor.black
}
}
Here (UIControlEvents) are all events of control/actions (with their brief description)
UIControlEventTouchCancel: A system event canceling the current touches for the control.
UIControlEventTouchDown: A touch-down event in the control; when button is tapped/pressed.
UIControlEventTouchDownRepeat: A repeated touch-down event in the control; for this event the value of the UITouch tapCount method is
greater than one.
UIControlEventTouchDragEnter: An event where a finger is dragged into the bounds of the control.
UIControlEventTouchDragExit: An event where a finger is dragged from within a control to outside its bounds.
UIControlEventTouchDragInside: An event where a finger is dragged inside the bounds of the control.
UIControlEventTouchDragOutside: An event where a finger is dragged just outside the bounds of the control.
UIControlEventTouchUpInside: A touch-up event in the control where the finger is inside the bounds of the control.
UIControlEventTouchUpOutside: A touch-up event in the control where the finger is outside the bounds of the control.
Use Touch Down to get button tapping event.
Yes it is possible
Button has following events to listen
You can use Touch Down
Related
I have created a custom view that is to be used as a radio button with images and text. I need to be able to load the saved selection when the controller loads. I set my listeners this way:
for button in genderButtons {
button.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(genderTapped(_:))))
}
#objc private func genderTapped(_ sender: UITapGestureRecognizer) {
for button in genderButtons {
button.select(sender.view! == button) // Toggles the button to display selected/deslected state.
...
}
}
The problem is that I can't find a way to tell the view to select. I tried making the gesture recognizer and object, but it doesn't have any methods I can use to trigger it. The 'buttons' aren't actually buttons, they're views, so I can't send an action event.
How can I select the correct button with code?
Just call genderTapped directly, handing it the gesture recognizer already attached to the desired "button".
For example, if thisGenderButton is the one you want to "tap", say:
if let tap = thisGenderButton.gestureRecognizers?[0] as? UITapGestureRecognizer {
genderTapped(tap)
}
You can add this method in your customView like this,
Class CustomView: UIView {
public func select(_ value: Bool) {
self.backgroundColor = value ? .green: .red
}
}
and then in below method you can call select for the tapped view.
#objc private func genderTapped(_ sender: UITapGestureRecognizer) {
(sender.view as? CustomView)?.select(true)
}
I see that there are a ton of these questions, and I think I'm following the accepted Swift 3 methodology, but I'm still getting nothing. I can see that the UITapGestureRecognizer has been attached. Here's my code:
let tileClick = UITapGestureRecognizer(target: self, action: #selector(GameManagement.initiateTileClick(_:)))
newView.addGestureRecognizer(tileClick)
newView.isUserInteractionEnabled = true
func initiateTileClick(_ sender: UITapGestureRecognizer) {
print("initiate tile click")
}
A few things to note:
1) The view that I'm attaching the gesture recognizer to has a two views and a label within it that each cover the entire frame of the view, however, I tried attaching the recognizer to the label, which is the topmost child item and it still doesn't work.
2) Both the function that adds the recognizer and the function that is called on the tap are contained in an NSObject file. I have a variety of interconnected functions that I want to be able to call from multiple view controllers and would prefer to keep this in the separate NSObject file. The process worked when I had everything in a UIViewController file and stopped working when I moved the functions to the NSObject file.
3) I've tried changing GameManagement.initiateTileClick to self.initiateTileClick or just initiateTileClick and none of those worked.
If you are putting your views inside NSObject subclass then these views will lose their behaviors for UIResponder which manages the UI interactions as I am not able to see how you are adding these views to interface.
As you said, it was working inside ViewController because it manages view hierarchy and responder chain.
The solution would be to write extensions to separate code or better abstractions.
extension YourViewController {
newView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(GameManagement.initiateTileClick(_:))))
newView.isUserInteractionEnabled = true
func initiateTileClick(_ sender: UITapGestureRecognizer) {
print("initiate tile click")
}
}
Giving you an idea how the tap recogniser works.
Firstly add Tap gesture recogniser to your view controller. You have to put the object here as shown in the image.
Then control+drag the tap gesture object to your view and select delegate.
Then control+drag the recogniser to your swift file and action will be like this.
#IBAction func tapGesture(_ sender: UITapGestureRecognizer) {
}
Now you must have seen when you give some input to a text field, the keyboard appears. But if you press outside the text field, that is anywhere in the view, the keyboard hides. This is because of the tap gesture recogniser.
Consider you have a text field such that if you click in that text field, keyboard is appeared. But when you tap outside the textfield, the keyboard must hide.
Add this delegate
UITextFieldDelegate
Implement this:
#IBOutlet var phoneText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
exampleText.delegate = self
}
#IBAction func tapGesture(_ sender: UITapGestureRecognizer) {
exampleText.endEditing(true)
}
Obviously,this function is instance method.
func initiateTileClick(_ sender: UITapGestureRecognizer) {
print("initiate tile click")
}
-
UITapGestureRecognizer(target: self, action:#selector(GameManagement.initiateTileClick(_:)))
but thisGameManagement.initiateTileClick(_:) looks like a class is calling a class method!The target should be the caller of method.self can't call GameManagement.initiateTileClick(_:).
I'm sure that answer is near.
I'm new in swift and want to create simple app for iOS.
I have created view and add different elements on this view. Also added pan recognized for this view. I want to do different actions when user drag his finger over different element. For example when finger entered in button area to write in console, when dragged into label area - change labels's text. Also With this type realized swipe method of input text from keyboard. It must do in one touch that's why I use pan recognizer. But when I run my app, I can get finger position, but don't know how triggered function when need.
Hope for yours help
Thanx
class ViewController: UIViewController {
#IBOutlet var mainView: UIView!
#IBOutlet var gest: UIPanGestureRecognizer!
#IBOutlet var tap: UITapGestureRecognizer!
#IBOutlet weak var btn: UIButton!
#IBOutlet weak var btn2: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.addGestureRecognizer(self.gest)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func drAG(_ sender: UIPanGestureRecognizer) {
print(sender.location(in: self.view))
}
Looks like you have most everything you need. Now, just use the hitTest() method of any view's layer:
func moveEye(_ recognizer:UIPanGestureRecognizer) {
let p = recognizer.location(in: self)
if btn.layer.hitTest(p) != nil {
// finger panned over btn
}
}
I use hitTest() alot in a few apps. But beware - I usually see it associated with the tap gesture. (I use the pan gesture to move a subview.) I do not know how things will behave if you have two overlapping subviews that the user pans over.
I've set up a function for editing did end with a slider, but it doesn't look like it's being called. I've thrown a print statement into it, and a breakpoint. Is there something else that needs to be done to trigger a function when my user lets go of the slider?
#IBAction func sliderEditingDidEnd(sender: UISlider) {
print("did end");
}
Use the event "Value Changed". If you just want updates for the final value, alter UISlider.continuous
var slider = UISlider()
slider.continuous = false
//add slider to view
#IBAction func valueChanged(sender: UISlider) {
println("Value changed.")
}
//prints "Value changed." once upon releasing slider.
If the slider needs to be continuous, you can implement an event for UIControlEvent.TouchUpInside.
Or in code:
override func viewDidLoad() {
super.viewDidLoad()
mySlider.addTarget(self, action: "userReleasedSlider:", forControlEvents: UIControlEvents.TouchUpInside)
// Do any additional setup after loading the view, typically from a nib.
}
func userReleasedSlider(slider: UISlider) {
print("User released slider.")
}
I think what you are trying to do is to get the notification when the value is changed. Then you have to set event to 'Value Changed' not 'Editing Did End'.
If you set both Touch Up Inside and Touch Up Outside to point to your #IBAction then you can get the function to fire when the user finishes sliding and keep the slider as continuous.
I'm trying to add a UIView subview into a UIViewController, and that UIView has a UISwitch that I want the user to be able to toggle. Based on the state, a UITextField's value will toggle back and forth. Here is the subview (InitialView):
import UIKit
class InitialView: UIView {
// All UI elements.
var yourZipCodeSwitch: UISwitch = UISwitch(frame: CGRectMake(UIScreen.mainScreen().bounds.width/2 + 90, UIScreen.mainScreen().bounds.height/2-115, 0, 0))
override func didMoveToSuperview() {
self.backgroundColor = UIColor.whiteColor()
yourZipCodeSwitch.setOn(true, animated: true)
yourZipCodeSwitch.addTarget(ViewController(), action: "yourZipCodeSwitchPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.addSubview(yourZipCodeSwitch)
}
}
If I want to have it's target properly pointing at the below function, where should I either set the target or include this function? I tried:
Setting the target in the UIViewController instead of the UIView
Keeping the function in the UIView
Here's the function:
// Enable/disable "Current Location" feature for Your Location.
func yourZipCodeSwitchPressed(sender: AnyObject) {
if yourZipCodeSwitch.on
{
yourTemp = yourZipCode.text
yourZipCode.text = "Current Location"
yourZipCode.enabled = false
}
else
{
yourZipCode.text = yourTemp
yourZipCode.enabled = true
}
}
And here is where I'm loading it into the UIViewController:
// add initial view
var initView : InitialView = InitialView()
// Execute on view load
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.addSubview(initView)
}
Any help is much appreciated - thanks!
Yeah, the didMoveToSuperView() placement doesn't make much sense. So you're creating a random, totally unconnected ViewController instance to make the compiler happy but your project sad. Control code goes in controllers, view code goes in views.
You need in your real ViewController:
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(initView)
// Note 'self' is the UIViewController here, so we got the scoping right
initView.yourZipCodeSwitch.addTarget(self, action: "yourZipCodeSwitchPressed:", forControlEvents: .ValueChanged)
}
Also, .TouchUpInside is for UIButtons. Toggle switches are much more complicated, so their events are different. Touching up inside on a toggle switch's current setting can and should do nothing, whereas touchup inside on the opposite setting triggers the control event above. iOS does all the internal hit detection for you.