Reputation: 1550
My app has 2 screens:
TableViewVC (no stack views here)
DetailVC (all the nested stack views here; please see link for picture: Nested StackViews Picture) -- Note, there are labels and images within these stack views.
When you press a cell in the tableview, it passes the information from the TableViewVC to the DetailVC. The problem is with hiding the specific UIStackViews in the DetailVC. I want only 2 stack views out of the various ones in the DetailVC to be hidden as soon as the view loads. So I write this code in the DetailVC to accomplish this:
override func viewDidLoad() {
super.viewDidLoad()
self.nameLabel.text = "John"
self.summaryStackView.hidden = true
self.combinedStackView.hidden = true
}
Everything looks great but Xcode give many warnings only at runtime. There are no warning in Storyboard when the app is not running. Please see link for picture of errors: Picture of Errors
Basically it's a lot of UISV-hiding, UISV-spacing, UISV-canvas-connection errors. These errors go away if I hide the same stack views in viewDidAppear
but then there is a flash of the stuff that was supposed to be hidden and then it hides. The user sees the the view briefly and then it hides which is not good.
Sorry for not being able to actually post pictures instead of links, still can't do so.
Any suggestions on how to fix this? This is for an app I actually want to launch to the app store - it's my first so any help would be great!
Edit/ Update 1:
I found a small work around with this code which I put inside the second screen called DetailVC:
// Function I use to delay hiding of views
func delay(delay: Double, closure: ()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
// Hide the 2 stack views after 0.0001 seconds of screen loading
override func awakeFromNib() {
delay(0.001) { () -> () in
self.summaryStackView.hidden = true
self.combinedStackView.hidden = true
}
}
// Update view screen elements after 0.1 seconds in viewWillAppear
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
delay(0.1) { () -> () in
self.nameLabel.text = "John"
}
}
This gets rid of the warnings about layout constraints completely from Xcode.
It's still not perfect because sometimes I see a glimpse of the views that are supposed to be hidden -- they flash really quick on the screen then disappear. This happens so quickly though.
Any suggestions as to why this gets rid of warnings? Also, any suggestions on how to improve this to work perfectly??? Thanks!
Upvotes: 29
Views: 42099
Reputation: 2674
Have you tried this? Calling super
after your changes?
override func viewWillAppear() {
self.nameLabel.text = "John"
self.summaryStackView.hidden = true
self.combinedStackView.hidden = true
super.viewWillAppear()
}
Upvotes: -4
Reputation: 3607
If you're having issues animating HIDING AND SHOWING subviews at the same time, repeating the .isHidden instructions in the animation completion may help. See my answer here for more detail on that.
Upvotes: 0
Reputation: 6772
So, this may only help 0.000001% of users but maybe this is a clips to bounds issue.
I ran into this recently when working with UICollectionViewCell
I forgot to check clips to bounds on the view I was treating as my content view. When you create a UITableViewCell
in IB it sets up a content view with clips to bounds as the default.
Point is, depending on your situation you may be able to accomplish your intended effect using frames and clipping.
Upvotes: 1
Reputation: 161
I did this by storing all the hidden views of the nested UIStackView in an array and removing them from the superview and arranged subviews. When I wanted them to appear again I looped through the array and added them back again. This was the first step.
The second step is after you remove the views of the nested UIStackView from the superview the parent UIStackView still doesn't adjust it's height. You can fix this by removing the nested UIStackView and adding it again straight afterwards:
UIStackView *myStackView;
NSUInteger positionOfMyStackView = [parentStackView indexOfObject:myStackView];
[parentStackView removeArrangedSubview:myStackView];
[myStackView removeFromSuperview];
[parentStackView insertArrangedSubview:myStackView atIndex:positionOfMyStackView];
Upvotes: 0
Reputation: 2836
I've found that nested UIStackViews show this behavior if you set the hidden property in ✨Interface Builder✨. My solution was to set everything to not hidden in ✨Interface Builder✨, and hide things in viewWillAppear selectively.
Upvotes: 3
Reputation: 91931
This is a known problem with hiding nested stack views.
There are essentially 3 solutions to this problem:
innerStackView.removeFromSuperview()
, but then you'll need to remember where to insert the stack view.The 3rd option is the best in my opinion. For more information about this problem, why it happens, the different solutions, and how to implement solution 3, see my answer to a similar question.
Upvotes: 35
Reputation: 4125
When the UIViewStack is hidden, the constraints automatically generated by the UIStackView will throw lots of UISV-hiding, UISV-spacing, UISV-canvas-connection warnings, if the UIStackView's spacing property has any value other than zero.
This doesn't make much sense, it's almost certainly a framework bug. The workaround I use is to set the spacing to zero when hiding the component.
if hideStackView {
myStackView.hidden = true
myStackView.spacing = CGFloat(0)
} else {
myStackView.hidden = false
myStackView.spacing = CGFloat(8)
}
Upvotes: 3
Reputation: 1137
You can use the removeArrangedSubview and removeFromSuperview property of UIStackView.
In Objective-C :
[self.topStackView removeArrangedSubview:self.summaryStackView];
[self.summaryStackView removeFromSuperview];
[self.topStackView removeArrangedSubview:self.combinedStackView];
[self.combinedStackView removeFromSuperview];
From Apple UIStackView Documentation:(https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIStackView_Class_Reference/#//apple_ref/occ/instm/UIStackView/removeArrangedSubview:)
The stack view automatically updates its layout whenever views are added, removed or inserted into the arrangedSubviews array.
To prevent the view from appearing on screen after calling the stack’s removeArrangedSubview: method, explicitly remove the view from the subviews array by calling the view’s removeFromSuperview method, or set the view’s hidden property to YES.
Upvotes: 8
Reputation: 179
I fixed it by putting the hide commands in traitCollectionDidChange.
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
self.item.hidden = true
}
Upvotes: 1
Reputation: 31
I moved all UIStackView.hidden code from viewDidLoad to viewDidAppear and broken constraints problem went away. In my case all conflicting constraints were auto generated, so no way to adjust priorities.
I also used this code to make it prettier:
UIView.animateWithDuration(0.5) {
self.deliveryGroup.hidden = self.shipVia != "1"
}
EDIT:
Also needed the following code to stop it from happening again when device is rotated:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
self.deliveryGroup.hidden = false
coordinator.animateAlongsideTransition(nil) {
context in
self.deliveryGroup.hidden = self.shipVia != "1"
}
}
Upvotes: 1
Reputation: 3886
I had the same problem and I fixed it by giving the height constraints of my initially hidden views a priority of 999.
The problem is that your stackview applies a height constraint of 0 on your hidden view which conflicts with your other height constraint. This was the error message:
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fa3a5004310 V:[App.DummyView:0x7fa3a5003fd0(40)]>",
"<NSLayoutConstraint:0x7fa3a3e44190 'UISV-hiding' V:[App.DummyView:0x7fa3a5003fd0(0)]>"
)
Giving your height constraint a lower priority solves this problem.
Upvotes: 88
Reputation: 4623
This error is not about hiding, but about ambiguous constraints. You must not have any ambiguous constraints in your view. If you add them programmatically you should exactly understand what constraints you add and how they work together. If you do not add them programmatically, but use storyboard or xib, which is a good place to start, make sure there are no constraint errors or warnings.
UPD: You have a pretty complex structure of views there. Without seeing the constraints is hard to say what exactly is wrong. However, I would suggest to build you view hierarchy gradually adding views one by one and making sure there are no design-time/runtime warnings. Scroll view may add another level of complexity if you do not handle it correctly. Find out how to use constraints with a scroll view. All other timing hacks is not a solution anyway.
Upvotes: 1