Swift UIViewPropertyAnimator automatically plays when leaving app - swift

Good day everyone!
I've a problem with my app. I'm using an UIViewPropertyAnimator to animate my blur. I let the blur effect run from nil (0) to .light (1) but because the light effect is just too much I set the UIViewPropertyAnimator to 0.1 (.fractioncomplete = 0.1).
This works greath! But the problem is that if you leave the app (not kill, just leaving by pressing home button or going to another app), it automatically plays and goes from 0.1 to 1.
I think this is a bug? I hope someone has a solution for this.
Here some pictures: (not enough reputation to post them directly)
picture with blur on 0.1
picture with blur on 1
Code:
let effectView = UIVisualEffectView(effect: nil)
var animator: UIViewPropertyAnimator?
viewdidload:
effectView.frame = view.bounds
effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mainView.addSubview(effectView)
animator = UIViewPropertyAnimator(duration: 1, curve: .linear) {
self.effectView.effect = UIBlurEffect(style: .light)
}
blur action (need to start/pause first because of a known bug from apple to wake the animator up):
self.animator?.startAnimation()
self.animator?.pauseAnimation()
self.animator?.fractionComplete = CGFloat(0.1)
Thanks in advance !

I solved this issue by setting the pausesOnCompletion property of UIViewPropertyAnimator to true, immediately after setting the fractionComplete. No need to restart the animator.

I reproduced your issue, and confirm this behavior, but I doubt it's a bug. Property animator just returns from paused state to active and runs animation. To overcome it you have to stop it and then finish in current fraction of the state (respective states are described in docs). One more issue here - somehow stopping it right after setting fractionComplete stops it at 0 so you have to wait a while (very short). Try this code under your "blurAction":
self.animator?.startAnimation()
self.animator?.pauseAnimation()
self.animator?.fractionComplete = CGFloat(0.1)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
self.animator?.pauseAnimation()
self.animator?.stopAnimation(true)
self.animator?.finishAnimation(at: .current)
}
I verified it works for background/foreground app lifecycle change.

Related

Spritekit Animation not working

I'm trying to make a game where the main user is animated and i converted the gif to png and took each frame and put them all into a folder. However, right now I'm simply trying to get the first frame to appear, but nothing appears. Sorry if i worded this weird my English isn't very good.
Right now I think just the first frame, "trumpyhappy1.png" should show when I try to run it, but when I run it nothing shows up.
For anyone that stumbles upon this and is still wondering why their animations are blank. I found that programmatically adding the actions would cause this before viewDidAppear got called. However, setting the animation in the scene file directly I was able to get around the blank animations
So basically in spritekit to animate a spritenode you should be doing this
override func didMove() {
let mainGuy = SKSpriteNode()
self.addChild(mainGuy)
// Give your size and position and everything
// Then to animate that spriteNode with frames
let textureAtlas = SKTextureAtlas(named: "trump")
let frames: [SKTexture] = []
for i in 0...textureAtlas.textureNames.count {
var name = "trumphappy\(i).png"
frames.append(SKTexture(named: name))
}
// Then to create the animation add this code
let animation = SKAction.animate(with: frames, timePerFrame: ) // Whatever time you want your animation to spend on each frame
}
That should work, hope it works!

Animate Auto Layout Constraints and Alpha on NSView

Swift 3, iOS 10, macOS 10.12.4
I am building an app that runs on both iOS and Mac. On the iOS side, I have successfully animated a UIView. When the user taps on something, a popup appears and animates into position. Here's my code inside the tap event:
self.popupConstraintX.constant = x
self.popupConstraintY.constant = y
UIView.animate(withDuration: 0.25 , delay: 0.0, options: .curveLinear, animations: {
self.graphPopup.alpha = 1.0
self.layoutIfNeeded()
}, completion:nil)
In this case, self refers to a UITableViewCell that holds the graphPopup.
I have built the same thing on the Mac side, but I'm trying to animate graphPopup which is now an NSView. Here's what I have so far inside my click event:
self.popupConstraintX.constant = x
self.popupConstraintY.constant = y
self.view.layoutSubtreeIfNeeded()
NSAnimationContext.runAnimationGroup({_ in
self.graphPopup.alphaValue = 1.0
//Indicate the duration of the animation
NSAnimationContext.current().duration = 0.25
NSAnimationContext.current().allowsImplicitAnimation = true
self.view.updateConstraints()
self.view.layoutSubtreeIfNeeded()
}, completionHandler:nil)
Here self refers to the containing NSViewController. Nothing animates--not the position or the alpha of graphPopup. It just appears and disappears like it's on an Atari in 1985.
Any idea what I'm doing wrong with my NSView animation?
Update
For posterity's sake, here is the working code as suggested by BJ (with a slight tweak to use the implicit animation context):
self.popupConstraintX.constant = x
self.popupConstraintY.constant = y
NSAnimationContext.runAnimationGroup({context in
context.duration = 0.25
context.allowsImplicitAnimation = true
self.graphPopup.alphaValue = 1.0
self.view.layoutSubtreeIfNeeded()
}, completionHandler:nil)
The modification of alphaValue is happening before you have turned on implicit animation, so the alpha will not be animated. It's unclear to me whether that was intentional or not.
The view is not animating to the position given by the popupConstraints, because you're not actually doing anything inside the animation block that would cause the view's frame to change. In order to trigger an implicit animation, you must not only update constraints; you must also ensure that the view's frame changes within the animation block. If you're using AutoLayout, this is usually done by calling layoutSubtreeIfNeeded.
However, because you updated the constraints and called layoutSubtreeIfNeeded() prior to the animation block, there are no additional frame changes left to make inside the block (unless there's something happening down in updateConstraints() which you haven't shown us.)
You should remove the first call to layoutSubtreeIfNeeded(), or if it's still necessary, put it above the popupConstraint modifications. Then, when you call layoutSubtreeIfNeeded() within the animation block, a new frame will be set based on those changed constraints, and you should see animation happening.
Swift 5
animator() is the key.
You can simply do like this:
NSAnimationContext.runAnimationGroup({ context in
//Indicate the duration of the animation
context.duration = 0.25
self.popupConstraintX.animator().constant = x
self.popupConstraintY.animator().constant = y
self.graphPopup.animator().alphaValue = 1.0
}, completionHandler:nil)

iOS UIButton in Navigation bar disappears after performing transform animation

I'm trying to animate transform from '+' button to 'X' button by rotating it on click.
Everything works great when I'm using standard button on UIView. I'm using following code:
UIView.animateWithDuration(2.0, delay: 0.0, options: .CurveEaseOut, animations: {
let transform = CGAffineTransformMakeRotation(CGFloat(M_PI_4))
self.navigationPlusButton.transform = transform
}, completion: nil)
The problem occurs when I try to achieve the same with button in navigation bar.
Looks like button height is resized to 0 before the rotation and I don't know how to fix navigation button size since there are no constraints definitions. Note storyboard
and for constraints
Note: Second approach using CABasicAnimation rotated button nicely but it returned it to initial state immediately after animation ends. I would like to stay 'X' until I click again.
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
rotateAnimation.toValue = CGFloat(M_PI_4)
rotateAnimation.duration = 2.0
self.navigationPlusButton.layer.addAnimation(rotateAnimation, forKey: nil)
How it works so easily outside the navigation bar and it is so hard to do it on navigation bar? I can't find the solution. Please help
try following lines to your code, it will solve your problem.
rotateAnimation.fillMode = kCAFillModeForwards
rotateAnimation.removedOnCompletion = false
Try this line on the CABasicAnimation:
rotateAnimation.removedOnCompletion = false
It may solve your problem.

Stopping an running SKAction - Sprite Kit

The following code will animate a rotation.
let something:SKSpriteNode = SKSpriteNode()
func start(){
let rotateAction = SKAction.rotateToAngle(CGFloat(M_PI), duration: 10.0)
something.runAction(SKAction.sequence([rotateAction]))
}
Now I want to stop the animation within the animating duration. Is there anything similar to the following? I want to stop the animation when the user touches the screen.
func stop(){
something.SKAction.stop()
}
You just have to use either:
something.paused = false // or true to pause actions on the node
something.removeAllActions() to definitely remove actions associated to the node
name your action when launching something.runAction(action,withKey:"action1") and then something.removeActionForKey("action1") to remove a given action
You may also change the speed if needed.
Firstly, run the action with a key so you can identify it later:
something.runAction(rotateAction, withKey: "rotate action")
Then you can stop it later by calling
something.removeActionForKey("rotate action")
Alternatively, you can remove all actions also
something.removeAllActions()

Implementing basic animations with tvOS

I'm hoping someone may be able to help me understand why my tvOS animations are not running.
In my code I have a function like this:
func testAnimation() {
clockLabel.alpha = 0.0
UIView.animateWithDuration(1.0, animations: {
self.clockLabel.alpha = 1.0
})
}
I am calling testAnimation() from within my viewDidLoad(), but no animation ever seems to happen.
I've tested with a few different types of animations, from things like position to opacity, but it seems that no animation ever actually runs in the Simulator.
At this time, my app does not have a focus. All I'm trying to do is load a blank UIView with a label in the middle that fades in.
You're trying to animate your UILabel before it has been displayed. Move your animation from viewDidLoad() to viewDidAppear().
I can confirm this behaviour as this happens for me as well. What I did was setting a delay of 0.1 (afterDelay:), and it is "good enough"
On the other hand, what DID actually work was setting a transform for my views. E.g. (objc though):
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(0.5,0.5);
[UIView animateWithDuration: 0.5 animations:^{
_myView.transform = scaleTransform;
} completion: nil]
Maybe it's a bug in tvOS
Try using UIView Animation, like this (Swift):
clockLabel.alpha = 0
UIView.animateWithDuration(0.5, delay: 0.0, options: .Linear, animations: {
self.clockLabel.alpha = 1.0
}, completion: { finished in
// you may add some code here to make another action right after the animation end, or just delete this comment :)
})
This works on our side.