UIStackView – 隐藏堆栈视图时的布局约束问题

我的应用有2个屏幕:

  1. TableViewVC(这里没有堆栈视图)

  2. DetailVC(此处所有嵌套堆栈视图;请参见图片链接: 嵌套StackViews图片 ) – 注意,这些堆栈视图中有标签和图像。

当您按下tableview中的单元格时,它会将信息从TableViewVC传递到DetailVC。 问题是隐藏DetailVC中的特定UIStackViews。 我希望只要视图加载,就会隐藏DetailVC中各个窗口中的2个堆栈视图。 所以我在DetailVC中编写这段代码来完成这个:

override func viewDidLoad() { super.viewDidLoad() self.nameLabel.text = "John" self.summaryStackView.hidden = true self.combinedStackView.hidden = true } 

一切看起来都很棒,但Xcode只在运行时发出许多警告。 应用程序未运行时,Storyboard中没有警告。 请参阅错误图片的链接:错误图片

基本上它是很多UISV隐藏,UISV间距,UISV-canvas连接错误。 如果我在viewDidAppear隐藏相同的堆栈视图,那么这些错误就会消失,但是有一些闪存的东西应该被隐藏然后隐藏起来。 用户简要地看到视图然后隐藏哪个不好。

很抱歉由于无法实际发布图片而非链接,仍然无法发布。

对于如何解决这个问题,有任何的建议吗? 这是我想要推出到应用程序商店的应用程序 – 这是我的第一个,所以任何帮助都会很棒!

编辑/更新1:

我在这个代码中找到了一个小工作,我把它放在名为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" } } 

这完全消除了Xcode中关于布局约束的警告。

它仍然不完美,因为有时我会看到一些应该被隐藏的视图 – 它们在屏幕上快速闪烁然后消失。 这种情况发生得如此之快。

有关为什么要摆脱警告的任何建议? 此外,任何关于如何改善这个完美工作的建议??? 谢谢!

你有没有试过这个,在你改变之后打电话给超级?

 override func viewWillAppear() { self.nameLabel.text = "John" self.summaryStackView.hidden = true self.combinedStackView.hidden = true super.viewWillAppear() } 

我有同样的问题,我通过给出我最初隐藏的视图的高度限制优先级为999来修复它。

在此处输入图像描述

问题是您的stackview在隐藏视图上应用了高度约束0,这与您的其他高度约束冲突。 这是错误消息:

 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) ( "", "" ) 

赋予您的高度约束优先级较低可解决此问题。

这是隐藏嵌套堆栈视图的已知问题。

这个问题基本上有3个解决方案:

  1. 将间距更改为0,但是您需要记住之前的间距值。
  2. 调用innerStackView.removeFromSuperview() ,但是你需要记住插入堆栈视图的位置。
  3. 在具有至少一个999约束的UIView中包装堆栈视图。 例如Top,Leading,Trailing @ 1000,Bottom @ 999。

在我看来,第三种选择是最好的。 有关此问题的更多信息,为什么会发生,不同的解决方案以及如何实现解决方案3,请参阅我对类似问题的回答 。

您可以使用UIStackView的removeArrangedSubview和removeFromSuperview属性。

在Objective-C中:

  [self.topStackView removeArrangedSubview:self.summaryStackView]; [self.summaryStackView removeFromSuperview]; [self.topStackView removeArrangedSubview:self.combinedStackView]; [self.combinedStackView removeFromSuperview]; 

来自Apple UIStackView文档:( https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIStackView_Class_Reference/#//apple_ref/occ/instm/UIStackView/removeArrangedSubview 🙂

每当添加,删除或插入到excludedSubviews数组中的视图时,堆栈视图都会自动更新其布局。

  • removeArrangedSubview:此方法从堆栈的arrangeSubviews数组中删除提供的视图。 视图的位置和大小将不再由堆栈视图管理。 但是,此方法不会从堆栈的子视图数组中删除提供的视图; 因此,视图仍显示为视图层次结构的一部分。

要在调用堆栈的removeArrangedSubview:方法后阻止视图出现在屏幕上,请通过调用视图的removeFromSuperview方法从子视图数组中显式删除视图,或将视图的hidden属性设置为YES。

当隐藏UIViewStack时,如果UIStackView的spacing属性具有除零之外的任何值,则UIStackView自动生成的约束将抛出大量UISV隐藏,UISV间距,UISV-canvas连接警告。

这没有太大意义,它几乎肯定是一个框架错误。 我使用的解决方法是在隐藏组件时将间距设置为零。

 if hideStackView { myStackView.hidden = true myStackView.spacing = CGFloat(0) } else { myStackView.hidden = false myStackView.spacing = CGFloat(8) } 

我将所有UIStackView.hidden代码从viewDidLoad移动到viewDidAppear,并且破坏的约束问题消失了。 在我的情况下,所有冲突的约束都是自动生成的,因此无法调整优先级。

我也使用这段代码使它更漂亮:

 UIView.animateWithDuration(0.5) { self.deliveryGroup.hidden = self.shipVia != "1" } 

编辑:

还需要以下代码来阻止设备旋转时再次发生:

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

我通过将hide命令放在traitCollectionDidChange中来修复它。

 override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) self.item.hidden = true } 

我发现如果在✨InterfaceBuilder✨中设置隐藏属性,嵌套的UIStackViews会显示此行为。 我的解决方案是将所有内容设置为不隐藏在✨InterfaceBuilder✨中,并有选择地隐藏viewWillAppear中的内容。

将隐藏命令放在viewWillLayoutSubviews() {}

这个错误不是关于隐藏,而是关于模棱两可的约束。 您的视图中不得有任何不明确的约束。 如果以编程方式添加它们,则应准确了解添加的约束以及它们如何协同工作。 如果您不以编程方式添加它们,但使用storyboard或xib(这是一个好的起点),请确保没有约束错误或警告。

UPD:那里有一个相当复杂的视图结构。 没有看到约束很难说究竟是什么错。 但是,我建议逐步构建视图层次结构逐个添加视图,并确保没有设计时/运行时警告。 如果您没有正确处理它,滚动视图可能会增加另一个复杂程度。 了解如何使用滚动视图使用约束。 所有其他计时黑客无论如何都不是解决方案。

我这样做是通过将嵌套的UIStackView的所有隐藏视图存储在一个数组中,并从superview和排列的子视图中删除它们。 当我希望它们再次出现时,我循环通过arrays并再次添加它们。 这是第一步。

第二步是从superview中删除嵌套UIStackView的视图后,父UIStackView仍然不调整它的高度。 您可以通过删除嵌套的UIStackView并在之后再次添加它来解决此问题:

 UIStackView *myStackView; NSUInteger positionOfMyStackView = [parentStackView indexOfObject:myStackView]; [parentStackView removeArrangedSubview:myStackView]; [myStackView removeFromSuperview]; [parentStackView insertArrangedSubview:myStackView atIndex:positionOfMyStackView];