I have a problem with the animation of a view after changing it's height constraint. In the screenshot, you can see it's initial value of 120.0.
The animation works but the constraint update from my second view (the blue one) happens directly and not during the animation. This means that second view jumps to the top directly.
With the following code, I will animate the change of the height constraint:
UIView.animate(withDuration: 3.0, animations: {
self.heightConstraint?.constant = 0.0
self.myLabel.alpha = 0.0
self.layoutIfNeeded()
})
Does anybody know why?
self.heightConstraint?.constant = 0.0
self.myLabel.alpha = 0.0
UIView.animate(withDuration: 3.0, animations: {
self.layoutIfNeeded()
})
It should be like this.
For animating constraint changes, you need to write code like below to work.
self.heightConstraint?.constant = 0.0
self.myLabel.alpha = 0.0
UIView.animate(withDuration: 5) {
self.layoutIfNeeded()
}
You need to call self.layoutIfNeeded() before and after updating constraint constant. Change your code to :
self.layoutIfNeeded()
UIView.animate(withDuration: 3.0, animations: {
self.heightConstraint?.constant = 0.0
self.myLabel.alpha = 0.0
self.layoutIfNeeded()
})
Related
I've created a custom view. added width, height, and centerY constraints.
I used it in a storyboard.
I want to add a label, increase the width animately. and after 1.5 seconds I need to remove the label and decrease the width animatedly.
I wrote the below code inside my custom view.
fileprivate func unfoldMeAnimatedly() {
self.labelLeadingToStatusImageView.isActive = true
self.updateStatusLabel()
self.layoutIfNeeded()
self.constraints.forEach { (constraint) in
if constraint.identifier == "widthOfCardDraftStatus" {
constraint.constant = 95
}
}
UIView.animate(withDuration: 0.6, delay: 0.0, options: UIView.AnimationOptions.curveLinear, animations: {
self.layoutIfNeeded()
}) { (finished) in
}
}
fileprivate func foldMeAnimatedly() {
self.constraints.forEach { (constraint) in
if constraint.identifier == "widthOfCardDraftStatus" {
constraint.constant = 24
}
}
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveLinear, animations: {
//self.statusLabel.alpha = 0.0
self.layoutIfNeeded()
}) { (finished) in
}
}
invoking animations
unfoldMeAnimatedly()
DispatchQueue.main.asyncAfter(deadline: .now()+1.5) {
self.foldMeAnimatedly()
}
privew of result:
I did not understand why it is moving. the desired one is just the width needs to be increased/decrease at only one end. i.e right side.
Few observations:
It's strange that I changed the animation durations to 0.5, 0.5 and wait time to 0.5. now it is working as expected.
Why like this? Anybody can explain why it's behaving like this or some issue with code?
This question already has answers here:
UIStackView Hide View Animation
(6 answers)
Closed 4 years ago.
I don't know what is going on but this will happened a lot of time to me. I used UIStackView for arranging the view and animation but when I hide the control in UIStackView there will be some sort of weird animation is there. Here I attached video and code.
UIView.animate(withDuration: 0.5, animations: {
self.viewCollectionSpecies.isHidden = true
})
Finally i got clue what is issue. There will be one height constraint which I need to forgot to remove after removing that constraint it work perfectly.
self.heightConstraint.constant = 0.0
UIView.animate(withDuration: 0.5, animations: {
self.viewCollectionSpecies.isHidden = true
self.layoutIfNeeded()
})
Try
self.viewCollectionSpecies.alpha = 0
UIView.animate(withDuration: 0.5, animations: {
self.viewCollectionSpecies.isHidden = true
self.stackView.layoutIfNeeded()
})
Or
self.viewCollectionSpecies.isHidden = true
UIView.animate(withDuration: 0.5, animations: {
self.stackView.layoutIfNeeded()
})
Try working with the alpha value:
func changeViewTo(newView: UIView, oldView: UIView) {
newView.isHidden = false
newView.alpha = 0
UIView.animate(withDuration:0.4, animations: {
oldView.alpha = 0
newView.alpha = 1
}) { (result: Bool) in
oldView.isHidden = true
}
layoutIfNeeded()
self.stackView.layoutIfNeeded()
}
I write this following code :
if !self.headerIsCollapsed{
self.headerIsCollapsed = true
self.heightProfilView.constant -= (self.view.bounds.height / 5)
UIView.animate(withDuration: 0.3, animations: {
self.imageUserProfil.layer.opacity = 0
self.view.layoutIfNeeded()
})
print(self.heightProfilView.constant)
print(self.topUserProfilView.bounds.height)
}
My question is: Why the value of the two print() is not the same ?
I need the value of self.topUserProfilView.bounds.height Before animate this for another function, would there be another way to catch this value before?
thanks
try this: it should work
if !self.headerIsCollapsed{
self.headerIsCollapsed = true
self.heightProfilView.constant -= (self.view.bounds.height / 5)
UIView.animate(withDuration: 0.3, animations: {
self.imageUserProfil.layer.opacity = 0
self.view.layoutIfNeeded()
}) { (isCompleted) in
print(self.heightProfilView.constant)
print(self.topUserProfilView.bounds.height)
}
}
P.S: This solution would not work if you added the heightProfilView constraint relative to the any view height as here you are changing the constant but in the IB you have assigned the multiplier so in that case the default constant value is 0. So, this approach will not work for the relative height constraint. as we can't change the multiplier of a constraint.
Maybe you have constraints taking priority. Check out your console output when you collapse the row, there should be some loud output involving constraints.
Also try hiding imageUserProfil
self.imageUserProfil.layer.opacity = 0
self.imageUserProfil.isHidden = true
You need completion block to do it...Just replace your animation method as below
UIView.animate(withDuration: 0.3, animations: {
self.imageUserProfil.layer.opacity = 0
self.view.layoutIfNeeded()
}) { (isDone) in
print(self.heightProfilView.constant)
print(self.topUserProfilView.bounds.height)
}
Hope it will work.
I have a weird problem that seems to be fairly easy to solve. I think I could use some workaround to be able to have the behavior that I want but I want to know if there is a better way to do it.
I have a view called contentView (blue in the image) that it will expand its height using a UIView.animation, this is no problem at all and works as expected.
The problem here is that this view has a child component (a button) that has an autolayout constraint to its bottom equal to 22 like this:
This is the autolayout constraint:
If I do the height resize without the animation it works fine, the view height change and the button are always 22 points of the bottom of the contentView. But when I use an animation to make this change more smoothy and user-friendly the button moves to the end position before the animation even start.
I want to know how I could achieve a smooth animation here but with the button moving along its parent view
The part of the code that handles the animation is pretty straightforward but I'll post it in here:
#IBAction func openDetail(_ sender: ExpandCourseDetail) {
let rotation = sender.getOpen() ? CGAffineTransform.identity : CGAffineTransform(rotationAngle: CGFloat.pi)
UIView.animate(withDuration: 0.5, delay: 0.1, options: [.curveEaseInOut], animations: {
sender.transform = rotation
}, completion: {
success in
sender.setOpen(!sender.getOpen())
})
UIView.animate(withDuration: 1.0, delay: 0.5, options: [.curveEaseInOut], animations: {
self.contentView.frame.size.height = sender.getOpen() ? self.contentView.frame.height - 300 : self.contentView.frame.height + 300
}, completion: nil)
}
As a side note, the button itself has an animation that rotates the button 180 degrees to show the user that the view is expanding.
Thank you so much for your help.
It's super easy with constraints, just create a superView height constraint IBOutlet and change its constant value.
#IBAction func btnPressed(_ sender: UIButton) {
self.toggleButton.isSelected = !sender.isSelected
//Animation starts here
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.7) {
if self.toggleButton.isSelected {
//transform button
self.toggleButton.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
//change your ParentView height to desired one
self.constContentViewHeight.constant = self.view.frame.size.height - 220
self.view.layoutIfNeeded()
} else {
self.toggleButton.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi*2))
// Set height constraint to original value
self.constContentViewHeight.constant = 250
self.view.layoutIfNeeded()
}
}
}
I have created a demo, check it out.
The issue you are facing is due to two animation blocks. So I have changed some lines and put both button transformation and height animation into one animation block.
func openDetail(_ sender: ExpandCourseDetail) {
let isOpen = sender.getOpen() ? CGAffineTransform.identity : CGAffineTransform(rotationAngle: CGFloat.pi)
UIView.animate(withDuration: 1.0, delay: 0.5, options: [.curveEaseInOut], animations: {
sender.transform = rotation
self.contentView.frame.size.height = self.contentView.frame.height + (isOpen ? 300 : -300)
}, completion: { (success) in
sender.setOpen(!isOpen)
})
}
I have view sView inside my ViewController. It height has constraint - I created IBOutlet for this constraint - sViewHeightConstraint. I want to decrease height of sView with animation.
I created function
UIView.animateWithDuration(5.5, animations: {
self.sViewHeightConstraint.constant = 50
})
Height of view is changing but i don't see any animation. What I am doing wrong?
use layoutIfNeeded()
view.layoutIfNeeded() // force any pending operations to finish
UIView.animateWithDuration(0.2, animations: { () -> Void in
self.sViewHeightConstraint.constant = 50
self.view.layoutIfNeeded()
})
swift 3
view.layoutIfNeeded()
sViewHeightConstraint.constant = 50
UIView.animate(withDuration: 1.0, animations: {
self.view.layoutIfNeeded()
})
In case your view updates but animation isn't working, this solution works for me.
UIView.animate(withDuration: 0.2, animations: {
self.sViewHeightConstraint.constant = 50
self.sView.size = CGSize(width: self.sView.frame.width, height: 50)
self.view.layoutIfNeeded()
})