Tap and Hold UIButton in Swift? - ios

I am trying to get a UIButton to repeat the code over and over until the user releases the button. I have an up arrow in a game and when it is tapped, a space ship will go up until it is released. Here is the code for my button:
//at top of page
let upArrow = UIButton()
//in viewdidload()
let upArrowImage = UIImage(named: "upArrow") as UIImage?
upArrow.setImage(upArrowImage, forState: .Normal)
upArrow.frame = CGRectMake(10, 220, 90, 40)
upArrow.addTarget(self, action: "upArrowTouched:", forControlEvents: UIControlEvents.TouchUpInside)
self.view?.addSubview(upArrow)
//outside of viewDidLoad()
func upArrowTouched(sender:UIButton!){
spaceship.position = CGPointMake(spaceship.position.x, spaceship.position.y + 3)
}
Any suggestions??

You need to implement your own solution for this, something along the lines
1- User touches down (UIControlEvent touchDown), you start a time that fires every x secs/millisecs
2- Timer will fire the action over and over
3- User touches up UICOntrolEvent touchUp, you cancel your timer
So you bind those 2 events to different functions, and start/kill your timers with appropriate actions
How that helps
Daniel

Related

iOS/Swift: How to implement doubletap action for backButton? [duplicate]

This question already has answers here:
on single tap UIBarButton display toast and on double tap back action need to perform
(3 answers)
Closed 4 years ago.
I'm trying to implement a custom back button for every ViewController in my app. I want it to have two actions. If the button gets single tapped, it should give toast warning. If the button gets double tapped it should go back to ViewController.
How can I achieve this for only the backbutton in swift?
Try this to Work with bar Button with single and Double Tap
/// Tap Gesture to Handle Double Tap
let tapGesture : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(SourceVC.handleGesture(getsure:)))
tapGesture.numberOfTapsRequired = 2
/// Custom Button That With Handle two actions
let customButtonn : UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
customButtonn.setTitleColor(UIColor.blue, for: .normal)
customButtonn.setTitle("button", for: .normal)
customButtonn.addTarget(self, action: #selector(SourceVC.navButton(sender:)), for: .touchUpInside)
customButtonn.addGestureRecognizer(tapGesture)
/// Create a Custom bar Button
let navLeftButton = UIBarButtonItem()
navLeftButton.customView = customButtonn
/// Assign it to navigation Bar
self.navigationItem.leftBarButtonItem = navLeftButton
My custom Button Actions in SourceVC Class
/// Single Tap
#objc func navButton(sender:UIButton){
print("navButtonTapped Once")
}
/// Double Tap
#objc func handleGesture(getsure:UITapGestureRecognizer){
print("navButtonTapped twice")
}
Simulator Output:
Console output:
Note - Doing this will move default back occur with the bar and you need to design it custom way so it appear like that as Shown in Simulator output - button appear without that back image
You cannot modify the actions and behavior for BackBarButtonItem, what you can do is create a your own UIBarButtonObject and assign it as your leftBarButtonItem while giving it your own selector
One thing to note is that this will remove the stock back button image.
Try this:
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(actingFunction))
DoubleTap.numberOfTapsRequired = 2
barButton.addGestureRecognizer(doubleTap)

Get sender's tag of a programmatically set button ios

I wish to get the sender's tag of a programmatically set button.
i have set many buttons with tags programmatically and when the app is running and one of the buttons is tapped i wish to get the sender's tag back.
An example in my project. This #IBAction is connected with 7 buttons, from Monday to Sunday.
#IBAction func OnBtnWeekDay(_ sender: UIButton) {
let day = sender.tag - 1
//....
}
Main point is the parameter of function: (_ sender: UIBUtton)
This is simple. Make a button programmatically e.g in viewdidload and set it's tag and add action to it using the following code
//make a button programmatically e.g in viewdidload
let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
button.setTitle("Test Button", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
//set tag to any integer value
button.tag = 1
//add to view controllers view or where ever you want
self.view.addSubview(button)
#objc func buttonAction(sender: UIButton!) {
print("Button tapped")
print("Buttons Tag is \(sender.tag)")
}
Tested and verified this solution my self. see the screen shot

Is there a different option than addTarget on a UIButton

addTarget
So I know that you can use addTarget on a button
like so:
import UIKit
class ViewController: UIViewController {
func calledMethod(_ sender: UIButton!) {
print("Clicked")
}
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(frame: CGRect(x: 30, y: 30, width: 60, height: 30))
btn.backgroundColor = UIColor.darkGray
btn.addTarget(self, action: #selector(self.calledMethod(_:)), for: UIControlEvents.touchUpInside)
self.view.addSubview(btn)
}
}
This works absolutely fine but I was just wondering is there another way to detect when something is clicked and run some code when that happens.
You can add button in the storyboard and create an outlet for it's action.
#IBAction func buttonAction(_ sender: UIButton) {
//implement your code here
}
A button is a subclass of UIControl. A UIControl is designed to use target/action to specify code to run when the specified action occurs. If you don't want to use that mechanism, you have to create an equivalent.
You could attach a tap gesture recognizer to some other object and set it's userInteractionEnabled flag to true, but gesture recognizers ALSO use the target/action pattern.
My suggestion is to "stop worrying and learn to love the button." Just learn to use target/action.
Another possibility: Create a custom subclass of UIButton that sets itself up as it's own target at init time (specifically in init(coder:) and init(frame:), the 2 init methods you need to implement for view objects.) This button would include an array of closures that its action method would execute if the button was tapped. It would have methods to add or remove closures. You'd then put such a button in your view controller and call the method to add the closure you want.
You can also have a look at RxSwift/RxCocoa or similar. All the changes and actions are added automatically and you can decide if you want to observe them or not.
The code would look something like this:
let btn = UIButton(frame: CGRect(x: 30, y: 30, width: 60, height: 30))
btn.backgroundColor = UIColor.darkGray
btn
.rx
.tap
.subscribe(onNext: {
print("Clicked")
}).disposed(by: disposeBag)
view.addSubview(btn)

How to change UIButton label programmatically

When I first run my app, I retrieve a number from my server and display it for my UIButton label. Think of this as a notification number displayed on a red UIButton.
When I remove a notification within the app, I want my UIButton label decrement by 1. I am able to get the decremented number from the server after I delete a notification, but I can't display this new number on the UIButton. The button always displays the number when the app is first fired.
I call makeButtonView() method after I remove a notification to update the UIButton
func makeButtonView(){
var button = makeButton()
view.addSubView(button)
button.tag = 2
if (view.viewWithTag(2) != nil) {
view.viewWithTag(2)?.removeFromSuperview()
var updatedButton = makeButton()
view.addSubview(updatedButton)
}else{
println("No button found with tag 2")
}
}
func makeButton() -> UIButton{
let button = UIButton(frame: CGRectMake(50, 5, 60, 40))
button.setBackgroundImage(UIImage(named: "redBubbleButton"), forState: .Normal)
API.getNotificationCount(userID) {
data, error in
button.setTitle("\(data)", forState: UIControlState.Normal)
}
button.addTarget(self, action: "targetController:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}
Use this code for Swift 4 or 5
button.setTitle("Click Me", for: .normal)
I need more information to give you a proper code. But this approach should work:
lazy var button : UIButton = {
let button = UIButton(frame: CGRectMake(50, 5, 60, 40))
button.setBackgroundImage(UIImage(named: "redBubbleButton"), forState: .Normal)
button.addTarget(self, action: "targetController:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}()
func makeButtonView(){
// This should be called just once!!
// Likely you should call this method from viewDidLoad()
self.view.addSubview(button)
}
func updateButton(){
API.getNotificationCount(userID) {
data, error in
// be sure this is call in the main thread!!
button.setTitle("\(data)", forState: UIControlState.Normal)
}
}
There have been some updates since Swift 4. This works for me:
self.button.setTitle("Button Title", for: UIControl.State.init(rawValue: 0))
Replace button with your IBOutlet name. You can also use a variable or array in place of the quoted text.
It's fairly simple ...
import UIKit
class ViewController: UIViewController {
#IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.setTitle("hello world", forState: UIControlState.Normal)
}
}
I believe if you set the state to normal, the value will propagate by default to other states so long as you haven't explicitly set a title for those states.
Said differently, if you set it for normal, it should also display this title when the button enters additional states
UIControlState.allZeros
UIControlState.Application
UIControlState.Disabled
UIControlState.Highlighted
UIControlState.Reserved
UIControlState.Selected
Lastly, here's Apple's documentation in case you have other questions.
Since your API call should be running on a background thread you need to dispatch your UI update back to the main thread like this:
DispatchQueue.main.async {
button.setTitle(“new value”, forState: .normal)
}
After setting the title, just a simple redraw of the button will do:
button.setNeedsDisplay();

Insert a button and load a second view programmatically using Swift

I want to, programmatically, add a button to a view and then when the user press this button a second view called "Giraanam" is loaded. I managed to write the code to display the button, but I cannot discover how to make it load the second view... Can anyone please help me?
The code I tried so far is:
let button = UIButton.buttonWithType(UIButtonType.System) as UIButton
button.frame = CGRectMake(20, 25, 34, 34)
button.backgroundColor = UIColor.greenColor()
button.setBackgroundImage(UIImage(named:"Back_Resultados.png"),forState: UIControlState.Normal)
button.addTarget(self, action: "Giraanam", forControlEvents: UIControlEvents.TouchUpInside)
self.addSubview(button)
You need to implement function Giraanam to create a new view and add to another view. Example:
func Giraanam() {
let newView = UIView()
// customise your view
self.view.addSubview(newView)
}

Resources