Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hidden property cannot be changed within an animation block

I've got two UILabels embedded within a UIStackView. The top label stays visible constantly, but the bottom label is toggled on and off via the hidden property. I wanted this effect to be animated, so I stuck it in an animation block:

private func toggleResultLabel(value:Double) {
    if value == 0 {
        UIView.animateWithDuration(0.25) { () -> Void in
            self.resultLabel.hidden = true
        }
    } else {
        UIView.animateWithDuration(0.25) { () -> Void in
            // Something weird is happening. I had to add 3 of the same statements to get 
            // the hidden flag to be false
            self.resultLabel.hidden = false
            self.resultLabel.hidden = false
            self.resultLabel.hidden = false
        }
    }
}

The problem is that the hidden property will not change unless I repeat the statement over and over (3 times in this case). I found this while breaking into the animation closure and seeing that the property would not change to it's assignment. Now I'm noticing the same problem occurring seemingly randomly again. The default value of the second label is true, if that's relevant.

Is there something I'm missing here, or is this a bug?

Update: For what it's worth, I got it working by adding removeArrangedSubview() and addArrangedSubview():

if value == 0 {
    UIView.animateWithDuration(0.25) { () -> Void in
        self.resultLabel.hidden = true
        self.heroStackView.removeArrangedSubview(self.resultLabel)
    }
 } else {
    UIView.animateWithDuration(0.25) { () -> Void in
        self.heroStackView.addArrangedSubview(self.resultLabel)
        self.resultLabel.hidden = false
    }
 }
like image 842
Alex Avatar asked Oct 20 '15 15:10

Alex


2 Answers

On iOS 11 and prior, when hiding an arrangedSubview of a UIStackView using UIView animation API multiple times, the hidden property values "stack", and it requires setting hidden to false multiple times before the value actually changes.

At work we decided to use a UIView extension with a workaround method that sets hidden only once for given value.

extension UIView {

    // Workaround for the UIStackView bug where setting hidden to true with animation
    // mulptiple times requires setting hidden to false multiple times to show the view.
    public func workaround_nonRepeatingSetHidden(hidden: Bool) {
        if self.hidden != hidden {
            self.hidden = hidden
        }
    }
}

This is definitely a bug in UIKit, check out the sample project that reproduces it clearly.

enter image description here

like image 88
Nikita Kukushkin Avatar answered Nov 20 '22 02:11

Nikita Kukushkin


In considering UIStackView bug I decide to check hidden property.

if myView.hidden != hidden {
   myView.hidden = hidden
}

It's not the most elegant solution but it works for me.

like image 8
CHiP-love-NY Avatar answered Nov 20 '22 01:11

CHiP-love-NY