Stanislav Smida
Stanislav Smida

Reputation: 1585

Auto Layout: layoutMarginsGuide

How to rewrite visual format

addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|-[label]-|", options: .AlignAllBaseline, metrics: nil, views: ["label": label]))
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[label]-|", options: .AlignAllCenterX, metrics: nil, views: ["label": label]))

by moving to layout guides (with margins)?

I tried it with

label.topAnchor.constraintEqualToAnchor(layoutMarginsGuide.topAnchor).active = true
label.leftAnchor.constraintEqualToAnchor(layoutMarginsGuide.leftAnchor).active = true
label.bottomAnchor.constraintEqualToAnchor(layoutMarginsGuide.bottomAnchor).active = true
label.rightAnchor.constraintEqualToAnchor(layoutMarginsGuide.rightAnchor).active = true

but does not work. Even layoutMarginsGuide.layoutFrame does not have expected value (yes I call it in layoutSubviews after super is executed). Constraints are set, but acts like there is zero margin. It layouts and gives expected layoutFrame only when the layout margin is set to negative; which is not what I want obviously, but demonstrates that constraints are set with margins guides. Looks like I'm missing something...

Upvotes: 8

Views: 4848

Answers (4)

Tancrede Chazallet
Tancrede Chazallet

Reputation: 7255

I actually found out that you can setup layoutMargins in init as well as your constraints without any problem.

It only requires to setup

self.translatesAutoresizingMaskIntoConstraints = false

(yes, self)

If you don't, no constraint will break, although margins won't work (in iOS 10)

Upvotes: 1

Vlad
Vlad

Reputation: 6730

Reusable view which contains workaround addressed layoutMarginsGuide issue (Swift 4).

open class View: UIView {

   public override init(frame: CGRect) {
      var adjustedFrame = frame
      if frame.size.width == 0 {
         adjustedFrame.size.width = CGFloat.greatestFiniteMagnitude
      }
      if frame.size.height == 0 {
         adjustedFrame.size.height = CGFloat.greatestFiniteMagnitude
      }
      super.init(frame: adjustedFrame)
      #if !TARGET_INTERFACE_BUILDER
         initializeView()
      #endif
   }

   public required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
   }

   open override func awakeFromNib() {
      super.awakeFromNib()
      initializeView()
   }

   open func initializeView() {
      // Do something in child classes.
   }
}

Upvotes: 0

Stanislav Smida
Stanislav Smida

Reputation: 1585

I did some another research on that since we now have iOS 10. Here is what I found:

  • It still doesn't work reliably. I mean setting constraints relative to layout margins guide in designated initializer with no further actions.
  • It works fine if frame size >= layout margins for particular size.
  • Else if you will call layoutMarginsGuide (even only in print, we are still talking about calls within initializer) you will corrupt this guide so even in later call (in didMoveToWindow for example) it will not work then. You can repair it by setting new layoutMargins (but new value must differ with old).

I consider this a bug and filed it (please file it as well so it can be prioritized for fix).

Upvotes: 7

midas06
midas06

Reputation: 2011

It seems to me that layoutMarginsGuide is not ready in the init method of a UIView. I'm also getting similar issues, where setting up the constraints in updateConstraints just works. Still investigating why.

UPDATE: What I was trying to do was set the layoutMargins before the view had been added to a superview (in the init). That didn't work. What did work was setting the constraints in the init, relative to layoutMarginsGuide, but actually setting the layoutMargins in viewDidMoveToSuperView.

Upvotes: 15

Related Questions