UIview resets to initial position after animation step complete - ios

I need to rotate clock view with some angle. But second step of animation starting at the initial position, when i need to continue its with the new one.
UIView.animate(withDuration: 0.8, delay: 0, options: [.beginFromCurrentState], animations: {
UIView.setAnimationRepeatCount(5)
self.clock.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi/4), 0, 0, 1)
}, completion: nil)
When i'm trying to do some animation in completion block it doesn't trigger. And after second pressing the button - animation doesn't launching at all, but the console is displaying "true".
#IBAction func flip(_ sender: Any) {
UIView.animate(withDuration: 0.2, animations: {
self.FirstView.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi), -1, 1, 0)
}, completion: { finished in
print(finished)
UIView.animate(withDuration: 0.2, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0, options: [], animations: {
self.FirstView.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi), -1, 1, 0)
}, completion: nil)
})}
P.S. Sorry for my poor English

Related

Cannot get closure syntax to work in swift 4

I've tried every syntax variation that I can, but the completion handler always activates before the end of the animation. I think I'm supposed to replace Bool with something else?
UIView.transition(with: swipeForPicturesIndicator,
duration: 1,
options: .curveEaseIn,
animations: {
self.swipeForPicturesIndicator.alpha = 0
},
completion: { (Bool) -> Void in
self.swipeForPicturesIndicator.isHidden = true
self.swipeForPicturesIndicator.alpha = 0.8
})
The Bool value indicates wether the animation was finished when the completion block was called. If that value is false it means your animation was interrupted.
You should use probably animate instead of transition
UIView.animate(withDuration: 1,
delay: 0,
options: .curveEaseIn,
animations: {
self.swipeForPicturesIndicator.alpha = 0
}) { (completed) in
/* Optionally check if animation finished */
self.swipeForPicturesIndicator.isHidden = true
self.swipeForPicturesIndicator.alpha = 0.8
}
Try this
self.swipeForPicturesIndicator.alpha = 0
UIView.transition(with: swipeForPicturesIndicator,
duration: 1,
options: .curveEaseIn,
animations: {
self.swipeForPicturesIndicator.alpha = 0.8
},
completion: nil)
You may want to use animate instead of transition:
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseIn, animations: {
self.swipeForPicturesIndicator.alpha = 0
}) { (success) in
self.swipeForPicturesIndicator.isHidden = true
self.swipeForPicturesIndicator.alpha = 0.8
}

How to do a sequence animation on a textview (swift3)

My code below is a button that when hit applies animation. Right now there are two animations. I would like to do a sequence the animations meaning have the 2nd animation not start until the first animation has completed.
var speed: CGFloat = 5.3 // speed in seconds
#IBAction func press(_ sender: Any) {
self.theTextView.resignFirstResponder()
UIView.animate(withDuration: TimeInterval(speed), animations: {
////1st action[
self.theTextView.contentOffset = .zero
self.theTextView.setContentOffset(.zero, animated: true)]
/////2nd action[
self.theTextView.contentOffset = CGPoint(x: 0, y: self.theTextView.contentSize.height)]
}, completion: nil)
}}
The easiest way of doing that would be using the completion block of the animate(withDuration:animations:completion:) method. The completion block is executed when the animation sequence ends. In your case, it would look like this :
UIView.animate(withDuration: 6.0, animations: {
// First animation goes here
self.theTextView.contentOffset = CGPoint.zero
}, completion: { (finished) in
// This completion block is called when the first animation is done.
// Make sure the animation was not interrupted/cancelled :
guard finished else {
return
}
UIView.animate(withDuration: 1.0, animations: {
// And the second animation goes here
self.theTextView.contentOffset = CGPoint(x: 0, y: self.theTextView.contentSize.height)
})
})
There is also convenient way to make sequence of concurrent animations by using animateKeyframes:
UIView.animateKeyframes(withDuration: 1, delay: 0, options: .calculationModeCubic, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.3, animations: {
self.someView.alpha = 0.5
self.view.layoutIfNeeded()
})
//second animation
UIView.addKeyframe(withRelativeStartTime: 0.4, relativeDuration: 0.3, animations: {
self.someView.alpha = 1
self.view.layoutIfNeeded()
})
}, completion: { (finish) in
// Do something on animation complete
})

High CPU Usage because of UIView.animate and UIView.animateKeyframes

I have two view controllers. AnimationVC has some UIView animations, and DestinationVC has none.
I have a CPU usage problem. After I perform the segue, the animation blocks still show up in the Instruments, even though these lines belong to the AnimationVC that performs the segue.
UIView.animate(withDuration: 1.0, delay: 0.0, options: [.curveEaseInOut, .autoreverse, .repeat], animations: {
self.s1.alpha = 0.0
self.s3.alpha = 0.0
}, completion: nil)
and
let dur = 0.5/12
UIView.animateKeyframes(withDuration: 30.0, delay: 0.0, options: [.repeat, .calculationModeCubic], animations: {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: dur, animations: {
self.sc.alpha = 1.0
})
UIView.addKeyframe(withRelativeStartTime: 1.0-dur, relativeDuration: dur, animations: {
self.sc.alpha = 0.0
})
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
self.sc.transform = CGAffineTransform(rotationAngle: .pi*0.2)
})
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
self.sc.center.y = 0.1*self.frame.size.height
})
}, completion: nil)
I tried calling this destruct function...
func destruct(){
layer.removeAllAnimations()
subviews.forEach { $0.removeFromSuperview() }
}
...in
just before performing the segue
in the AnimationVC's deinit method
Still, it shows alive and hogs the CPU with 40% load. How can I destruct this?
I even reset the navigation stack on the DestinationVC with...
self.navigationController?.viewControllers = [self]
...and I see the lines of deinit from AnimationVC, the animation delay closure is still alive.
As it turns out
...
}) { (finished) in
if finished {
self.specialAniamtion(delay: 2.0)
}
}
and calling destruct() on deinit fixed it.
func destruct(){
layer.removeAllAnimations()
}

UIView.animate not animating bool value perfectly

I tried to animate isHidden, it seems working ok, but if I mistakenly animate isHidden=false 5 times by setting yes to true 5 times, then sometimes I should animate isHidden=true 2 or more time to make my UIView visible!
Am I missing something?
if (yes)
{
UIView.animate(withDuration: 0.3, delay:0, animations: {
myLabel.isHidden=false
}
}
else
{
UIView.animate(withDuration: 0.3, delay:0, animations: {
myLabel.isHidden=true
}
}
You should not animate a view's "isHidden" parameter. You should animate its alpha.
if (yes)
{
UIView.animate(withDuration: 0.3, delay:0, animations: {
myLabel.alpha=1.0
}
}
else
{
UIView.animate(withDuration: 0.3, delay:0, animations: {
myLabel.alpha=0.0
}
}
-- UPDATE --
If you want to make the view hidden after the animation you can use this:
myLabel.isHidden=false
UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveEaseOut, animations: {
myLabel.alpha=1.0
}, completion: { finished in
})
UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveEaseOut, animations: {
myLabel.alpha=0.0
}, completion: { finished in
myLabel.isHidden=true
})
I think problem is that you are using linear animation on Bool type which has only 2 values (false = 0, true = 1) and any other values between that (it's pulse).
Try this:
if (yes)
{
myLabel.alpha = 0
myLabel.isHidden = false
UIView.animate(withDuration: 0.3, animations: {
myLabel.alpha = 1
})
}
else
{
UIView.animate(withDuration: 0.3, animations: {
myLabel.alpha = 0
}, completion: { (status) in
myLabel.isHidden = true
})
}

iOS Label Visibility toggle not animating

I am trying to toggle the visibility of a UILabel based on a Tap Gesture on an UIImageView. The code that performs the toggling is as follows:
func imageTapped(img: UIImageView) {
print(photoTitle.hidden)
if (photoTitle.hidden) {
UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.photoTitle.alpha = 1
}, completion: nil)
}
else {
UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.photoTitle.alpha = 0
}, completion: nil)
}
self.photoTitle.hidden = !self.photoTitle.hidden
}
The issue with this is that it seems to ignore the animation on the second tap i.e. to hide the UILabel again. It just becomes invisible instead of animating gradually. In the viewdDidLoad(), I initialize the photoTitle.hidden = true to be invisible initially.
Any glaring mistakes?
You need to move self.photoTitle.hidden = true into the completion block of your else condition
hidden doesn't work on this animation, you can instead of alpha
Just try to change the function like this
Swift 2
func imageTapped(img: UIImageView) {
print(photoTitle.hidden)
UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.photoTitle.alpha = self.photoTitle.alpha < 0.5 ? 1.0 : 0.0
}, completion: nil)
}
Swift 3, 4, 5
func imageTapped(img: UIImageView) {
print(photoTitle.hidden)
UIView.animate(withDuration: 0.5, delay: 0, options: UIView.AnimationOptions.curveEaseInOut, animations: {
self.photoTitle.alpha = self.photoTitle.alpha < 0.5 ? 1.0 : 0.0
}, completion: nil)
}

Resources