I'm trying to build an iOS app with a neon light that flickers randomly and constantly like a real one would.
I'm not totally sure how to get the animation to repeat constantly, and I'm not sure how to get it to just run automatically and forever. I put this in the viewDidLoad, but I'm not sure if that's really the best place to put it?
UIImageView.animate(withDuration: 0.05, delay: 5.0, options: .repeat, animations: {
UIImageView.animate(withDuration: 0.05, delay: 2.0, animations: {
self.Aletter.alpha = 0.2
}) { (_) in
UIImageView.animate(withDuration: 0.05, delay: 0.0, animations: {
self.Aletter.alpha = 1.0
}, completion: { (_) in
UIImageView.animate(withDuration: 0.05, delay: 2.0, animations: {
self.Aletter.alpha = 0.6
}, completion: { (_) in
UIImageView.animate(withDuration: 0.05, delay: 0.0, animations: {
self.Aletter.alpha = 1.0
}, completion: { (_) in
UIImageView.animate(withDuration: 0.05, delay: 0.0, animations: {
self.Aletter.alpha = 0.6
}, completion: { (_) in
UIImageView.animate(withDuration: 0.05, delay: 0.0, animations: {
self.Aletter.alpha = 1.0
}, completion: { (_) in
UIImageView.animate(withDuration: 0.05, delay: 0.0, animations: {
self.Aletter.alpha = 0.6
}, completion: { (_) in
UIImageView.animate(withDuration: 0.05, delay: 0.0, animations: {
self.Aletter.alpha = 1.0
}, completion: { (_) in
})
})
})
})
})
})
})
}
})
This code will run my series of flickers, but only once. I need it to go continuously.
As suggested by Matt in the comments section, you can use something like this:
private func flicker() { [weak self] in
UIView.animate(withDuration: 0.05, animations: {
self?.Aletter.alpha = CGFloat.random(in: 0.1...1.0)
}) { _ in
// When this round of animations completes call the same method again to start the animations again with a new random value for alpha.
self?.flicker()
}
}
And just call flicker() in your viewDidLoad(). flicker method starts an animation with a random alpha value for Aletter view, and when this animation completes it calls itself again.
As a side note, use small first letters for your variables, Aletter should be aletter or maybe aLetter based on the context.
Related
In a navigation controller embedded project, using animations, I cannot avoid getting a "fast preview" of the buttons present in the next ViewController, where those buttons will slide from left border of the screen to the center.
So, when I tap in first VC, see for an instant the buttons in second VC, and then the second VC appears and the animation works (and it works fine)
In home controller the button is:
#objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
print("tapped")
//animate 1/2
UIView.animate(withDuration: 0.8, animations: { () -> Void in
self.mainButtonContainerView.center.y -= self.view.bounds.width //self.view.frame.origin
self.mainButtonContainerView.isUserInteractionEnabled = false
self.mainButtonContainerView.alpha = 0.0
})
//animate2/2
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1) ) {
self.pushShowNextVC_ChoiceVC(dataToPass: "")
}
}
Then, the animation in second VC ViewDidLoad is:
for singleView in coantinersOutCollection {
//animation
singleView.center.x -= self.view.bounds.width
singleView.layer.cornerRadius = singleView.bounds.size.height/2
singleView.backgroundColor = UIColor.white
singleView.layer.borderColor = Constants.skyBlue3Color.cgColor
singleView.layer.borderWidth = 1
}
for singleLabel in labesForButtons {
singleLabel.textColor = Constants.skyBlue3Color
singleLabel.font = UIFont.boldSystemFont(ofSize: 17.0)
}
for singleImage in self.iconButtonImages {
// singleImage.image = UIImage(named: "")
singleImage.backgroundColor = UIColor.clear
singleImage.layer.borderWidth = 1
singleImage.layer.borderColor = Constants.skyBlue3Color.cgColor
}
UIView.animate(withDuration: 1.5, delay: 0.6,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 1,
options: [], animations: {
self.containerDownloadButton.center.x += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 1.5, delay: 0.7,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 1,
options: [], animations: {
self.containerUploadButton.center.x += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 1.5, delay: 0.8,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 1,
options: [], animations: {
self.containerCallButton.center.x += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 1.5, delay: 0.9,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 1,
options: [], animations: {
self.containerIdleButton.center.x += self.view.bounds.width
}, completion: nil)
I'm trying to move a UIImageView to top, bottom, left and right. Animation should be 4 four times. Center image move towards top, then left position and right position. How can I achieve this using UIAnimation swift 3?
UIView.animate(withDuration: 0.1,
delay:0,
animations: {},
completion: {completion in})
How to move image to top, left, right and bottom using animation?
You should use a keyframe animation for this, as it allows you to specify the order for the animations. Below is a basic example:
let animationDuration = 2.0
let position: CGFloat = 50.0
let viewToAnimate = UIImageView()
UIView.animateKeyframes(withDuration: animationDuration, delay: 0.0, options: .calculationModeLinear, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1/3, animations: {
viewToAnimate.frame.origin.y = viewToAnimate.frame.origin.y + position
})
UIView.addKeyframe(withRelativeStartTime: 1/4, relativeDuration: 1/4, animations: {
viewToAnimate.frame.origin.y = viewToAnimate.frame.origin.y - (position * 2)
})
UIView.addKeyframe(withRelativeStartTime: 2/4, relativeDuration: 1/4, animations: {
viewToAnimate.frame.origin.x = viewToAnimate.frame.origin.x - position
})
UIView.addKeyframe(withRelativeStartTime: 3/4, relativeDuration: 1/4, animations: {
viewToAnimate.frame.origin.x = viewToAnimate.frame.origin.x + (position * 2)
})
}, completion: { completed in
})
UIView.animate(withDuration: 1, delay:0, animations: {
//top
self.imageView.frame.origin.y = self.imageView.frame.origin.y - 100
}, completion: {completion in
UIView.animate(withDuration: 1, delay:0, animations: {
//bottom
self.imageView.frame.origin.y = self.imageView.frame.origin.y + 100
}, completion: {completion in
UIView.animate(withDuration: 1, delay:0, animations: {
//left
self.imageView.frame.origin.x = self.imageView.frame.origin.x - 100
}, completion: {completion in
UIView.animate(withDuration: 1, delay:0, animations: {
}, completion: {completion in
//right
self.imageView.frame.origin.x = self.imageView.frame.origin.x + 100
})
})
})
})
UIView.animate(withDuration: 1, delay:0, animations: {
//top
self.tempVW.frame.origin.y = self.tempVW.frame.origin.y - 100
}, completion: {completion in
UIView.animate(withDuration: 1, delay:0, animations: {
//left
self.tempVW.frame.origin.x = self.tempVW.frame.origin.x - 100
}, completion: {completion in
UIView.animate(withDuration: 1, delay:0, animations: {
//bottom
self.tempVW.frame.origin.y = self.tempVW.frame.origin.y + 100
}, completion: {completion in
UIView.animate(withDuration: 1, delay:0, animations: { //right
self.tempVW.frame.origin.x = self.tempVW.frame.origin.x + 100
}, completion: {completion in
})
})
})
})
Recently, I have made some code which draws a face. I wanted to animate the face to shake back and forth. Currently I have this code. It rotates once to the right, then more to the left, and then to the original position. However, what if I wanted the head to infinitely shake back and forth(rotate bath and forth). Is it possible to make some sort of recursive function to do this?
#IBAction func shakeHead(_ sender: UITapGestureRecognizer) {
UIView.animate(
withDuration: 0.5,
animations: {
self.faceView.transform = self.faceView.transform.rotated(by: self.shakeAngle)
},
completion:{ finished in
if(finished){
UIView.animate(
withDuration: 0.5,
animations: {
self.faceView.transform = self.faceView.transform.rotated(by: -(self.shakeAngle)*2)
},
completion:{ finished in
if(finished){
UIView.animate(
withDuration: 0.5,
animations: {
self.faceView.transform = self.faceView.transform.rotated(by: self.shakeAngle)
},
completion: nil
)
}
}
)
}
}
)
}
You could call shakeHead from the final completion block.
#IBAction func shakeHead(_ sender: UITapGestureRecognizer) {
UIView.animate(
withDuration: 0.5,
animations: {
self.faceView.transform = self.faceView.transform.rotated(by: self.shakeAngle)
},
completion:{ finished in
if(finished){
UIView.animate(
withDuration: 0.5,
animations: {
self.faceView.transform = self.faceView.transform.rotated(by: -(self.shakeAngle)*2)
},
completion:{ finished in
if(finished){
UIView.animate(
withDuration: 0.5,
animations: {
self.faceView.transform = self.faceView.transform.rotated(by: self.shakeAngle)
},
completion: { finished in
shakeHead(sender)
}
)
}
}
)
}
}
)
}
Even though this is technically a recursive call, it's not a problem due to the asynchronous nature of the code.
Use animateKeyframes for a better chain animation experience
#IBAction func shakeHead(_ sender: UITapGestureRecognizer) {
UIView.animateKeyframes(withDuration: animationDuration, delay: 0, options: [], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
self.faceView.transform = self.faceView.transform.rotated(by: self.shakeAngle)
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
self.faceView.transform = self.faceView.transform.rotated(by: -(self.shakeAngle)*2)
}
UIView.addKeyframe(withRelativeStartTime: 1.0, relativeDuration: 0.5) {
self.faceView.transform = self.faceView.transform.rotated(by: self.shakeAngle)
}
}) { (isFinished) in
shakeHead(sender)
}
}
I'm animating the scale of a button using animateKeyframes in Swift 3 using the following code:
UIView.animateKeyframes(withDuration: 4, delay: 1, options: [.repeat, .allowUserInteraction, .calculationModeCubic], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.1, animations: {
self.myButton.transform = CGAffineTransform(scaleX: 1,y: 1)
})
UIView.addKeyframe(withRelativeStartTime: 0.1, relativeDuration: 0.1, animations: {
self.myButton.transform = CGAffineTransform(scaleX: 0.9,y: 0.9)
})
}, completion: nil)
What I need to do is add easing to each keyframe. I looked up something that uses the following code that can then be passed to animateKeyframes
let animationOptions: UIViewAnimationOptions = .curveEaseIn
let keyframeAnimationOptions: UIViewKeyframeAnimationOptions = UIViewKeyframeAnimationOptions(rawValue: animationOptions.rawValue)
However, it doesn't quite say exactly how to pass the keyframeAnimationOptions variable, and I can't seem to figure it out myself! Can anybody help?
You can use below code to call the keyframeAnimationOptions variable.
let keyframeAnimationOption=UIViewKeyframeAnimationOptions.CalculationModeCubic
UIView.animateKeyframesWithDuration(duration, delay: delay, options: keyframeAnimationOption, animations:
{
/////Your code //////
}, completion: nil)
I'm trying to implement this animation where a UIButton fades out when a user saves a file. While the button fades out, a UIImageView of a check mark image fades in place of the button. Once the imageview has fully faded in, then it fades out and the button fades back in.
UIView.animateWithDuration(0.60, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.recButton.alpha = 0.0
}, completion: {
(value: Bool) in
UIView.animateWithDuration(0.60, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.checkView.alpha = 1.0
}, completion: {
(value: Bool) in
UIView.animateWithDuration(0.60, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.checkView.alpha = 0.0
}, completion: {
(value: Bool) in
UIView.animateWithDuration(0.60, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.recButton.alpha = 1.0
self.recButton.enabled = true
}, completion: nil)
})
})
})
While the method above does work, its not as smooth as I would like. Is there a better way to go about this?
You need four keyframes for the animation you want: button fade out, image fade in, image fade out, button fade in.
let button: UIButton
let checkmarkImage: UIImageView
button.alpha = 1.0
checkmarkImage = 0.0
UIView.animateKeyframesWithDuration(2.4, delay: 0, options: .CalculationModeLinear, animations: {
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.25, animations: {
button.alpha = 0.0
})
UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25, animations: {
checkmarkImage.alpha = 1.0
})
UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.25, animations: {
checkmarkImage.alpha = 0.0
})
UIView.addKeyframeWithRelativeStartTime(0.75, relativeDuration: 0.25, animations: {
button.alpha = 1.0
})
}, completion: nil)
This question raised my curiosity - this keyframe thing is pretty cool.