0

我想创建一个“添加新的信用卡视图控制器”。我们不希望一次性显示所有必填字段来激怒用户。此操作包含几个步骤。在每一步,视图控制器都会显示一个新的子视图(其中包含一个或多个文本字段)并折叠一个旧的子视图(验证文本后的当前文本字段)。

  1. 我在情节提要上创建了 ViewController。并将其所有子视图放在另一个之上。

  2. 我已经在故事板上创建了所有约束,每个子视图的剪辑到上述子视图等。

IE:

NSMutableArray *constraints = [[NSLayoutConstraint
    constraintsWithVisualFormat:
        @"V:|[titleView]-[subtitleView]-[amountView]-[cardNumView]-[cardsImagesView]-[mmYYCvvView]-[billingInfoView]-[buttomView]|"
    options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom
    metrics:nil
    views:variableBindings] mutableCopy];
  1. 这些子视图中的每一个都包含一个高度约束。

  2. 在每一步中,一个高度约束设置为零,另一个从零更改为所需高度。

IE:

self.hgtCrtMMYYCvv.constant = showFields? 50 : 0;
self.hgtCrtBillingInfo.constant = showFields? 140 : 0;
self.mmYYCvvView.hidden = !showFields;
self.billingInfoView.hidden = !showFields;

我有两个问题:

  • 没有调用layoutIfNeeded初始布局是有效的,但在改变高度约束后没有改变。

  • 调用layoutIfNeeded并没有将底部视图剪辑到最后一个可见的视图 - 将其放置在视图的底部,就好像所有子视图同时出现一样,但由于有些子视图被隐藏,因此创建了一个间隙。在屏幕上应用了更改子视图的高度约束,但仍然存在差距。

请指教。

4

1 回答 1

2

调用“layoutIfNeeded”并没有将底部视图剪辑到最后一个可见的视图 - 将其放置在视图的底部,就好像所有子视图同时出现一样

看看你的约束。您已将底部视图的底部固定到其超级视图的底部!所以它的底部必须出现在超级视图的底部,因为这是您指示它执行的操作。

确实,我很惊讶您的约束完全起作用。你基本上已经过度确定了它们。如果您为每个字段指定一个高度固定其顶部和底部,那么对于每个字段,除非您非常幸运,否则将无法满足您的约束。超级视图的高度是固定的,所以你的约束必须完美地加起来到那个高度。

我将建议一个完整的替代方法,我认为您会发现它更容易。与其弄乱单个常量,不如为每种可能的情况计划正确的(不是过度确定的)约束,并将这些约束存储在属性中。现在,当您想要隐藏/显示一个字段时,您只需删除所有约束并换入另一组。

这也将解决layoutIfNeeded问题。

碰巧我有一个实际的例子来展示如何做到这一点。(它是用 Swift 编写的,但我相信你可以在心理上有所补偿。)在我的示例代码中,我们有三个矩形;然后我删除一个矩形并缩小其余两个之间的间隙。准备两组约束是乏味但基本的:

    let c1 = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(20)-[v(100)]", options: nil, metrics: nil, views: ["v":v1]) as [NSLayoutConstraint]
    let c2 = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(20)-[v(100)]", options: nil, metrics: nil, views: ["v":v2]) as [NSLayoutConstraint]
    let c3 = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(20)-[v(100)]", options: nil, metrics: nil, views: ["v":v3]) as [NSLayoutConstraint]
    let c4 = NSLayoutConstraint.constraintsWithVisualFormat("V:|-(100)-[v(20)]", options: nil, metrics: nil, views: ["v":v1]) as [NSLayoutConstraint]
    let c5with = NSLayoutConstraint.constraintsWithVisualFormat("V:[v1]-(20)-[v2(20)]-(20)-[v3(20)]", options: nil, metrics: nil, views: ["v1":v1, "v2":v2, "v3":v3]) as [NSLayoutConstraint]
    let c5without = NSLayoutConstraint.constraintsWithVisualFormat("V:[v1]-(20)-[v3(20)]", options: nil, metrics: nil, views: ["v1":v1, "v3":v3]) as [NSLayoutConstraint]

    self.constraintsWith.extend(c1)
    self.constraintsWith.extend(c2)
    self.constraintsWith.extend(c3)
    self.constraintsWith.extend(c4)
    self.constraintsWith.extend(c5with)

    self.constraintsWithout.extend(c1)
    self.constraintsWithout.extend(c3)
    self.constraintsWithout.extend(c4)
    self.constraintsWithout.extend(c5without)

    NSLayoutConstraint.activateConstraints(self.constraintsWith)

但是当需要将中间视图换入或换出界面时,回报就来了:这很简单。只需删除或插入它,然后删除所有约束,现在插入适合情况的完整新约束集,我们已经准备好了:

@IBAction func doSwap(sender: AnyObject) {
    if self.v2.superview != nil {
        self.v2.removeFromSuperview()
        NSLayoutConstraint.deactivateConstraints(self.constraintsWith)
        NSLayoutConstraint.activateConstraints(self.constraintsWithout)
    } else {
        self.view.addSubview(v2)
        NSLayoutConstraint.deactivateConstraints(self.constraintsWithout)
        NSLayoutConstraint.activateConstraints(self.constraintsWith)
    }
}

多组约束的准备是乏味的,但可以通过规则来完成,即约束可以在循环中“机器生成”(编写这个留作练习)。再次根据一个简单的规则交换约束条件,因为对于您希望显示/隐藏的特定字段集,只有一组是正确的。因此,一旦设置完成,它将比您现在所做的更简单、更易于维护。

于 2014-11-09T16:08:56.593 回答