My app have circle animation from the framework connected to the timer. When the timer is running, the animation starts. If the app goes into the background, the animation stops. When we return to the app, the animation continues from the same place, when did stopped. How do I get the animation to recalculate and start from where the timer is now? I attached screenshot. All animation methods are concentrated in one file
I created a new method in the framework, where I pass the remaining time. The method changes the value in the timer. Thanks guys
public func updateTime(time: Int) {
elapsedTime = TimeInterval(time)
delegate?.timerDidResume?(sender: self)
}
Related
I am running swift 4 on Xcode 9.4.1. My program uses a UITapGestureRecognizer for single taps with the code below:
let screenTapOnce = UITapGestureRecognizer(target: self, action: #selector(singleTapGesture))
screenTapOnce.numberOfTapsRequired = 1
view.addGestureRecognizer(screenTapOnce)
The singletap function is:
#objc func singleTapGesture(_ gestureRecognizer: UITapGestureRecognizer) {
This function has a lot of code since it is the main way to interface with the game. My problem is that any change this function makes to the UIView, (even starting a simple activity indicator) does not display until after the singleTapGesture function completes. This is a problem as I would like to show some progress during a special screen update that take 2 seconds to calculate.
Any help to understand how to force an UIView update or even understand why UITapGestureRecognizer seems to block any updates would be appreciated.
My problem is that any change this function makes to the UIView, (even starting a simple activity indicator) does not display until after the singleTapGesture function completes.
That is how iOS works. Drawing takes place on the CATransaction commit, which starts when all your code has run to completion.
This is a problem as I would like to show some progress during a special screen update that take 2 seconds to calculate
Then you need to get off the main thread and onto a background thread. If you take two seconds to calculate something on the main thread, the Watchdog process will kill your app dead before the user's very eyes. There are straightforward ways to display an indication of progress (on the main thread) while you are doing time-consuming work (on a background thread).
I have a problem with animation as I want the same animation with different end points, to be called upon finishing the previous animation and to be executed smoothly without slight stop.
Let me elaborate with a sample code and comments.
Func animate()
{
Start animation(completionHandler: {
If condition is true
Repeat the animation and check after it finishes
}
}
but the problem with this code is that, between finishing the first animation and starting another one, there will be a split second stop which is not smooth movement. For example, I have a view on zero point to move with animation to point A (x:100,y:100), and then it will receive point B (x:500, y:900), after it reaches point A it will stop a split second then move to point B. Since the points are Dynamic, I cannot know if there is a new point or not, and if I did i will not know the coordinates beforehand, so I need to keep the logic dynamic and keeps the animation smooth between points.
I tried many logics and results were not the thing I wanted. problems I faced toward a smooth queued animation are:
I tried UIView.animate in the following:
a. I tried setting an animation duration let's say 2 sec, then after it finishes, it calls animation again within completion hander/closure/block, but it will result in a less than second stop between the two animations.
b. I tried to start 2 animations, the second is delayed with the exact duration go the first animation, but results also brief stop between 2 animations.
2.I tried animation with keyframes, but since I don't know all animations in advance, this won't work.
Can you help please with my approach toward a smooth dynamic animation?
Your own pseudocode answers your question. Just test whatever your condition, and if you need to animate again, work out the new start and end points and animate again:
func animate(start:Int, end:Int) {
UIView.animate(withDuration: 5, animations: {
// animate here based on new start and end
}, completion: { _ in
var weShouldDoItAgain = false
// figure out if we should do it again
// if so, change weShouldDoItAgain to true
if weShouldDoItAgain {
var start = start // and now change it to new value
var end = end // and now change it to new value
self.animate(start:start, end:end)
}
})
}
Just change all the values and types to suit your use case.
For my custom UIView I've overriden touchesBegan method. What I told it to do is to change its' layer's background color:
dispatch_async(dispatch_get_main_queue()){
self.layer.backgroundColor = clr_someCGColor
}
It acts weird. If I quickly tap the view while in Landscape it does everything perfectly well, but if I do this in Portrait, I have to hold it for some time to see the result, however the touchesEnded method is called right away, if I quickly tap. What could be the reason, causing the delay in Portrait?
Remove the dispatch_async wrapper. All it does is cause a delay (we can't execute on the main thread until, as you rightly say, the tap ends and touchesEnded has come and gone). You are already on the main thread, in touchesBegan, so there is no need for this extra delay.
Even better, use a tap gesture recognizer.
I am using Swift to develop an app that uses timer so i am using this code for timer
var timer = NSTimer()
timer=NSTimer.scheduledTimerWithTimeInterval(1.0,target:self,selector:Selector("updateTimeLabel"), userInfo:nil , repeats: true)
my problem is this when this game complete a view appears as subview of current view and the timer invalidates using
timer.invalidate()
and on this subview there is a button to start a new game when this button is pressed a new game is started but the timer starts from the time it stopped.
suppose the game finished in 00:10 time so the subview appears and if we start new game then the time will start from 00:11. This works fine when user moves to another view and then comes back to the same view for game play, in this case the timer starts from 00:00
pls tell where i am wrong
THANKS IN ADVANCE.
You should reset your timeSec and timeMin variables when he decides to start a new game.
In other words, whenever that subview with the button is removed from its superview, reset it.
Or, do it into that button action.
reset your sec and minute variable that are updating the label in your updateTimeLabel method. this would do
Your timer is only used to fire the method that will update the time label.
You need to reset the variable that holds the elapsed time to zero when the game finishes. Probably timeSec in your case, which is hold by your GameScreen class.
I'm using a horizontal UIScrollView that displays photos on the first half of the screen. (Imagine a CGRect (0,0,320,120). The first scrollView is embedded in a second scrollview, which takes all the screen. When I scroll down the page (thus the second scrollView), the first scrollview stop being animated. I programmed a NSTimer to change photo every 3 seconds in the first UIScrollView, but while I'm scrolling the second scrollView, it seems like the animations are being queued. When I release my finger of the screen, there are few photo transitions (i.e: 2 changes if I scrolled without stoping for 6 seconds). In short: how can I make use of blocks (or something else) to continue my animations while I'm scrolling the second scrollView?
My NSTimer (in viewDidLoad):
timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:#selector(changePage:) userInfo:nil repeats:YES];
Your iOS app has a run loop that continually checks for things like user input. If it is busy detecting touch events, things that are scheduled on that run loop will not get performed. (Similarly, if you block the main thread with e.g. a big server request, you won't get touch events during that time).
Here's how you can get the NSTimer on the right run loop:
First, use timerWithTimeInterval:target:selector:userInfo:repeats: to create a timer not scheduled on a run loop.
Second, use - (void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode to schedule the timer on a run loop. For the mode argument (the run loop type), use NSRunLoopCommonModes to allow the timer to fire without having to wait on the main run loop.
Note that this same effect exists for e.g. performSelectorAfterDelay if done in the main run loop. It also applies to animation completion blocks. I'm not sure if there's an easy way around the animation completion block problem besides using CoreAnimation.