【问题标题】:Creating layout constraints programmatically以编程方式创建布局约束
【发布时间】:2012-10-01 08:51:26
【问题描述】:

我知道很多人已经对此提出了很多问题,但即使有答案我也无法解决问题。

当我处理情节提要上的约束时,这很容易,但在代码中我却很难。 例如,我尝试让视图保持在右侧,并根据屏幕方向具有屏幕高度。这是我的代码:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

它不满足某些约束。我看不出有什么问题。另外,为什么我不能使用像self.myView 这样的属性而不是像myView 这样的局部变量?

【问题讨论】:

  • 以上代码中的vivi是什么?
  • 请将标题改为“iOS”而不是“IOS”——后者指的是思科的交换机/路由器操作系统。使我困惑。谢谢。
  • 关于此的几个问题:(1)当它“不满足某些约束”时,您会遇到什么错误? (2) 您是否将自动调整大小转换为myView 上的约束? (3) vivi 是什么(正如 ACB 所问)? (4) 你有在self 上声明的属性myView 吗?
  • ih Tim,很抱歉 vivi,我敲得太快了……这是 myView。你说的翻译是什么意思?我所做的一切都在上面的代码中。关于该属性,我还有一些其他视图被声明为属性,但是当我对这些属性实现相同的代码时,它会崩溃...消息“错误”真的很大,我不能在这里粘贴它
  • 要暂时从特定视图中删除约束,然后执行此操作stackoverflow.com/questions/13388104/…

标签: objective-c ios constraints autolayout


【解决方案1】:

斯威夫特版本

为 Swift 3 更新

此示例将显示两种方法以编程方式添加以下约束,就像在 Interface Builder 中一样:

宽度和高度

容器中心

样板代码

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

方法一:锚样式

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

方法二:NSLayoutConstraint 样式

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

注意事项

  • 锚样式是优于NSLayoutConstraint 样式的首选方法,但它仅适用于iOS 9,因此如果您支持iOS 8,则仍应使用NSLayoutConstraint 样式。
  • 另请参阅Programmatically Creating Constraints 文档。
  • 请参阅this answer,了解添加固定约束的类似示例。

【讨论】:

    【解决方案2】:

    还请注意,从 iOS9 开始,我们可以使用新的辅助类 NSLayoutAnchor 的子类以编程方式定义约束“更简洁,更易于阅读”

    文档中的示例:

    [self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
    

    【讨论】:

      【解决方案3】:

      为什么我不能使用像 self.myView 这样的属性,而不是像 myView 这样的局部变量?

      尝试使用:

      NSDictionaryOfVariableBindings(_view)
      

      而不是self.view

      【讨论】:

      • 这使我的应用程序崩溃,它给出消息:'无法解析约束格式:polylineImageView 不是视图字典中的键。'
      【解决方案4】:

      在代码中使用自动布局时,设置框架不起作用。因此,您在上面的视图中指定宽度为 200 的事实在您对其设置约束时没有任何意义。为了使视图的约束集明确,它需要四个东西:任何给定状态的 x 位置、y 位置、宽度和高度。

      目前在上面的代码中,您只有两个(高度,相对于父视图,y 位置,相对于父视图)。除此之外,您还有两个必需的约束,它们可能会根据视图的超级视图约束的设置方式而发生冲突。 如果超级视图有一个必需的约束,指定它的高度小于 748,你将得到一个“不可满足的约束”异常。

      在设置约束之前设置视图的宽度这一事实没有任何意义。它甚至不会考虑旧框架,而是会根据它为这些视图指定的所有约束来计算新框架。在代码中处理自动布局时,我通常只使用initWithFrame:CGRectZero 或简单地使用init 创建一个新视图。

      要创建您在问题中口头描述的布局所需的约束集,您需要添加一些水平约束来限制宽度和 x 位置,以便提供完全指定的布局:

      [self.view addConstraints:[NSLayoutConstraint
          constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
          options:NSLayoutFormatDirectionLeadingToTrailing
          metrics:nil
          views:NSDictionaryOfVariableBindings(myView)]];
      
      [self.view addConstraints:[NSLayoutConstraint
          constraintsWithVisualFormat:@"H:[myView(==200)]-|"
          options:NSLayoutFormatDirectionLeadingToTrailing
          metrics:nil
          views:NSDictionaryOfVariableBindings(myView)]];
      

      从垂直约束开始,口头描述此布局如下:

      myView 将使用顶部和底部填充填充其父视图的高度 等于标准空间。 myView 的 superview 有一个最小高度 748 分。 myView 的宽度是 200pts 并且有一个右填充等于 标准空间与其superview。

      如果您只是希望视图填充整个超级视图的高度而不限制超级视图的高度,那么您只需在可视格式文本中省略(>=748) 参数。如果您认为需要(>=748) 参数来给它一个高度 - 在这种情况下您不需要:使用条形 (|) 或带空格的条形 (|-, @ 将视图固定到超级视图的边缘987654330@) 语法,你给你的视图一个 y 位置(将视图固定在单边上)和一个带高度的 y 位置(将视图固定在两个边上),从而满足视图的约束集。

      关于你的第二个问题:

      使用NSDictionaryOfVariableBindings(self.myView)(如果您为myView 设置了属性)并将其输入您的VFL 以在您的VFL 文本中使用self.myView,当自动布局尝试解析您的VFL 文本时,您可能会遇到异常。它与字典键中的点符号和尝试使用valueForKeyPath: 的系统有关。 See here for a similar question and answer.

      【讨论】:

      • 不要忘记一些像 UILabel 这样的对象有一个固有的大小,你不必设置该对象的宽度或高度,只需设置它的位置。但是,如果您设置高度或宽度,我相信它会同时删除两者,然后您必须同时提供两者。
      • 尽管这个答案没有回答我的问题,但它帮助我意识到了一些事情。谢谢你! :)
      • 迄今为止互联网上唯一简洁易读的自动布局介绍。
      • 请帮帮我我的问题是...我不知道如何以编程方式使用约束stackoverflow.com/questions/36326288/…
      【解决方案5】:

      您好,我一直在使用此页面进行限制和“如何做”。我花了很长时间才意识到自己需要:

      myView.translatesAutoresizingMaskIntoConstraints = NO;
      

      让这个例子工作。感谢 Userxxx、Rob M. 尤其是 larsacus 在这里的解释和代码,非常宝贵。

      这是运行上述示例的完整代码:

      UIView *myView = [[UIView alloc] init];
      myView.backgroundColor = [UIColor redColor];
      myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
      [self.view addSubview:myView];
      //needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
      [self.view addConstraints:[NSLayoutConstraint
                                 constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                                 options:NSLayoutFormatDirectionLeadingToTrailing
                                 metrics:nil
                                 views:NSDictionaryOfVariableBindings(myView)]];
      
      [self.view addConstraints:[NSLayoutConstraint
                                 constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                                 options:NSLayoutFormatDirectionLeadingToTrailing
                                 metrics:nil
                                 views:NSDictionaryOfVariableBindings(myView)]];
      

      【讨论】:

        【解决方案6】:

        关于你关于属性的第二个问题,你可以使用self.myView,只有当你将它声明为类中的属性时。由于myView 是一个局部变量,你不能那样使用它。有关这方面的更多详细信息,我建议您查看Declared Properties 上的苹果文档,

        【讨论】:

          猜你喜欢
          • 2019-06-01
          • 2015-10-17
          • 2018-04-08
          • 1970-01-01
          • 2017-01-10
          • 2022-07-08
          • 1970-01-01
          • 2015-12-26
          • 1970-01-01
          相关资源
          最近更新 更多