UIStackView Hide Animation not working properly [duplicate] - ios

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()
}

Related

updating width of custom view is not going in the right direction

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?

Animate UIView using swift 4.2 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Someone, please help me with this animation, When I click on X button the cardView move out form screen with 0.3 seconds after that card comes back it's an original position(that is center of the parent view) with fade animation. Same thing for right side when users click on the ✅ button the card should move right.
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
self.cardView.frame.origin.x = self.cardView.frame.minX - (self.cardView.frame.width + 100)
self.cardView.transform = CGAffineTransform(rotationAngle:-45)
}) { (true) in
self.cardView.center = self.view.center
self.cardView.alpha = 0;
self.cardView.transform = CGAffineTransform.identity
UIView.animate(withDuration: 0.5, animations: {
self.cardView.alpha = 1.0;
}, completion: { (true) in
})
}
Example of Image -
I believe that your main issue is that you don't call the layoutIfNeeded() function that actually makes the animation happens. check documentation. Try this function it should do what you want.
func doAnimationAction(isTick: Bool) {
let originToReturn = CGPoint(x: self.view.frame.origin.x, y: self.cardView.frame.origin.y)
UIView.animate(withDuration: 0.5, animations: {
self.cardView.alpha = 0.0
if isTick {
// Go left
self.cardView.frame.origin.x = 0 - (self.cardView.frame.width * 1.5)
} else {
// Go right (you can change them)
self.cardView.frame.origin.x = self.view.frame.width + (self.cardView.frame.width * 1.5)
}
self.cardView.transform = CGAffineTransform(rotationAngle:-45)
self.cardView.layoutIfNeeded()
self.cardView.superview?.layoutIfNeeded()
}) { (finished) in
// Here you can update the cardViewData
UIView.animate(withDuration: 0.5, animations: {
self.cardView.transform = CGAffineTransform(rotationAngle:0)
self.cardView.frame.origin = originToReturn
self.cardView.alpha = 1.0
self.cardView.layoutIfNeeded()
self.cardView.superview?.layoutIfNeeded()
}, completion: { (finishedSecondAnimation) in
})
}
}

UIStackView - hide and collapse subview with animation

I'm trying to hide UIStackView's subview like this:
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 2.0,
delay: 0, options: [.curveEaseOut], animations: {
self.label.isHidden = true
self.label.alpha = 0.0
self.stackView.layoutIfNeeded()
})
However, the label disappears instantly with using this code. I suspect this is because of setting isHidden to true, which is required for collapsing.
Is there a way how to hide and collapse UIStackView's subvew with animation? Or it might be better to not to use UIStackView at all?
According to Apple's documentation:
You can animate both changes to the arranged subview’s isHidden property and changes to the stack view’s properties by placing these changes inside an animation block.
I've tested the below code using iOS 12.1 Simulator and it works as expected.
UIView.animate(
withDuration: 2.0,
delay: 0.0,
options: [.curveEaseOut],
animations: {
self.label.isHidden = true
self.label.alpha = 0.0
})
You can animate view properties like alpha, color, etc. However, some things happen instantly - isHidden in this case.
Here's an example using UIView.animate:
UIView.animate(withDuration: 2, delay: 0, options: .curveEaseOut, animations: {
self.label.alpha = 0 // Changes the label's layer alpha value
}, completion: { finished in
self.label.isHidden = true // Hides the label
self.label.layer.alpha = 1 // Resets the label's alpha without un-hiding it
})
Using UIViewPropertyAnimator:
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 2, delay: 0, options: .curveEaseOut, animations: {
self.label.alpha = 0 // Sets the label's alpha
}) { _ in
self.label.isHidden = true // Hides the label
self.label.alpha = 1 // Resets the label's alpha without un-hiding it
}
I have tried your code. Its animating
if self.stackView.subviews.count > 0 {
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 1.0, delay: 0, options: [.curveEaseOut], animations: {
self.stackView.subviews[0].isHidden = true
self.stackView.subviews[0].alpha = 0.0
self.stackView.layoutIfNeeded()
}) { (position) in
self.stackView.subviews[0].removeFromSuperview()
}
}
Just you can use simple solution with animateKeyframes to fade alpha , then hide , i think this will give you what you need So hide after 1 Sec and 0.8 Sec fading
// showLabel is Bool to handle status declare it at you File
#IBAction func toggleStackLabelTapped(_ sender: UIButton) {
showLabel = !showLabel
UIView.animateKeyframes(withDuration: 1, delay: 0, options: .calculationModeLinear, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.8) {
self.label.alpha = (self.showLabel) ? 1 : 0
}
UIView.addKeyframe(withRelativeStartTime: 0.8, relativeDuration: 1) {
self.label.isHidden = !self.showLabel
}
})
}
make sure you have not given height constraint to the stackview.
and try this.
UIView.animate(withDuration: 0.5) {
self.stackView.subviews[INDEX_OF_LABEL_IN_STACK]?.alpha = 0
self.stackView.subviews[INDEX_OF_LABEL_IN_STACK]?.isHidden = true
self.view.layoutSubviews()
}

UIView animation with autolayout and child views

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)
})
}

iOS Animate height constraint issue

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()
})

Resources