Long Press Recognize Gesture via Button - Swift 3 - ios

I'm new to Swift and I'm trying to make timer(in the label) that starts with a long press on the button. At the same time I want to change the long press button image when press the long press button. I leave button, I want the button revert back.
What might be wrong?
#IBOutlet weak var myBtn: UIButton!
func initGesture()
{
{ let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap(_:)))
myBtn.addGestureRecognizer(longGesture)
}
}
func TimerAction()
{
Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(longTap), userInfo: nil, repeats: false)
myBtn.setImage(UIImage(named: "xxx.png"), for: .normal)
}
#IBOutlet weak var lbl: UILabel!
func start()
{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController2.updateTime as (ViewController2) -> () -> ())), userInfo: nil, repeats: true)
}
func updateTimer () {
count += 1
let hours = Int(count) / 3600
let minutes = Int(count) / 60 % 60
let seconds = Int(count) % 60
label.text = String(format: "%02i:%02i:%02i",hours,minutes,seconds)
}
func reset()
{
timer.invalidate()
count = 0
label.text = "00:00:00"
}

You can get TouchUpInside and TouchUpOutside also TouchDown action of button don't use the gesture.
class ViewController: UIViewController {
#IBOutlet weak var lbl: UILabel!
#IBOutlet weak var myBtn: UIButton!
var timer: NSTimer!
override func viewDidLoad() {
super.viewDidLoad()
myBtn.addTarget(self, action: "buttonDown:", forControlEvents: .TouchDown)
myBtn.addTarget(self, action: "buttonUp:", forControlEvents: [.TouchUpInside, .TouchUpOutside])
}
func buttonDown(sender: AnyObject) {
singleFire()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "rapidFire", userInfo: nil, repeats: true)
}
func buttonUp(sender: AnyObject) {
timer.invalidate()
count = 0
label.text = "00:00:00"
}
func singleFire() {
myBtn.setImage(UIImage(named: "xxx.png"), for: .normal)
}
func rapidFire() {
count += 1
let hours = Int(count) / 3600
let minutes = Int(count) / 60 % 60
let seconds = Int(count) % 60
label.text = String(format: "%02i:%02i:%02i",hours,minutes,seconds)
}
}

You should implement button events instead of using the gesture recognisers here. The button events i talk about are TouchDown and TouchUpInside. TouchDown will tell you when a button is being pressed and touchupinside will tell you when the user lifted their finger from button.
So you will change the button image and start your timer on touchdown event. Then you will revert back on touchupinside event.
https://developer.apple.com/documentation/uikit/uicontrolevents

Try this,
set first the image of the button depending on its state.
self.arrowIcon.setImage(UIImage(named: "normalImage.png"), for: .normal)
self.arrowIcon.setImage(UIImage(named: "pressedImage.png"), for: .highlighted)

Related

How to change the collor of a button once timer runs out?

Here is the code that I am using, at the bottom of the code is my timer it is a timer counting up and once it hits 60 minutes I would like for a button to turn red.
import UIKit
import AVFoundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func btnPressed1(_ sender: UIButton) {
sender.backgroundColor = sender.backgroundColor == UIColor.red ? UIColor.black : UIColor.red
}
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var progressBar1: UIProgressView!
let start = 5
var timer = Timer()
var player: AVAudioPlayer!
var totalTime = 0
var secondsPassed = 0
#IBAction func startButtonPressed(_ sender: UIButton) {
let startB = sender.titleLabel?.text
totalTime = start
progressBar1.progress = 0.0
secondsPassed = 0
titleLabel.text = "coffee timer"
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
}
#objc func updateTimer() {
if secondsPassed < totalTime {
secondsPassed += 1
progressBar1.progress = Float(secondsPassed) / Float(totalTime)
print(Float(secondsPassed) / Float(totalTime))
} else {
timer.invalidate()
titleLabel.text = "check coffee"
let url = Bundle.main.url(forResource: "alarm_sound", withExtension: "mp3")
player = try! AVAudioPlayer(contentsOf: url!)
player.play()
}
}
}
I need the button to turn the color red after my timer ends and if possible when the button is pressed have the color turn back to black.
You could add an IBOutlet to the button, and then use that outlet to update the button in your updateTimer routine.
An alternative to adding an IBOutlet to the button is to pass the button as the userInfo: parameter of the Timer.
You can pass anything you want as the userInfo: and right now you're just passing nil. If you change nil to sender, then the button will be passed along to the Timer.
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self,
selector: #selector(updateTimer), userInfo: sender,
repeats: true)
Then, add the Timer parameter to updateTimer:
#objc func updateTimer(t: Timer) {
if let button = t.userInfo as? UIButton {
button.backgroundColor = .red
}
}
Making use of userInfo makes even better sense if you have multiple buttons that share the same updateTimer code. By creating a structure to hold the secondsPassed and button and passing that structure as userInfo:, you could have multiple buttons using multiple timers at the same time and each Timer would know which button it was assigned to.

Adding a navigation bar refresh button with timer in swift 4

I'm trying to add a navigation bar refresh button to update my table view content that coming from JSON and beside that i want my table view keep updating automatically every 5 minutes if the user hasn't pressed the refresh button and changing the button to be an Activity indicator to let the user that is been updating when the table view updating the data
my refresh button IBAction code :
#IBAction func refreshButton(_ sender: Any) {
self.getCoinData()
self.coinTableView.reloadData()
}
Swift 4+
Create Timer & on completion of webservice show the reload icon
class ViewController: UIViewController {
var timer: Timer!
var refreshBarButtonActivityIndicator: UIBarButtonItem!
var refreshBarButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
barItemSetUp()
}
func barItemSetUp() {
///SettingReloadButton
let image = UIImage(named: "refresh-25")?.withRenderingMode(.alwaysOriginal)
refreshBarButton = UIBarButtonItem(image: image, style: .plain, target: self, action: nil)
///Setting activity Indicator
let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(activityIndicatorStyle: .gray)
refreshBarButtonActivityIndicator = UIBarButtonItem(customView: activityIndicator)
activityIndicator.startAnimating()
toogleIndicator()
}
deinit {
timer?.invalidate()
}
func toogleIndicator() {
// 5 minutes = 300 seconds //write here 300
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(refreshNow), userInfo: nil, repeats: true)
}
#objc func refreshNow() {
//here i am creating delay for sample purpose
//here write your webservice code on completion of webservice change bar button item
self.navigationItem.rightBarButtonItem = refreshBarButtonActivityIndicator
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
self.navigationItem.rightBarButtonItem = self.refreshBarButton
}
}
}
Output:-
First add the timer which is refresh data every 5 minutes. At timer, you add the web service.
var timer = Timer()
func runTimer(){
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(self.updateTimer)), userInfo: nil, repeats: true)
}
func updateTimer() {
self.getCoinData()
self.coinTableView.reloadData()
}
override func viewWillAppear(_ animated: Bool){
runTimer()
}
To reload your UITableView after every 5 minutes, you need to schedule a Timer that executes a block of code every 5 minutes, i.e.
var timer: Timer?
override func viewDidLoad()
{
super.viewDidLoad()
self.timer = Timer.scheduledTimer(withTimeInterval: 300, repeats: true, block: {[weak self] (tt) in
self?.getCoinData()
self?.coinTableView.reloadData()
})
timer?.fire()
}
deinit
{
timer?.invalidate()
}
You can change the time interval according to your requirement. You need to give the time interval in seconds.

When push the UIButton, change image in the image view

I'm new to Swift and I am trying the make a button. I want to when i push the button start the timer and change image in the image view.
My code;
#IBOutlet weak var label: UILabel!
func start()
{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController2.updateTime as (ViewController2) -> () -> ())), userInfo: nil, repeats: true)
}
func updateTimer () {
count += 1
let hours = Int(count) / 3600
let minutes = Int(count) / 60 % 60
let seconds = Int(count) % 60
label.text = String(format: "%02i:%02i:%02i",hours,minutes,seconds)
}
func reset()
{
timer.invalidate()
count = 0
label.text = "00:00:00"
}
#IBAction func buttonPressed(sender : UIButton)
{
if sender.currentTitle == " "
{
sender.setTitle("", for: UIControlState.normal)
reset()
}
else
{
sender.setTitle(" ", for: UIControlState.normal)
start()
}
}
#IBOutlet weak var image: UIImageView!
#IBAction func tick(sender: UIButton)
{
if checked
{
sender.setImage( UIImage(named:"Rectangle1.png"), for: [])
checked = false
}
else
{
sender.setImage(UIImage(named:"Rectangle2.png"), for: [])
checked = true
}
}
Unfortunately when i push the button, changes the picture of the button. How can i change the image in the image view?
You are setting the senders image.. which is your UIButton.. change this part of your code
wrong:
sender.setImage(UIImage(named:"Rectangle1.png"), for: [])
...
sender.setImage(UIImage(named:"Rectangle2.png"), for: [])
right:
image.image = UIImage(named:"Rectangle1.png")
...
image.image = UIImage(named:"Rectangle2.png")
Define the button as a IBOutlet and set a new image:
button.setImage(UIImage(named: "Rectangle1.png"), for: .normal)

How to make a timer that starts with a long press on the button?

I'm currently learning Swift and iOS programming. I want to make a timer that starts with a long press on the button. At the same time I want to change the UIButton image. I leave button, I want the button revert back. Is this possible?
You absolutely can do this. You have to add LongPressGestureRecognizer:
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(yourAction))
button.addGestureRecognizer(longPress)
And then in your func start the timer and change the button's image:
func yourAction(){
Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(timerAction), userInfo: nil, repeats: false)
button.setImage(UIImage(named: "yourImage"), for: .normal)
}
func timerAction(){
//Do whatever you want
}
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
I will add a code for demonstration:
#IBOutlet var button: UIButton!
var timer: Timer!
var speedAmmo = 100
#IBAction func buttonDown(sender: AnyObject) {
singleFire()
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector:#selector(rapidFire), userInfo: nil, repeats: true)
}
#IBAction func buttonUp(sender: AnyObject) {
timer.invalidate()
}
func singleFire() {
if speedAmmo > 0 {
speedAmmo -= 1
print("bang!")
} else {
print("out of speed ammo, dude!")
timer.invalidate()
}
}
func rapidFire() {
if speedAmmo > 0 {
speedAmmo -= 1
print("bang!")
} else {
print("out of speed ammo, dude!")
timer.invalidate()
}
}
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action:#selector(buttonDown(sender:)), for: .touchDown)
button.addTarget(self, action:#selector(buttonUp(sender:)), for: [.touchUpInside, .touchUpOutside])
}
Please try and let me know!

SIGABRT error when using NSTimer, Swift 2 Xcode 7

I have a function that flashes a button. The function is inside a for i loop, which is in the viewDidLoad function. I also have an NSTimer that calls the function repeatedly flashing a different button each time. However I am getting a SIGABRT error when I run this. If you are going to ask, I have made sure that the connections with my buttons are solid, no cut off connections.
var computerChoices = [Int](count: 11, repeatedValue: 0)
var randomIndex = 0
var pcChoice = 0
var lit = [b0o,b1o,b2o,b3o,b4o,b5o,b6o,b7o,b8o]
var litIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
for i in 1...10{
print(randomIndex)
print(computerChoices)
var buttonChoice = lit[randomIndex]
randomIndex = Int(arc4random_uniform(UInt32(lit.count)))
computerChoices[i] = randomIndex
print("yoyoyo")
func flashingButtons(){
var one = computerChoices[pcChoice]
lit[one].setImage(UIImage(named: "redb.png"), forState: UIControlState.Normal)
pcChoice += 1
}
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("flashingButtons"), userInfo: nil, repeats: true)
}
}
Put out the flashingButtons function out of the viewDidLoad. The timer find the function and couldn't find it if it is embedded.
override func viewDidLoad() {
super.viewDidLoad()
for i in 1...10{
print(randomIndex)
print(computerChoices)
var buttonChoice = lit[randomIndex]
randomIndex = Int(arc4random_uniform(UInt32(lit.count)))
computerChoices[i] = randomIndex
print("yoyoyo")
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("flashingButtons"), userInfo: nil, repeats: true)
}
}
func flashingButtons(){
var one = computerChoices[pcChoice]
lit[one].setImage(UIImage(named: "redb.png"), forState: UIControlState.Normal)
pcChoice += 1
}
You should put flashingButtons() out side viewDidLoad. And in it you make sure that out of range don't happen because pcChoice increase over time.
func flashingButtons(){
var one = computerChoices[pcChoice]
lit[one].setImage(UIImage(named: "redb.png"), forState: UIControlState.Normal)
if pcChoice >= 10 {
pcChoice = 0
return
}
pcChoice += 1
}

Resources