18

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?

Mehul Thakkar
  • 12,440
  • 10
  • 52
  • 81
Andrey Gordeev
  • 30,606
  • 13
  • 135
  • 162
  • 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 true – Mocha Jan 07 '19 at 20:23
  • 1
    @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? – Chirag Shah Jan 08 '19 at 07:54
  • I haven’t attempted this... is the solution as simple as adding the key `showHideTransitionViews` in the array of `UIView.AnimationOptions`... [Apple docs](https://developer.apple.com/documentation/uikit/uiview/animationoptions/1622462-showhidetransitionviews) state “this key causes views to be hidden or shown (instead of removed or added)...”. – andrewbuilder Jan 08 '19 at 10:53
  • 1
    I tried your code and found the label slowly collapsed and became invisible finally. What effect do you expect if not this? – E.Coms Jan 09 '19 at 01:31

5 Answers5

33

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

Wez
  • 10,555
  • 5
  • 49
  • 63
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
}
ZGski
  • 2,398
  • 1
  • 21
  • 34
  • 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 0 – Andrey Gordeev Jan 06 '19 at 04:13
2

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

Kathiresan Murugan
  • 2,783
  • 3
  • 23
  • 44
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
        }

    })
}
Abdelahad Darwish
  • 5,969
  • 1
  • 17
  • 35
-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()
}
Sand'sHell811
  • 358
  • 3
  • 15
  • Thanks, but this approach doesn't fade the subview (doesn't change its alpha). It only collapses the subview – Andrey Gordeev Jan 08 '19 at 10:03
  • 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 me – Sand'sHell811 Jan 08 '19 at 10:22
  • That's exactly what I was trying, please see code in my question above. That code doesn't work properly – Andrey Gordeev Jan 08 '19 at 10:31
  • 1
    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. – Artem Kirillov Jun 08 '20 at 09:28