UIStackView - hide and collapse subview with animation
Asked Answered
P

5

20

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?

Profane answered 5/1, 2019 at 18:39 Comment(4)
Is it possible to modify the subview's height? In the animation block, set the height and alpha to 0, and on completion you can reset the height and alpha while setting the isHidden to trueDeidredeific
@Andrey if possible will you please show us what is currently doing with your animation? and one more thing if you are hide your label then why you set alpha?Frankenstein
I haven’t attempted this... is the solution as simple as adding the key showHideTransitionViews in the array of UIView.AnimationOptions... Apple docs state “this key causes views to be hidden or shown (instead of removed or added)...”.Chlores
I tried your code and found the label slowly collapsed and became invisible finally. What effect do you expect if not this?Impinge
S
35

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

Arranged Subview Animation Gif

Stator answered 11/1, 2019 at 12:26 Comment(1)
fwiw, works well with labels outside of stackviews as wellSunshine
S
4

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
}
Shaunna answered 5/1, 2019 at 19:2 Comment(1)
Thanks for your answer, but setting isHidden in completion block doesn't work for me: as I said, I want to achieve collapse animation as well. In this case the subview will be collapsed without any animation after alpha was animated to 0Profane
K
3

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

initialScreen

animated

Kinny answered 9/1, 2019 at 5:52 Comment(0)
F
1

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
        }

    })
}
Flunkey answered 9/1, 2019 at 6:3 Comment(0)
C
-2

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()
}
Castora answered 8/1, 2019 at 7:39 Comment(4)
Thanks, but this approach doesn't fade the subview (doesn't change its alpha). It only collapses the subviewProfane
similarly write self.stackView.subviews[INDEX_OF_LABEL_IN_STACK]?.alpha = 0 you can achieve what you want, if still you doesn't achieve what you want please share a screenshot of stackview with meBesought
That's exactly what I was trying, please see code in my question above. That code doesn't work properlyProfane
You should not call layoutSubviews() directly. If you want to force a layout update, call the setNeedsLayout() method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded() method.Oren

© 2022 - 2024 — McMap. All rights reserved.