Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use preservesSuperviewLayoutMargins in nested views

I'm trying to make used of preservesSuperviewLayoutMargins through a nested view hierarchy but hitting a lot of issues with UIKit and wondering what I am doing wrong (or whether this is a genuine bug).

I'm trying to lay out a handful of views (some by the side of each other, some above each other) like so:

// Various combinations here will create different visual results (it will either work or won't)

let i1 = ImageView()
//let i1 = LabelView()
let i2 = ImageView()
//let i2 = LabelView()
let i3 = ImageView()
//let i3 = LabelView()

let view = LeftRight(left: i1, right: TopBottom(top: i2, bottom: i3))
//let view = LeftRight(left: TopBottom(top: i2, bottom: i3), right: i1)

With some layout's I can get it to work, shown below. You can see that the images on the right are correctly indented against the green view, which is in turn correctly indented against the white view.

Correctly embedded

But with others I am struggling:

Black screen!

Running code similar to this in an app I can get a complete lockup and memory runaway.

The indenting is done using layoutMargins like this:

let masterView = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
masterView.translatesAutoresizingMaskIntoConstraints = false
masterView.layoutMargins = UIEdgeInsets(top: 5.0, left: 5.0, bottom: 5.0, right: 5.0)

let subView = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
subView.translatesAutoresizingMaskIntoConstraints = false
subView.layoutMargins = UIEdgeInsets(top: 5.0, left: 5.0, bottom: 5.0, right: 5.0)

Here's a sample of the image layout from a playground. The full playground project can be found here and can easily be loaded up and ran in XCode to see what I mean.

class ImageView: UIView {

    init() {

        super.init(frame: CGRect(x: 0, y: 0, width: 1000, height: 1000))

        self.preservesSuperviewLayoutMargins = true
        self.layoutMargins = .zero

        let imageView = UIImageView(image: UIImage(named: "jesus"))
        imageView.contentMode = .center

        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.clipsToBounds = true
        self.clipsToBounds = true
        imageView.backgroundColor = UIColor.red

        self.addSubview(imageView)

        imageView.leftAnchor.constraint(equalTo: self.layoutMarginsGuide.leftAnchor).isActive = true
        imageView.rightAnchor.constraint(equalTo: self.layoutMarginsGuide.rightAnchor).isActive = true
        imageView.topAnchor.constraint(equalTo: self.layoutMarginsGuide.topAnchor).isActive = true
        imageView.bottomAnchor.constraint(equalTo: self.layoutMarginsGuide.bottomAnchor).isActive = true
    }
}
like image 377
Sam Avatar asked Nov 20 '22 03:11

Sam


1 Answers

I believe that you forgot something those are required.

  1. Implementation of intrinsicContentSize on ImageView and Label
  2. Missing constraints that make both subviews have the same width and height in those 2 UIView subclasses (TopBottom and LeftRight)
  3. right view of view (LeftRight) still haven't been set its translatesAutoresizingMaskIntoConstraints property to false
  4. Add the constraint for bottom of the outmost frame view
  5. Call layoutIfNeeded() on frame view

    top.widthAnchor.constraint(equalTo: bottom.widthAnchor).isActive = true top.heightAnchor.constraint(equalTo: bottom.heightAnchor).isActive = true

like image 108
Pitiphong Phongpattranont Avatar answered Nov 21 '22 19:11

Pitiphong Phongpattranont