PinLayout icon indicating copy to clipboard operation
PinLayout copied to clipboard

Composing views that use PinLayout

Open egenvall opened this issue 4 years ago • 1 comments

Hi.

I use FlexLayout a lot and it's really good. I've now experimented some with PinLayout and ran into some issues which I don't yet quite understand.

The scenario is where you have a number of custom UIViews who themselves lay out using PinLayout. With FlexLayout, this works like a charm where each view is sized correctly with .layout(.adjustHeight)

final class SomeView: UIView {
    private let headerView = SomeHeaderView()
    private let baseContainer = UIView()
    private let tableView = UITableView()
    init() {
       super....
        addSubview(baseContainer)
        baseContainer.addSubview(headerView)
        baseContainer.addSubview(tableView)
    }

     override func layoutSubviews() {
        super.layoutSubviews()
        pinViews()
    }
    private func pinViews() {
        baseContainer.pin.all().margin(safeArea)
        headerView.pin.horizontally().top().wrapContent(.vertically) // Want this view to size correctly
        tableView.pin.horizontally().bottom().below(of: headerView)
    }
}

final class SomeHeaderView: UIView {
    private let baseContainer = UIView()
    private let someSquareView = UIView()
    private let someLabel = UILabel()
    private let someButton = UIButton()

    init() {
        super...
        addSubview(baseContainer)
        baseContainer.addSubview(someSquareView)
        baseContainer.addSubview(someLabel)
        baseContainer.addSubview(someButton)
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        baseContainer.pin.all()
        someSquareView.pin.size(100).top().horizontally()
        someLabel.pin.below(of: someSquareView).horizontally().sizeToFit(.width)
        someButton.pin.below(of: someLabel)...
    }
}

The issue I'm facing is that headerView always gets a 0 frame, and I want to avoid setting a static height for the view.

One way I've experimented with, after pinning the initial views is something along the lines of

private func pinHeight() {
        let totalHeight = baseContainer.subviews.reduce(0) {
            return $0 + $1.frame.height
        }
        baseContainer.pin.height(totalHeight)
}

But I'm not sure this is quite the way to approach it. I suppose another way to tackle the issue is by getting the maxY of the last element

egenvall avatar Mar 27 '20 12:03 egenvall

One common way to go would be to size your header using headerView.pin.top().horizontally().sizeToFit(.width) and implement sizeThatFits in your SomeHeaderView class, this is where you should return the proper height of your view but you should not assign any frames while doing so. If you want to avoid having to compute the resulting height manually you can take a look to the automatic sizing feature that was just released.

antoinelamy avatar Jun 30 '20 14:06 antoinelamy

Very old topic. Closing it, sorry

lucdion avatar Mar 01 '23 20:03 lucdion