I'm writing a music player using Swift, but when I'm tried to auto scroll the lyric, I found something weird.
I use a NSTimer to trigger the scroll:
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "updateTime", userInfo: nil, repeats: true)
func upadate is:
let offset = lyricScrollView.contentOffset
lyricScrollView.setContentOffset(CGPoint(x: offset.x, y: offset.y + 25), animated: true)
but when I change the time interval to 0.1 like this:
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "updateTime", userInfo: nil, repeats: true)
I found that my scrollview doesn't scroll 10x faster than before, instead, it scrolls a little every 0.1 seconds, not 25 points every 0.1 seconds. If I set animated to false, the problem is gone.
Could someone tell me why this happens?
Related
I am trying to move my collection view vertically 5px at a time using content offset using time interval trigger but it's not animating, my code for that is
timer = Timer.init(timeInterval: 1.0, target: self, selector: #selector(animateScroll), userInfo: nil, repeats: true)
#objc func animateScroll() {
self.previousOffset = self.collectionView.contentOffset.y
self.collectionView.contentOffset.y = self.previousOffset + 5
}
just use method setContentOffset:animated:
I have a Timer that fires every 1.0 seconds. Every time it fires, a TimeInterval variable gets set to Date.timeSinceReferenceDate, and when I pause the timer, another TimeInterval variable also gets set to Date.timeSinceReferenceDate and the timer is invalidated.
When I press the start button again, I want it to resume from where it left off (i.e. if you paused 0.5 seconds before it fired again, it should take 0.5 seconds for it to fire when you resume, not the 1.0 it currently does).
Here's how my code looks:
if (elapsedTime - beginTime) < 1.0 {
leftoverTime = elapsedTime - beginTime
timer = Timer.scheduledTimer(timeInterval: leftoverTime, target: self, selector: #selector(decreaseTime), userInfo: nil, repeats: false)
let fireDate = Date().addingTimeInterval(leftoverTime)
timer = Timer.init(fireAt: fireDate, interval: 1.0, target: self, selector: #selector(decreaseTime), userInfo: nil, repeats: true)
}
I imagine I need to do something with a Run Loop, but isn't there a way to just do a scheduled timer with a fire date? If I do the fire() method, it naturally only runs once and doesn't loop.
Hope someone can shine some light on this.
Thank you.
Edit
I have a UIViewPropertyAnimator
var animator: UIViewPropertyAnimator? = nil
When I start the timer, I first check if it's nil
animator == nil {
animator = UIViewPropertyAnimator(duration: TimeInterval(timeSec), curve: .linear) {
self.view.layoutIfNeeded()
}
}
And then the timer starts initially
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(decreaseTime), userInfo: nil, repeats: true)
In the method for decreasing time, I change the constraints and start the animation
self.timeTrailing.constant = screenSize / 2
self.timeLeading.constant = screenSize / 2
animator?.startAnimation()
At this point it's all good, but when I then hit the pause button and pause the animation (and invalidating the timer), resuming them means they're no longer in sync. I imagine it's because you won't hit an interval of exactly 0.1 when you press it, but rather 0.03, 0.07 etc.
animator?.pauseAnimation()
timer?.invalidate()
How do I ensure that they're always synced up, no matter when and how many times you pause it before it's finished?
Excuse me, if it is a stupid question, but i'm just trying to understand GCD.
I tried to do a simple thing: UITableViewController with one UITableViewCell and UIProgressView on the cell. And this progressView should update every second.
In cellForRowAtIndexPatch I did this
let cell = tableView.dequeueReusableCellWithIdentifier("onlyCell", forIndexPath: indexPath) as! OnlyTableViewCell
cell.runChanges()
return cell
In runChanges function I just create timer
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("doSomething"), userInfo: nil, repeats: true)
And doSomething looks like this:
func doSomething() {
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.rawValue),0)) {
if self.i >= 100 {
self.timer!.invalidate()
return
}
++self.i
dispatch_async(dispatch_get_main_queue()) {
self.prgrs.progress = Float(self.i)/100.0
print(self.i)
}
}
}
So I thought that it would work all the time, while I interact (maybe) with the UI. And it works quite good while I don't touch it. But when I interact with UI, for example, scroll UITableView and hold my finger(mouse in simulator) on the screen, it freezes.
I thought if now it is 22% and I will scroll it and hold my finger for 10 seconds it maybe should continue from about 32% but it shows 23%.
Sorry for my English and stupidness.
Images and source here.
I had a similar issue with NSTimer, adding your timer to mainRunLoop should fix it.
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("doSomething"), userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
i want to display values 1-10 repeatedly in UILable with animation user should be able to see the fluctuation of the values slowly how can i achieve this functionality ?
You can use :
var timer : NSTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "change_label", userInfo: nil, repeats: true)
func change_label()
{
count = count+1
label.text = String(format: "%d",count)
}
I have a timer in my application that triggers a certain event:
myTimer = NSTimer.scheduledTimerWithTimeInterval(10, target: self,
selector: "searchForDrivers:", userInfo:nil, repeats: true)
The first time the timer is triggered, it has a delay of 10 ms. I don’t want the delay on the first timer trigger, but I'd like the second trigger to be delayed by 10 ms. How can I achieve this?
First schedule the timer as you've done.
timer = NSTimer.scheduledTimerWithTimeInterval(
10.0, target: self,
selector: "searchForDrivers:",
userInfo: nil,
repeats: true
)
Then, immediately afterwards, fire timer.
timer.fire()
According to the documentation,
You can use this method to fire a repeating timer without interrupting its regular firing schedule. If the timer is non-repeating, it is automatically invalidated after firing, even if its scheduled fire date has not arrived.
See the NSTimer Class Reference for more information.
One more way to do that is you can use two timers for that like:
var myTimer = NSTimer()
var secondTimer = NSTimer()
After that you can set two timers this way:
myTimer = NSTimer.scheduledTimerWithTimeInterval(0, target: self,
selector: "searchForTRuckDrivers", userInfo:nil, repeats: false)
secondTimer = NSTimer.scheduledTimerWithTimeInterval(10, target: self,
selector: "searchForTRuckDrivers", userInfo:nil, repeats: true)
You can set first timer with delay 0 which will not repeat again while set another timer with delay 10 and it will repeat again and again.
After that in method you can invalidate first timer this way:
func searchForTRuckDrivers() {
if myTimer.valid {
myTimer.invalidate()
}
}
This will remove first timer but second timer will call this method with delay.
Hope it will help.