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

时间:2015-11-11 01:41:08

标签: ios swift uistackview

我的应用有2个屏幕:

  1. TableViewVC(此处没有堆栈视图)

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

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

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

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

    基本上它有很多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中删除了有关布局约束的警告。

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

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

13 个答案:

答案 0 :(得分:80)

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

enter image description here

问题是你的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) 
(
    "<NSLayoutConstraint:0x7fa3a5004310 V:[App.DummyView:0x7fa3a5003fd0(40)]>",
    "<NSLayoutConstraint:0x7fa3a3e44190 'UISV-hiding' V:[App.DummyView:0x7fa3a5003fd0(0)]>"
)

将高度限制设为较低优先级可以解决此问题。

答案 1 :(得分:24)

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

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

  1. 将间距更改为0,但是您需要记住之前的间距值。
  2. 调用innerStackView.removeFromSuperview(),但是您需要记住插入堆栈视图的位置。
  3. 在具有至少一个999约束的UIView中包装堆栈视图。例如。 Top,Leading,Trailing @ 1000,Bottom @ 999。
  4. 第三种选择在我看来是最好的。有关此问题的更多信息,原因,不同的解决方案以及如何实施解决方案3,请参阅my answer to a similar question

答案 2 :(得分:8)

您可以使用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:)

只要在placementSubviews数组中添加,删除或插入视图,堆栈视图就会自动更新其布局。

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

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

答案 3 :(得分:2)

当隐藏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)
}

答案 4 :(得分:1)

我将所有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"
    }
}

答案 5 :(得分:1)

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

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

答案 6 :(得分:1)

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

答案 7 :(得分:1)

因此,这可能仅能帮助0.000001%的用户,但这也许是限幅问题。

我最近在与%{format%}一起工作时遇到了这个问题,我忘记检查在我视为内容视图的视图上的边界剪辑。当您在IB中创建ansible-playbook install.yml -i inventory时,它会设置一个内容剪辑,默认设置为带有边界的内容。

要点是,根据您的情况,您可能可以使用框架和剪辑来达到预期的效果。

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

我这样做是通过将嵌套的UIStackView的所有隐藏视图存储在数组中,然后将它们从Superview和安排的子视图中删除。当我希望它们再次出现时,我遍历了数组并再次将其添加回去。这是第一步。

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

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

答案 11 :(得分:0)

如果在同时为HIDING和SHOWING子视图设置动画时遇到问题,则在动画完成中重复.isHidden指令可能会有所帮助。有关更多详细信息,请参见我的答案here

答案 12 :(得分:-2)

您是否尝试过此操作,在更改后调用超级?

override func viewWillAppear() {

    self.nameLabel.text = "John"

    self.summaryStackView.hidden = true
    self.combinedStackView.hidden = true

    super.viewWillAppear()
}