Width and Height Equal to its superView using autolayout programmatically?

前端 未结 11 1454
后悔当初
后悔当初 2020-12-07 09:09

I\'ve been looking for a lot of snippets in the net and I still can\'t find the answer to my problem. My question is I have a scrollView(SV) and I want to add a button insid

相关标签:
11条回答
  • 2020-12-07 10:00

    I needed to cover the superview completely. The other ones wouldn't do that during orientation changes. So I wrote a new one which does - using an arbitrary size multiplier of 20. Feel free to change to your needs. Also note this one in fact makes the subview a lot bigger than the superview which might be different from requirements.

    extension UIView {
        func coverSuperview() {
            guard let superview = self.superview else {
                assert(false, "Error! `superview` was nil – call `addSubview(_ view: UIView)` before calling `\(#function)` to fix this.")
                return
            }
            self.translatesAutoresizingMaskIntoConstraints = false
            let multiplier = CGFloat(20.0)
            NSLayoutConstraint.activate([
                self.heightAnchor.constraint(equalTo: superview.heightAnchor, multiplier: multiplier),
                self.widthAnchor.constraint(equalTo: superview.widthAnchor, multiplier: multiplier),
                self.centerXAnchor.constraint(equalTo: superview.centerXAnchor),
                self.centerYAnchor.constraint(equalTo: superview.centerYAnchor),
                ])
        }
    }
    
    0 讨论(0)
  • 2020-12-07 10:04

    I'm not sure if this is the most efficient way to do it, but it works..

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    // initialize
    
    
    [coverForScrolView addSubview:button];
    
    NSLayoutConstraint *width =[NSLayoutConstraint
                                        constraintWithItem:button
                                        attribute:NSLayoutAttributeWidth
                                        relatedBy:0
                                        toItem:coverForScrolView
                                        attribute:NSLayoutAttributeWidth
                                        multiplier:1.0
                                        constant:0];
    NSLayoutConstraint *height =[NSLayoutConstraint
                                         constraintWithItem:button
                                         attribute:NSLayoutAttributeHeight
                                         relatedBy:0
                                         toItem:coverForScrolView
                                         attribute:NSLayoutAttributeHeight
                                         multiplier:1.0
                                         constant:0];
    NSLayoutConstraint *top = [NSLayoutConstraint
                                       constraintWithItem:button
                                       attribute:NSLayoutAttributeTop
                                       relatedBy:NSLayoutRelationEqual
                                       toItem:coverForScrolView
                                       attribute:NSLayoutAttributeTop
                                       multiplier:1.0f
                                       constant:0.f];
    NSLayoutConstraint *leading = [NSLayoutConstraint
                                           constraintWithItem:button
                                           attribute:NSLayoutAttributeLeading
                                           relatedBy:NSLayoutRelationEqual
                                           toItem:coverForScrolView
                                           attribute:NSLayoutAttributeLeading
                                           multiplier:1.0f
                                           constant:0.f];
    [coverForScrolView addConstraint:width];
    [coverForScrolView addConstraint:height];
    [coverForScrolView addConstraint:top];
    [coverForScrolView addConstraint:leading];
    
    0 讨论(0)
  • 2020-12-07 10:04

    I've picked the best elements from the other answers:

    extension UIView {
      /// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
      /// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
      func bindFrameToSuperviewBounds() {
        guard let superview = self.superview else {
          print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
          return
        }
    
        self.translatesAutoresizingMaskIntoConstraints = false
    
        NSLayoutConstraint.activate([
          self.topAnchor.constraint(equalTo: superview.topAnchor),
          self.bottomAnchor.constraint(equalTo: superview.bottomAnchor),
          self.leadingAnchor.constraint(equalTo: superview.leadingAnchor),
          self.trailingAnchor.constraint(equalTo: superview.trailingAnchor)
        ])
      }
    }
    

    You can use it like this, for example in your custom UIView:

    let myView = UIView()
    myView.backgroundColor = UIColor.red
    
    self.addSubview(myView)
    myView.bindFrameToSuperviewBounds()
    
    0 讨论(0)
  • 2020-12-07 10:07

    Approach #1: Via UIView Extension

    Here's a more functional approach in Swift 3+ with a precondition instead of a print (which can perish easily in the console). This one will report programmer errors as failed builds.

    Add this extension to your project:

    extension UIView {
        /// Adds constraints to the superview so that this view has same size and position.
        /// Note: This fails the build if the `superview` is `nil` – add it as a subview before calling this.
        func bindEdgesToSuperview() {
            guard let superview = superview else {
                preconditionFailure("`superview` was nil – call `addSubview(view: UIView)` before calling `bindEdgesToSuperview()` to fix this.")
            }
            translatesAutoresizingMaskIntoConstraints = false
            ["H:|-0-[subview]-0-|", "V:|-0-[subview]-0-|"].forEach { visualFormat in
                superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: visualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
            }
        }
    }
    

    Now simply call it like this:

    // after adding as a subview, e.g. `view.addSubview(subview)`
    subview.bindEdgesToSuperview()
    

    Note that the above method is already integrated into my HandyUIKit framework which also adds some more handy UI helpers into your project.


    Approach #2: Using a Framework

    If you work a lot with programmatic constraints in your project then I recommend you to checkout SnapKit. It makes working with constraints a lot easier and less error-prone.

    Follow the installation instructions in the docs to include SnapKit into your project. Then import it at the top of your Swift file:

    import SnapKit
    

    Now you can achieve the same thing with just this:

    subview.snp.makeConstraints { make in
        make.edges.equalToSuperview()
    }
    
    0 讨论(0)
  • 2020-12-07 10:09

    addConstraint and removeConstraint methods for UIView are going to be deprecated, so it's worth to use 'constraint creation conveniences':

    view.topAnchor.constraint(equalTo: superView.topAnchor, constant: 0).isActive = true
    view.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: 0).isActive = true
    view.leadingAnchor.constraint(equalTo: superView.leadingAnchor, constant: 0).isActive = true
    view.trailingAnchor.constraint(equalTo: superView.trailingAnchor, constant: 0).isActive = true
    
    0 讨论(0)
提交回复
热议问题