layoutBox / PinLayout

Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable. [iOS/macOS/tvOS/CALayer]

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Problem with sizeToFit - autoSizing

proxzi opened this issue · comments

Hi all! Please help me solve the problem, in case someone has come across such a case: I’ll describe it briefly, I have many elements in my project that are pin using pinLayout, and there is a need to calculate the content size for a specific view, for example:
Let's say there is a TextItem element:
its implementation is like this

final class TextItem: UIView {
    
    private var textView: UILabel
    init(text: String) {
        textView = UILabel()
        textView.text = text
        textView.font = .systemFont(ofSize: 14)
        textView.numberOfLines = 0
        textView.lineBreakMode = .byWordWrapping
        super.init(frame: .zero)
        addSubview(textView)
    }
    
    @available(*, unavailable, message: "init(coder:) has not been implemented")
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        performLayout()
    }
    
    override func sizeThatFits(_ size: CGSize) -> CGSize {
        autoSizeThatFits(size, layoutClosure: performLayout)
    }
    
    private func performLayout() {
        textView.pin
            .sizeToFit(.width)
            .all()
    }
}

If you usually pin it into any view, then everything is okay, everything works, but I need to calculate the size of this view (that is, the label that is pinned with the PinLayout) based on the size of the content.
I want to do something like this (for a regular UILabel() this will all work like in your example "AdjustToContainer")

class ChoiceSelectorView: UIView {

    private var textLeft = TextItem(text: "Левая часть")
    private var textRight = TextItem(text: "правая частььььььььььььььььььььььььььь")

    init() {
        super.init(frame: .zero)
     
        addSubview(textLeft)
        addSubview(textRight)  
        textRight.sizeToFit()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        performLayout()
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        autoSizeThatFits(size, layoutClosure: performLayout)
    }

    private func performLayout() {
        textRight.pin.top().right().size(textRight.bounds.size).maxWidth(UIScreen.main.bounds.width*0.9)
        textLeft.pin.top().left().before(of: textRight).sizeToFit(.width)
    }
}

But for a TextItem element that is on pinLayout, sizeThatFits will return the length of the entire screen and the left label will displace the right one and fill the entire screen.

textRight.sizeThatFits(UIScreen.main.bounds.size) -> return screen width

I also tried to specify sizeToFit(.widthFlexible) for TextItem, but then for this case, cutting the line will not work, that is, if numberOfLine = 1, then at the end of the 3rd dot will not appear, and this change may break all other views in which there is a TextItem, and they are already laid out.

Maybe you have some options with pinLayout, how you can correctly calculate the size of a TextItem so that it is calculated only by the size of the text itself.

Thanks.

its solve like this in TextItem:

override func sizeThatFits(_ size: CGSize) -> CGSize {
    textView.sizeThatFits(size)
}

private func performLayout() {
    textView.frame = bounds
}