IOS 11 UIStackView fills proportional distribution causes strange animation loading views

If I install:

stackView.distributon = .fillProportionally 

Then on iOS 11, I get a very strange animation when loading a view containing this stack view (all sub items, not just the stack view, fly from the top or bottom of the screen). In the lower version of iOS, everything works fine. If I set the stack view distribution to anything else, everything will work fine.

Can anyone understand what could be causing this problem?

Thanks.

+5
source share
3 answers

I think I found a fix - calling self.view.layoutIfNeeded() in the animations block.

Here is my reproduction:

 import UIKit class ViewController: UIViewController { var showB = true weak var viewB: UIView! override func viewDidLoad() { super.viewDidLoad() let viewA = UIView() viewA.backgroundColor = UIColor.green let toggleViewBButtonAnimated = UIButton(frame: CGRect(x: 50, y: 150, width: 200, height: 40)) toggleViewBButtonAnimated.backgroundColor = UIColor.cyan toggleViewBButtonAnimated.setTitle("Toggle B (animated)", for: .normal) viewA.addSubview(toggleViewBButtonAnimated) toggleViewBButtonAnimated.addTarget(self, action: #selector(toggleBButtonTappedAnimated), for: .touchUpInside) let viewB = UIView() viewB.backgroundColor = UIColor.orange let viewBHeightConstraint = viewB.heightAnchor.constraint(equalToConstant: 200) viewBHeightConstraint.priority = 999 viewBHeightConstraint.isActive = true self.viewB = viewB let stackView = UIStackView(arrangedSubviews: [viewA, viewB]) stackView.axis = .vertical stackView.alignment = .fill stackView.distribution = .fill stackView.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(stackView) stackView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true } @IBAction func toggleBButtonTappedAnimated() { self.showB = !self.showB UIView.animate(withDuration: 0.3, animations: { self.viewB.isHidden = !self.showB; self.view.layoutIfNeeded() } ) } } 

This controller sets up a UIStackView , which has two vertical views, green (A) and orange (B). Pressing the button hides / hides view B.

If I don't have self.view.layoutIfNeeded() in the animations block, then when view B is displayed, it flies to the top of the screen. (When view B is hidden, it usually hides - moving down from the bottom of the screen.)

When I added self.view.layoutIfNeeded() to the animations block, view B shows as expected - it appears at the bottom of the screen.

Thanks to the answer from @ g3rv4 for pointing me in that direction!

+9
source

This morning I ran into the same problem using GM seeds. I ended up using the UIView.performWithoutAnimation { block to make any modifications to the UIStackView where animations are not yet desirable.

+1
source

For me, the problem was a regression of behavior introduced in iOS 11 and having nothing to do with the UIStackView distribution type. I tried a couple of software solutions to no avail: first, calling layoutIfNeeded in the container hierarchy; secondly (as seen in another answer to a similar question), adjusting the content of contentMode views.

My hacked solution is as follows:

Add a new, zero-width UIView placeholder on the UIStackView side, where the show animation incorrectly inserted elements from the edge of the screen.

0
source

Source: https://habr.com/ru/post/1271227/


All Articles