【问题标题】:How to Create layout constraints programmatically如何以编程方式创建布局约束
【发布时间】:2015-10-17 12:23:40
【问题描述】:

我正在通用应用程序的底部显示一个视图,并在我的视图中动态添加此视图。我想每次都像 iAd 一样在底部显示这个视图。在两个方向。如何为此添加约束。请提出建议。

谢谢

【问题讨论】:

标签: ios iphone constraints


【解决方案1】:

要将视图固定到屏幕底部,您需要设置以下约束。

  1. Leading Constraint 对于 - X 的父视图
  2. Trailing Constraint 与父视图相关的 - Width
  3. 关于 - Y 的父视图的 底部约束
  4. 高度约束附加到自身 - 高度

让我们添加。

UIView *subView=bottomView;
UIView *parent=self.view;

subView.translatesAutoresizingMaskIntoConstraints = NO;

//Trailing    
NSLayoutConstraint *trailing =[NSLayoutConstraint
                                constraintWithItem:subView
                                attribute:NSLayoutAttributeTrailing
                                relatedBy:NSLayoutRelationEqual
                                toItem:parent   
                                attribute:NSLayoutAttributeTrailing
                                multiplier:1.0f
                                constant:0.f];

//Leading

NSLayoutConstraint *leading = [NSLayoutConstraint
                                   constraintWithItem:subView
                                   attribute:NSLayoutAttributeLeading
                                   relatedBy:NSLayoutRelationEqual
                                   toItem:parent
                                   attribute:NSLayoutAttributeLeading
                                   multiplier:1.0f
                                   constant:0.f];

//Bottom
NSLayoutConstraint *bottom =[NSLayoutConstraint
                                 constraintWithItem:subView
                                 attribute:NSLayoutAttributeBottom
                                 relatedBy:NSLayoutRelationEqual
                                 toItem:parent
                                 attribute:NSLayoutAttributeBottom
                                 multiplier:1.0f
                                 constant:0.f];

//Height to be fixed for SubView same as AdHeight
NSLayoutConstraint *height = [NSLayoutConstraint
                               constraintWithItem:subView
                               attribute:NSLayoutAttributeHeight
                               relatedBy:NSLayoutRelationEqual
                               toItem:nil
                               attribute:NSLayoutAttributeNotAnAttribute
                               multiplier:0
                               constant:ADHeight];

    //Add constraints to the Parent
    [parent addConstraint:trailing];
    [parent addConstraint:bottom];
    [parent addConstraint:leading];

    //Add height constraint to the subview, as subview owns it.
    [subView addConstraint:height];

希望这会有所帮助。

干杯。

【讨论】:

  • *height 上的 attribute 值实际上应该是 NSLayoutAttributeNotAnAttribute,而不是 0
  • @dperk NSLayoutAttributeNotAnAttribute = 0: NSLayoutAttribute 是枚举值,它被定义为 0,所以两者都是一样的,没有区别,它是关于选择你想要使用的。
  • 是的,尽管最好的做法是与枚举名称保持一致。对于 0,我承认;这没什么大不了的。但最好始终保持一致。
  • 应该在 awakeFromNib 还是 viewDidload 中完成此设置?为什么?
  • @Honey 它应该只添加一次,选择viewDidLoad,因为它被调用一次。
【解决方案2】:

先前答案的小扩展,因为 addConstraint 将来会被弃用。这是 UI 视图的扩展。在将视图添加到层​​次结构后使用这些函数。

OBJC

@implementation UIView (Constraints)

-(void)addConstaintsToSuperviewWithLeftOffset:(CGFloat)leftOffset topOffset:(CGFloat)topOffset {

    self.translatesAutoresizingMaskIntoConstraints = false;

    [[NSLayoutConstraint constraintWithItem: self
                                  attribute: NSLayoutAttributeLeading
                                  relatedBy: NSLayoutRelationEqual
                                     toItem: self.superview
                                  attribute: NSLayoutAttributeLeading
                                 multiplier: 1
                                   constant: leftOffset] setActive:true];

    [[NSLayoutConstraint constraintWithItem: self
                                  attribute: NSLayoutAttributeTop
                                  relatedBy: NSLayoutRelationEqual
                                     toItem: self.superview
                                  attribute: NSLayoutAttributeTop
                                 multiplier: 1
                                   constant: topOffset] setActive:true];
}

-(void)addConstaintsWithWidth:(CGFloat)width height:(CGFloat)height {

    self.translatesAutoresizingMaskIntoConstraints = false;


    [[NSLayoutConstraint constraintWithItem: self
                                  attribute: NSLayoutAttributeWidth
                                  relatedBy: NSLayoutRelationEqual
                                     toItem: nil
                                  attribute: NSLayoutAttributeNotAnAttribute
                                 multiplier: 1
                                   constant: width] setActive:true];

    [[NSLayoutConstraint constraintWithItem: self
                                  attribute: NSLayoutAttributeHeight
                                  relatedBy: NSLayoutRelationEqual
                                     toItem: nil
                                  attribute: NSLayoutAttributeNotAnAttribute
                                 multiplier: 1
                                   constant: height] setActive:true];
}

@end

斯威夫特 3

extension UIView {

    public func addConstaintsToSuperview(leftOffset: CGFloat, topOffset: CGFloat) {

        self.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint(item: self,
                           attribute: .leading,
                           relatedBy: .equal,
                           toItem: self.superview,
                           attribute: .leading,
                           multiplier: 1,
                           constant: leftOffset).isActive = true

        NSLayoutConstraint(item: self,
                           attribute: .top,
                           relatedBy: .equal,
                           toItem: self.superview,
                           attribute: .top,
                           multiplier: 1,
                           constant: topOffset).isActive = true
    }

    public func addConstaints(height: CGFloat, width: CGFloat) {

        self.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint(item: self,
                           attribute: .height,
                           relatedBy: .equal,
                           toItem: nil,
                           attribute: .notAnAttribute,
                           multiplier: 1,
                           constant: height).isActive = true


        NSLayoutConstraint(item: self,
                           attribute: .width,
                           relatedBy: .equal,
                           toItem: nil,
                           attribute: .notAnAttribute,
                           multiplier: 1,
                           constant: width).isActive = true
    }
}

【讨论】:

    【解决方案3】:

    此外,从 iOS 9 开始,使用锚点可以非常简单地完成:

    斯威夫特 3

    extension UIView {
    
        func addConstaintsToSuperview(leadingOffset: CGFloat, topOffset: CGFloat) {
    
            guard superview != nil else {
                return
            }
    
            translatesAutoresizingMaskIntoConstraints = false
    
            leadingAnchor.constraint(equalTo: superview!.leadingAnchor,
                                     constant: leadingOffset).isActive = true
    
            topAnchor.constraint(equalTo: superview!.topAnchor,
                                 constant: topOffset).isActive = true
        }
    
        func addConstaints(height: CGFloat, width: CGFloat) {
    
            heightAnchor.constraint(equalToConstant: height).isActive = true
            widthAnchor.constraint(equalToConstant: width).isActive = true
        }
    
    }
    

    OBJC类别

    @implementation UIView (Constraints)
    
    -(void)addConstaintsToSuperviewWithLeadingOffset:(CGFloat)leadingOffset topOffset:(CGFloat)topOffset
    {
        if (self.superview == nil) {
            return;
        }
    
        self.translatesAutoresizingMaskIntoConstraints = false;
    
        [[self.leadingAnchor constraintEqualToAnchor:self.superview.leadingAnchor
                                            constant:leadingOffset] setActive:true];
    
        [[self.topAnchor constraintEqualToAnchor:self.superview.topAnchor
                                       constant:topOffset] setActive:true];
    }
    
    -(void)addConstaintsWithHeight:(CGFloat)height width:(CGFloat)width
    {
        [[self.heightAnchor constraintEqualToConstant:height] setActive:true];
        [[self.widthAnchor constraintEqualToConstant:width] setActive:true];
    }
    
    @end
    

    【讨论】:

      【解决方案4】:

      您可以像下面这样以编程方式使用自动布局约束

      fileprivate func setupName(){
              let height = CGFloat(50)
      
              lblName.text = "Hello world"
              lblName.backgroundColor = .lightGray
      
              //Step 1
              lblName.translatesAutoresizingMaskIntoConstraints = false
      
              //Step 2
              self.view.addSubview(lblName)
      
              //Step 3
              NSLayoutConstraint.activate([
      
                  lblName.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
                  lblName.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
                  lblName.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,constant: -height),
                  lblName.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
                  ])
      
          }
      

      Output screenshot

      【讨论】:

      • 简单易用,无需编写大量代码。
      【解决方案5】:

      在 Swift 4 中扩展 @Alex Shubin 解决方案,我执行以下操作:

      有时,我需要添加可变数量的约束,在本例中为 3,因为高度将在后面计算。

      keyboard.addConstaints(top: nil, right: 0.0, bottom: 0.0, left: 0.0, width: nil, height: nil)
      

      您必须小心添加所有必需的内容,并确保没有任何冲突的约束。

      extension UIView {
          func addConstaints(top: CGFloat?, right: CGFloat?, bottom: CGFloat?, left: CGFloat?, width: CGFloat?, height: CGFloat?) {
              translatesAutoresizingMaskIntoConstraints = false
              if top != nil { self.addConstaint(top: top!) }
              if right != nil { self.addConstaint(right: right!) }
              // Add lines for bottom, left, width an heigh
              // ...
          }
          func addConstaint(top offset: CGFloat) {
              guard superview != nil else { return }
              topAnchor.constraint(equalTo: superview!.topAnchor, constant: offset).isActive = true
          }
      }
      

      要验证所有视图的布局是否正确,您可以检查 superView 的 .constraints 属性,也可以检查框架:

      override func viewDidLayoutSubviews() {
          print(keyboard.frame)
      }
      

      【讨论】:

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