I have a UISlider and AvAudioPlayer, currently I am able to set the UISlider to the currentTime of a AvAudioPlayer like so:
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: (#selector(RecordController.updateTimer)), userInfo: nil, repeats: true)
#objc func updateTimer() {
if(audio != nil) {
audioSlider.setValue(Float((self.audio?.currentTime)! / (self.audio?.duration)!), animated: false)
}
}
But how would I set the currentTime of the AVAudioPlayer when changing the value of the UISlider?
#IBAction func audioSliderUpdated(_ sender: Any) {
}
You can use the currentTime property of AVAudioPlayer:
#IBAction func audioSliderUpdated(_ sender: Any) {
if let slider = sender as? UISlider {
self.audio?.currentTime = slider.value
}
}
Use this, slider value changes according to time
#IBAction func slide(_ sender: UISlider) {
self.audio.currentTime = TimeInterval(slider.value)
}
You have to convert your slider value to a new value which based on your media file.
First, you must config your slider values to work in normalized values (from 0.0 to 1.0)
/// call this on viewDidLoad: configDefaults(for: audioSlider)
func configDefaults(for slider: UISlider)
slider.minimumValue = 0.0
slider.maximumValue = 1.0
}
Then you should calculate currentTime from audioSlider.value and duration then set it to the player.currentTime.
#IBAction func audioSliderUpdated(_ sender: Any) {
guard let slider = sender as? UISlider,
let player = audio else {
return
}
player.currentTime = Double(slider.value) * player.duration
}
Related
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.
I'm making timer application and I have countdown slider.
I want to get current position of slider when I pause it.
I tried to use Int(value.sender) but I have this error message:
sliderOutlet.setValue(seconds, animated: true)
Cannot invoke 'setValue' with an argument list of type '(Int, animated: Bool)'
#IBOutlet weak var sliderOutlet: UISlider!
#IBAction func slider(_ sender: UISlider)
{
seconds = Int(sender.value)
timeScreen.text = timeString(time: TimeInterval(seconds))
}
#IBAction func startButton(_ sender: UIButton)
{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(CountdownViewController.counter), userInfo: nil, repeats: true)
sliderOutlet.isHidden = true
}
#IBAction func pauseButton(_ sender: UIButton) {
stop()
timeScreen.text = timeString(time: TimeInterval(seconds))
sliderOutlet.setValue(seconds, animated: true)
}
func stop()
{
timer.invalidate()
sliderOutlet.isHidden = false
}
I expected when I tapped on pauseButton, sliderOutlet will show current seconds' position.
The setValue(_:animated:) method expects a Float, not an Int.
sliderOutlet.setValue(Float(seconds), animated: true)
Make sure the value of seconds is between the minimum and maximum values you have set for the slider which default to 0.0 and 1.0 respectively.
I have created a simple timer in swift 3.
For some reason though, even though it works the label display too many numbers :S it displays a crazy amount of 9's. Is this to do with rounding?
Thanks, code below :)
var swiftTimer : Timer?
var swiftCounter: Double = 0.00
#IBOutlet weak var displayTimeLBL: UILabel!
#IBAction func start(_ sender: Any) {
swiftTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(ViewController.updateCounter), userInfo: nil, repeats: true)
}
#IBAction func stop(_ sender: Any) {
if swiftTimer != nil{
swiftTimer?.invalidate()
swiftCounter = 0.00
updateLabel()
swiftTimer = nil
}
}
func updateLabel(){
displayTimeLBL.text = String(swiftCounter)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func updateCounter(){
swiftCounter+=0.01
round(swiftCounter)
updateLabel()
}
enter image description here
Simplest Solution:
func updateCounter(){
swiftCounter+=0.01
round(swiftCounter)
swiftCounter = Double(round(100*swiftCounter)/100)
updateLabel()
}
If you want two fractions then you can use swiftCounter.round(2) instead of round(swiftCounter)
to update the text use:
displayTimeLBL.text = "\(swiftCounter.round(2))"
Here is the Double extension used:
extension Double {
func round(_ places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}
Ive created a timer in swift to move a UISlider from one end to another again and again when a button is pressed. But I'm always getting a breakpoint at the timer line, although everything should be right.
#IBAction func setSliderValue(_ sender: UIButton){
mytimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}
func timerAction(){
let Range = slider.maximumValue - slider.minimumValue;
let Increment = Range/100;
let newval = slider.value + Increment;
if(Increment >= slider.maximumValue)
{
slider.setValue(newval, animated: true)
}
else
{
slider.setValue(0, animated: true)
}
}
The check of your function is incorrect.
func timerAction(){
let range = slider.maximumValue - slider.minimumValue
let increment = range/100
let newval = slider.value + increment
if newval <= slider.maximumValue {
slider.setValue(newval, animated: true)
} else {
slider.setValue(slider.minimumValue, animated: true)
}
}
Also, in your event handler, should invalidate the timer (if it's not nil) first before instancing a new one.
Its working now with the following code, though the slider is only moving from left to right until it gets invalidated.
#IBAction func setSliderValue(_ sender: UIButton){
mytimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
/*slider.setValue(100, animated: true)
print("The value of the slider is now \(slider.value)")
sliderValue = Int(slider.value)*/
}
func timerAction(){
let Range = slider.maximumValue - slider.minimumValue;
let Increment = Range/100;
let newval = slider.value + Increment;
if(Increment <= slider.maximumValue)
{
slider.setValue(newval, animated: true)
print("The value of the slider is now \(slider.value)")
sliderValue = Int(slider.value)
}
else if (Increment >= slider.minimumValue)
{
slider.setValue(newval, animated: true)
}
}
Hope this helps if someone else needs help on a task "starting a count down timer on a button click".
Timer itself has to be declared inside of the button code and additionally create a Obj-C function to update the timer that will be connected trough the #selector.
class ViewController: UIViewController {
var myTimer = Timer()
var secondsToCount = 100
#IBAction func buttonTapped(_ sender: UIButton) {
myTimer.invalidate()
myTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
}
#objc func updateTimer() {
secondsToCount -= 1
timerDisplayed.text = String(secondsToCount)
}
}
timerDisplayed is a label that I connected to see the value of the timer on the screen of the app.
SWIFT 5.3 & Xcode 12.0.1
I'm trying to make a simple timer in iOS using Swift.
The program is working fine but whenever my START UIButton is pressed the function of timer starts and runs multiple time as much as the button is pressed.
I want to disable the START UIButton as soon as the timer function starts so that it does not run multiple times.
Please help me for the same.
This is my code of ViewController
import UIKit
class ViewController: UIViewController {
var time = 0.0
var timer = Timer()
#IBOutlet weak var lbl: UILabel!
#IBAction func start(_ sender: UIButton)
{
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
}
#IBAction func pause(_ sender: UIButton)
{
timer.invalidate()
}
#IBAction func reset(_ sender: UIButton)
{
timer.invalidate()
time = 0.0
lbl.text = ("0")
}
func action()
{
time += 0.1
lbl.text = String(time)
}
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.
}
}
To disable your button you can just set it's isUserInteractionEnabled property in start function:
#IBOutlet weak var startButton: UIButton!
#IBAction func start(_ sender: UIButton) {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
startButton.isEnabled = false
}
Then set it back to true in pause and reset methods:
#IBAction func pause(_ sender: UIButton) {
timer.invalidate()
startButton.isEnabled = true
}
#IBAction func reset(_ sender: UIButton) {
timer.invalidate()
startButton.isEnabled = true
//the rest of your code
}
The most reliable way to ensure that the timer is only started and stopped once is writing two methods which check the current state (timer is not nil if it's currently running):
var timer : Timer?
func startTimer()
{
guard timer == nil else { return }
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
// disable start button
}
func stopTimer()
{
guard timer != nil else { return }
timer!.invalidate()
timer = nil
// enable start button
}
In the methods you can enable/disable the button(s) accordingly.