Incrementing a parameter in UIView.animateWithDuration in Swift - ios

I have an IBOutlet Collection of buttons that I am trying to present on screen sequentially. They all start off screen fine, but as they animate in, I'd like each button to be presented on screen 0.05 seconds after the previous button. I can't figure out how to increment the delay in UIView.animateWithDuration. With the code below, they are all animating on screen at the same time.
//outlet collection
#IBOutlet var options: [UIButton]!
let increment = 0.25
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
for button in options {
button.center.y += view.bounds.height
}
}
override func viewDidLoad() {
super.viewDidLoad()
for button in options {
UIView.animateWithDuration(1.0, delay: increment, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.0, options: nil, animations: {
button.center.y -= self.view.bounds.height
self.increment + 0.05
}, completion: nil)
}
}

for button in options {
UIView.animateWithDuration(1.0, delay: increment, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.0, options: nil, animations: {
button.center.y -= self.view.bounds.height
}, completion: nil)
}
increment = increment + 0.05
}
Besides:
Change this
let increment = 0.25
To
var increment = 0.25
Increase the increment outside animation. Because animateWithDuration is an async method,it will return first. So,all your button have same delay.

#IBOutlet weak var button1: UIButton!
#IBOutlet weak var button2: UIButton!
#IBOutlet var options: [UIButton]!
let increment = 0.25
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
for button in options {
button.center.y += view.bounds.height
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
for button in options {
UIView.animateWithDuration(1.0, delay: increment, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.0, options: nil, animations: {
button.center.y -= self.view.bounds.height
}, completion: nil)
self.increment + 0.05
}
}
Also getting error "Cannot invoke '+=' with an argument list of type '(Double, FloatLiteralConvertible)'" when using += but it will take just +

Here is the way to achieve the required delay between animations:
var i! as UInt64;
i = 0
for button in options {
// your animation with delay
UIView.animateWithDuration(1.0, delay: (i *0.05), usingSpringWithDamping: 0.7, initialSpringVelocity: 0.0, options: nil, animations: {
button.center.y -= self.view.bounds.height
}, completion: nil)
})
++i
}

Related

Swift tvOS - pause UIImage animations when user presses MENU button

For my intro page I have multiple images animations in sync with music to make a cool intro page. Problem is when I tap MENU and return to the app, all of the animations have completed. I have implemented a function to pause the music, yet need to do the same to the UIImage animations. FYI, it is the Mortal Kombat theme song synced with the characters it says in the song. I have not worked with animations before so looking at other solutions on SO and trying them has not worked.
// Mortal Kombat Good Guys
#IBOutlet weak var luiKangImage: UIImageView!
#IBOutlet weak var johnnyCageImage: UIImageView!
#IBOutlet weak var raidenImage: UIImageView!
#IBOutlet weak var kitanaImage: UIImageView!
#IBOutlet weak var sonyaImage: UIImageView!
#IBOutlet weak var nightWolfImage: UIImageView!
#IBOutlet weak var cassieCageImage: UIImageView!
#IBOutlet weak var kenshiTakahashiImage: UIImageView!
#IBOutlet weak var kungLaoImage: UIImageView!
#IBOutlet weak var jaxBriggsImage: UIImageView!
// Mortal Kombat Bad Guys
#IBOutlet weak var scorpionImage: UIImageView!
#IBOutlet weak var kanoImage: UIImageView!
#IBOutlet weak var reptileImage: UIImageView!
#IBOutlet weak var subZeroImage: UIImageView!
#IBOutlet weak var shangTsungImage: UIImageView!
#IBOutlet weak var goroImage: UIImageView!
#IBOutlet weak var shaoKhanImage: UIImageView!
#IBOutlet weak var tanyaImage: UIImageView!
#IBOutlet weak var quanChiImage: UIImageView!
#IBOutlet weak var mileenaImage: UIImageView!
var player: AVAudioPlayer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//Set to execute function playSound
playSound()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setInMotionImagePaths()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setInMotionImageTimePaths()
}
func setInMotionImagePaths() {
// Mortal Kombat Good Guys Image Animation Paths
luiKangImage.center.x -= view.bounds.width
johnnyCageImage.center.y += view.bounds.width
raidenImage.center.y -= view.bounds.width
kitanaImage.center.x -= view.bounds.width
sonyaImage.center.x -= view.bounds.width
nightWolfImage.center.y += view.bounds.width
cassieCageImage.center.y -= view.bounds.width
kenshiTakahashiImage.center.y += view.bounds.width
kungLaoImage.center.x -= view.bounds.width
jaxBriggsImage.center.y -= view.bounds.width
// Mortal Kombat Bad Guys Image Animation Paths
scorpionImage.center.x += view.bounds.width
kanoImage.center.y += view.bounds.width
reptileImage.center.x += view.bounds.width
subZeroImage.center.x += view.bounds.width
shangTsungImage.center.y += view.bounds.width
goroImage.center.x += view.bounds.width
shaoKhanImage.center.y += view.bounds.width
tanyaImage.center.x += view.bounds.width
quanChiImage.center.y += view.bounds.width
mileenaImage.center.x += view.bounds.width
}
func setInMotionImageTimePaths() {
playSound()
// Mortal Kombat Good Guys Animation Time and Path
UIView.animate(withDuration: 5.0, delay: 0.6, options: [], animations: {
self.luiKangImage.center.x += self.view.bounds.width
}, completion: nil)
//DONT TOUCH TIME
UIView.animate(withDuration: 5.0, delay: 2.3, options: [], animations: {
self.johnnyCageImage.center.y -= self.view.bounds.width
}, completion: nil)
//DONT TOUCH TIME
UIView.animate(withDuration: 5.0, delay: 1.2, options: [], animations: {
self.raidenImage.center.y += self.view.bounds.width
}, completion: nil)
//DONT TOUCH TIME
UIView.animate(withDuration: 5.0, delay: 10.0, options: [], animations: {
self.kitanaImage.center.x += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 8.5, options: [], animations: {
self.sonyaImage.center.x += self.view.bounds.width
}, completion: nil)
//DONT TOUCH TIME
UIView.animate(withDuration: 5.0, delay: 11.0, options: [], animations: {
self.nightWolfImage.center.y -= self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 12.0, options: [], animations: {
self.cassieCageImage.center.y += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 13.0, options: [], animations: {
self.kenshiTakahashiImage.center.y -= self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 14.0, options: [], animations: {
self.kungLaoImage.center.x += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 15.0, options: [], animations: {
self.jaxBriggsImage.center.y += self.view.bounds.width
}, completion: nil)
// Mortal Kombat Bad Guys Animation Time and Path
UIView.animate(withDuration: 4.0, delay: 5.5, options: [], animations: {
self.scorpionImage.center.x -= self.view.bounds.width
}, completion: nil)
//DONT TOUCH TIME
UIView.animate(withDuration: 2.0, delay: 0.0, options: [], animations: {
self.kanoImage.center.y -= self.view.bounds.width
}, completion: nil)
//DONT TOUCH TIME
UIView.animate(withDuration: 5.0, delay: 11.0, options: [], animations: {
self.reptileImage.center.x -= self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 4.0, delay: 7.0, options: [], animations: {
self.subZeroImage.center.x -= self.view.bounds.width
}, completion: nil)
//DONT TOUCH TIME
UIView.animate(withDuration: 5.0, delay: 10.3, options: [], animations: {
self.shangTsungImage.center.y -= self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 11.5, options: [], animations: {
self.goroImage.center.x -= self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 12.5, options: [], animations: {
self.shaoKhanImage.center.y -= self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 13.5, options: [], animations: {
self.tanyaImage.center.x -= self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 15.0, options: [], animations: {
self.quanChiImage.center.y -= self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 5.0, delay: 14.5, options: [], animations: {
self.mileenaImage.center.x -= self.view.bounds.width
}, completion: nil)
}
func playSound() {
let url = Bundle.main.url(forResource: "MortalKombatSong", withExtension: "mp3")!
do {
player = try AVAudioPlayer(contentsOf: url)
guard let player = player else { return }
player.prepareToPlay()
player.play()
player.numberOfLoops = 0
} catch let error {
print(error.localizedDescription)
}
}
func stopSound() {
if player?.isPlaying ?? true {
player?.stop()
}
}
How I pause the music in App Delegate
import AVFoundation
var player: AVAudioPlayer?
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
player?.pause()
}
You could try out this answer. I don't believe it's possible to pause the actual view animations since they start as soon as they're passed to the animation block and you don't get any references to them

How to fix up animation in swift?

I have UIImageView with moon image.
And moonImageContainerView is a superView for UIImageView
And I added swipe gesture to moonImageContainerView.
If swipe to up,
self.titleLabel.isHidden = false
UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseIn, animations: {
self.moonImageContainerView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
self.moonImageContainerView.center.y = self.view.center.y
}, completion: nil)
you can see the result with gif
https://imgur.com/a/ftShkpO
And now, If I add just self.titleLabel.text = "MY TOPIA"
My animation is break.
self.titleLabel.text = "MY TOPIA" // Just added this line.
self.titleLabel.isHidden = false
UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseIn, animations: {
self.moonImageContainerView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
self.moonImageContainerView.center.y = self.view.center.y
}, completion: nil)
You can see the result with gif
https://imgur.com/a/y57fPlA
Why does the moonImageContainerView disappear to the bottom?
How can I fix it?
Well, I use the rest setting and did not see your case.
import UIKit
class ImageViewController: UIViewController {
#IBOutlet var moonImageContainerView: UIView!
#IBOutlet var titleLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let pan = UISwipeGestureRecognizer.init(target: self, action: #selector(pp(_:)))
pan.direction = .up
moonImageContainerView.addGestureRecognizer(pan)
}
#objc func pp(_ pan: UISwipeGestureRecognizer){
self.titleLabel.text = "MY TOPIA"
self.titleLabel.isHidden = false
UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseIn, animations: {
self.moonImageContainerView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
self.moonImageContainerView.center.y = self.view.center.y
}, completion: nil)
}
}

issues with UIView animation swift 4 Xcode9

I am trying to make an animation of a UILabel from off the screen to the center with a spring animation block. The first part of my code below in viewDidLoad() works perfectly, but when I add the animation block, it's like the code in the closure of the animation gets read first and it doesn't animate because the label is already in the place where I want the label to animate to. I have also tried to put this exact code in viewDidAppear() but the same thing happens.
#IBOutlet weak var follow: UILabel!
#IBOutlet weak var followX: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.follow.translatesAutoresizingMaskIntoConstraints = false
self.followX.constant = self.view.frame.width/2 + follow.frame.width/2
self.view.layoutIfNeeded()
UIView.animate(withDuration: 2, delay: 2, usingSpringWithDamping: 5, initialSpringVelocity: 5, options: .curveEaseOut, animations: {
self.followX.constant = 0
self.view.layoutIfNeeded()
})
}
This is the correct way to do it (although I would try to move that animation to viewWillAppear or viewDidAppear):
#IBOutlet weak var follow: UILabel!
#IBOutlet weak var followX: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.follow.translatesAutoresizingMaskIntoConstraints = false
self.followX.constant = self.view.frame.width/2 + follow.frame.width/2
self.view.layoutIfNeeded()
self.followX.constant = 0
self.view.setNeedsLayout()
UIView.animate(withDuration: 2, delay: 2, usingSpringWithDamping: 5, initialSpringVelocity: 5, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
})
}
To work with autolayout:
You first make sure the to begin animation is ready:
self.followX.constant = self.view.frame.width/2 + follow.frame.width/2
self.view.layoutIfNeeded()
Then you change constraints to the final state of the animation:
self.followX.constant = 0
Then you tell autolayout that the constraints were changed:
self.view.setNeedsLayout()
And finally you call UIView.animate with layoutIfNeeded() to animate the change:
UIView.animate(withDuration: 2, delay: 2, usingSpringWithDamping: 5, initialSpringVelocity: 5, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
})
override func viewDidLayoutSubviews() {
if(once)
{
once = false
self.follow.translatesAutoresizingMaskIntoConstraints = false
self.followX.constant = self.view.frame.width/2 + follow.frame.width/2
self.view.layoutIfNeeded()
}
}
and in viewDidAppear
override func viewDidAppear() {
self.followX.constant = 0
UIView.animate(withDuration: 2, delay: 0, usingSpringWithDamping: 5, initialSpringVelocity: 5, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
})
}

Swift - Animation Direction

I have having a nightmare with a simple problem. On my app I have clouds moving in the background (currently from left to right).
However with the background they need to be right to left.
Eddited for the more of the page code below. Hopefully this will be easier to work out where I have gone wrong.
#IBOutlet var cloud1: UIImageView!
#IBOutlet var cloud2: UIImageView!
#IBOutlet var cloud3: UIImageView!
#IBOutlet var cloud4: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
cloud1.alpha = 0.0
cloud2.alpha = 0.0
cloud3.alpha = 0.0
cloud4.alpha = 0.0
}
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 2.0, delay: 0.1,
options: [],
animations: {
self.cloud1.alpha = 1.0
}, completion: nil)
UIView.animate(withDuration: 2.0, delay: 0.1,
options: [],
animations: {
self.cloud2.alpha = 1.0
}, completion: nil)
UIView.animate(withDuration: 2.0, delay: 0.1,
options: [],
animations: {
self.cloud3.alpha = 1.0
}, completion: nil)
UIView.animate(withDuration: 2.0, delay: 0.1,
options: [],
animations: {
self.cloud4.alpha = 1.0
}, completion: nil)
animateTheClouds(cloud: cloud1)
animateTheClouds(cloud: cloud2)
animateTheClouds(cloud: cloud3)
animateTheClouds(cloud: cloud4)
}
func animateTheClouds(cloud : UIImageView) {
let cloudMovingSpeed = 60.0/view.frame.size.width
let duration = (view.frame.size.width - cloud.frame.origin.x) * cloudMovingSpeed
UIView.animate(withDuration: TimeInterval(duration), delay: 0.0, options: .curveLinear, animations: {
// Animate the origin to be off the left side of the screen.
cloud.frame.origin.x = cloud.frame.size.width
}, completion: {_ in
// Reset back to the right edge of the screen
cloud.frame.origin.x = -self.view.frame.size.width
self.animateTheClouds(cloud: cloud)
})
If you want to move them from right to left then you simply need to change the starting and ending x origin.
func animateTheClouds(cloud : UIImageView) {
let cloudMovingSpeed = 60.0/view.frame.size.width
let duration = (cloud.frame.origin.x + cloud.frame.size.width) * cloudMovingSpeed
UIView.animate(withDuration: TimeInterval(duration), delay: 0.0, options: .curveLinear, animations: {
// Animate the origin to be off the left side of the screen.
cloud.frame.origin.x = -cloud.frame.size.width
}, completion: {_ in
// Reset back to the right edge of the screen
cloud.frame.origin.x = self.view.frame.size.width
self.animateTheClouds(cloud: cloud)
})
Also make sure the initial x origin is set to self.view.frame.size.width.

.xib Called Inside ViewController Does not Recognize Touch Events

Inside a UIViewController, I call a .xib file and present it over the current UIView.
// initiate the pop up ad view and display it
let popUpAdView = PopUpAdViewController(nibName: "PopUpAdView", bundle: nil)
popUpAdView.displayIntoSuperView(view)
There is a button inside that .xib file that should remove itself from the screen when it's touched. However it doesn't perform so.
What exactly am I missing?
class PopUpAdViewController: UIViewController {
#IBOutlet weak var popUpAdView: UIView!
#IBOutlet weak var closeButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// adjust the view size from the device's screen size
let screenSize = UIScreen.mainScreen().bounds
view.frame = CGRectMake(0, 64, screenSize.width, screenSize.height-64)
// cosmetically adjust the view itself
view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.6)
view.userInteractionEnabled = true
closeButton.userInteractionEnabled = true
// style the pop up ad view
popUpAdView.layer.cornerRadius = 5
popUpAdView.layer.shadowOpacity = 0.8
popUpAdView.layer.shadowOffset = CGSizeMake(0.0, 0.0)
closeButton.addTarget(self, action: #selector(removeOutOfSuperView), forControlEvents: .TouchUpInside)
}
func displayIntoSuperView(superView: UIView!) {
superView.addSubview(self.view)
// define the initial cosmetical values of the items
popUpAdView.transform = CGAffineTransformMakeScale(0.3, 0.3)
popUpAdView.alpha = 0.0
closeButton.alpha = 0.0
// animate...
UIView.animateWithDuration(0.8, delay: 0.0, options: .CurveEaseIn, animations: {
self.popUpAdView.alpha = 1.0
self.popUpAdView.transform = CGAffineTransformMakeScale(1.0, 1.0)
}) { (Bool) in
UIView.animateWithDuration(0.6, delay: 1.5, options: .CurveEaseIn, animations: {
self.closeButton.alpha = 1.0
}, completion: { (Bool) in
})
}
}
func removeOutOfSuperView() {
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseIn, animations: {
self.closeButton.alpha = 0.0
self.popUpAdView.transform = CGAffineTransformMakeScale(0.1, 0.1)
}) { (finished) in
UIView.animateWithDuration(0.8, delay: 0.0, options: .CurveEaseIn, animations: {
self.view.alpha = 0.0
self.view.removeFromSuperview()
}, completion: nil)
}
}
#IBAction func closePopUpAdView(sender: AnyObject) {
print("Closing the pop up ad...")
removeOutOfSuperView()
}
}
Update
.xib structureL:

Resources