How to set same speed to UIView animation - ios

I want to set speed to my UISlider, to make it move more smoothly.
Here is how I am trying to animate it :
UIView.animateWithDuration(6, delay: 0.0, options: UIViewAnimationOptions.TransitionCurlUp, animations: { () -> Void in
self.videoSlider.setValue(time, animated: true)
if self.videoSlider.value == self.videoSlider.maximumValue {
self.playerLayer.stop()
self.playBigButton.hidden = false
self.pauseButton.hidden = true
self.playButton.hidden = false
}
}, completion: { (finished: Bool) -> Void in
})
But it moves with a different speed on the beginning, middle and end.

Try giving your animation the option of .CurveLinear, like this:
UIView.animateWithDuration(6,
delay: 0.0,
options: [UIViewAnimationOptions.TransitionCurlUp, .CurveLinear],
animations: { () -> Void in
self.videoSlider.setValue(time, animated: true)
if self.videoSlider.value == self.videoSlider.maximumValue {
self.playerLayer.stop()
self.playBigButton.hidden = false
self.pauseButton.hidden = true
self.playButton.hidden = false
}
}, completion: { (finished: Bool) -> Void in
})

Related

Swift - CoreAnimation with duration

Trying to understand CoreAnimation and completion handlers.
Why does this code happen all at once, not over a 5.0 second period?
I am trying to get it to run 6 times with the 5 second duration each time for a total of 30 seconds and get "complete" to print every 5 seconds.
func animateBox() {
UIView.animate(withDuration: 5.0, delay: 0.0, options: [], animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: {finished in
print("complete")
})
}
#objc func buttonTapped() {
for _ in 1...6 {
animateBox()
print("animate")
}
}
for _ in 1...6 { is executed instantly, so animateBox is called 6 times, right after another, in a split second.
What you want to do is call each animation block inside the completion handler (which is called when the animation completes) of the previous one. Something like this:
UIView.animate(withDuration: 5.0, delay: 0.0, options: [], animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: { finished in
print("complete")
UIView.animate(withDuration: 5.0, delay: 0.0, options: [], animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: { finished in
print("complete")
UIView.animate(withDuration: 5.0, delay: 0.0, options: [], animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: { finished in
print("complete")
...
})
})
})
But this will result in a huge completion pyramid... instead, try using animateKeyframes:
let totalDuration = CGFloat(30)
let relativeIndividualDuration = CGFloat(1) / CGFloat(6)
UIView.animateKeyframes(withDuration: totalDuration, delay: 0, options: .calculationModeCubic, animations: {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: relativeIndividualDuration) {
self.myBox.layer.borderColor = self.getRandom()
}
UIView.addKeyframe(withRelativeStartTime: relativeIndividualDuration, relativeDuration: relativeIndividualDuration) {
self.myBox.layer.borderColor = self.getRandom()
}
UIView.addKeyframe(withRelativeStartTime: relativeIndividualDuration * 2, relativeDuration: relativeIndividualDuration) {
self.myBox.layer.borderColor = self.getRandom()
}
...
})
Another way you could sequence the animations is to use the delay parameter, and add a delay for each step after the first:
func animateBox(step: Int) {
let duration = 5.0
UIView.animate(withDuration: duration,
delay: duration * Double(step),
options: [],
animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: {finished in
print("complete")
})
}
#objc func buttonTapped() {
for index in 0...5 {
animateBox(step: index)
print("animating step \(index)")
}
}
(Note that I changed your loop to run from 0...5 so delay =step * duration would start at 0.)

Paused animation finishes when an app is in background

I have a view that im moving using this
func r() {
movel.constant = self.view.bounds.width - self.move.bounds.width
move.setNeedsLayout()
UIView.animate(withDuration: time, delay: 0, options:[], animations: {
self.move.superview?.layoutIfNeeded()
}, completion: {(finished: Bool) -> Void in
if (finished == true){
self.timerand()
self.l()
}else{
self.view.layoutIfNeeded()
}
})
}
And I'm using these functions to pause and resume it
func movestop() {
pausedmovetime = self.move.layer.convertTime(CACurrentMediaTime(), from: nil)
self.move.layer.speed = 0.0
self.move.layer.timeOffset = pausedmovetime
}
func movestart() {
self.move.layer.speed = 1.0
self.move.layer.timeOffset = 0.0
self.move.layer.beginTime = 0.0
let timeSincePause = self.move.layer.convertTime(CACurrentMediaTime(), from: nil) - pausedmovetime
self.move.layer.beginTime = timeSincePause
}
The app works fine but when I go out of the app I call the movestop() but when I come back it is at its final position and the completion block doesnt get called

Unbalanced calls to begin/end appearance transitions with segmented control

So, I have a segmented control to switch between to view controllers.
However, often, as soon as I switch, I get this message:
Unbalanced calls to begin/end appearance transitions
Plus, after I get this, sometimes it happens that every object on the view disappear.
Here's the code:
func segmentValueChanged(sender: AnyObject) {
if sender.selectedIndex == 0 {
let newController = controllers.newController1
let oldController = childViewControllers.last as UIViewController!
self.container.frame.size.height = newController.view.frame.height
oldController.willMoveToParentViewController(nil)
addChildViewController(newController)
transitionFromViewController(oldController, toViewController: newController, duration: 0.9, options: .CurveLinear, animations:{ () -> Void in
// nothing needed here
}, completion: { (finished) -> Void in
oldController.removeFromParentViewController()
newController.didMoveToParentViewController(self)
})
} else if sender.selectedIndex == 1 {
let newController = controllers.newController2
let oldController = childViewControllers.last as UIViewController!
oldController.willMoveToParentViewController(nil)
addChildViewController(newController)
transitionFromViewController(oldController, toViewController: newController, duration: 0.9, options: .CurveLinear, animations:{ () -> Void in
// nothing needed here
}, completion: { (finished) -> Void in
oldController.removeFromParentViewController()
newController.didMoveToParentViewController(self)
})
}
}
How can I solve this?
This line is backwards:
self.container.frame.size.height = newController.view.frame.height
It is newController's view's frame that you need to set!
Moreover, you are failing to put newController.view into the interface. That is why you end up without an interface.

Passing data in transitionFromViewController

I'm using transitionFromViewController to switch between two view controllers using a segmented control.
Here's my code:
#IBAction func valueChanged(sender: AnyObject) {
var newController = storyboard?.instantiateViewControllerWithIdentifier(viewControllerIdentifiers[sender.selectedSegmentIndex]) as! UIViewController
let oldController = childViewControllers.last as! UIViewController
oldController.willMoveToParentViewController(nil)
addChildViewController(newController)
newController.view.frame = oldController.view.frame
if viewControllerIdentifiers[sender.selectedSegmentIndex] == "first" {
let vc = newController as! userProfileViewController
vc.userToShow = self.userToShow
}
transitionFromViewController(oldController, toViewController: newController, duration: 0.25, options: .TransitionCrossDissolve, animations:{ () -> Void in
// nothing needed here
}, completion: { (finished) -> Void in
oldController.removeFromParentViewController()
newController.didMoveToParentViewController(self)
})
}
is it possible to pass data to the childViewControllers, from the Parent?
Yes
transitionFromViewController(oldController, toViewController: newController, duration: 0.25, options: .TransitionCrossDissolve, animations:{ () -> Void in
newController.property = currentProperty
//basically here is where you can pass the data. I used a property as an example. You know what you need to send :)
}, completion: { (finished) -> Void in
oldController.removeFromParentViewController()
newController.didMoveToParentViewController(self)
})

Swift cant resolve CurveEaseIn in UIView.animateWithDuration when using parameter from function inside animation block

I am trying to pass parameter to function to change layout constraint in animation block dynamically.
This works:
func moveKeyboard (up: Bool, newMargin: Int)
{
UIView.animateWithDuration(0.2, delay: 0, options: .CurveEaseIn, animations: {
self.topMarginConstraint.constant=10;
}, completion: { finished in
println("Animation end!")
})
}
and this doesn't (i get error "Could not find member CurveEaseIn"):
func moveKeyboard (up: Bool, newMargin: Int)
{
UIView.animateWithDuration(0.2, delay: 0, options: .CurveEaseIn, animations: {
self.topMarginConstraint.constant=newMargin;
}, completion: { finished in
println("Animation end!")
})
}
How should i define my function to be able to use newMargin parameter inside animation block?
It's because, the "constant" is of type "CGFLoat" and you are passsing "Int":
func moveKeyboard (up: Bool, newMargin: CGFloat)
{
UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.topMarginConstraint.constant = newMargin;
}, completion: { finished in
println("Animation end!")
})
}
Check this out it's working fine.

Resources