【问题标题】:Auto layout - Collapsable views (vertically)自动布局 - 可折叠视图(垂直)
【发布时间】:2015-01-05 22:19:43
【问题描述】:

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

  1. 我已经在情节提要上创建了 ViewController。并将其所有子视图一层一层地放置。

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

即:

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

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

即:

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

我有两个问题:

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

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

请指教。

【问题讨论】:

    标签: ios autolayout collapsable


    【解决方案1】:

    调用“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)
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多