SwiftBox icon indicating copy to clipboard operation
SwiftBox copied to clipboard

Layout wasn't returning correct width/height when child nodes get a bit more complicated

Open jamztang opened this issue 9 years ago • 6 comments

Here's the setup I encountered issue

let imageText = Node(
    direction: .Column,
    padding: Edges(top: 20, bottom: 20),
    children: strings.map { (text : String) -> Node in
        let image = Node(
            size: CGSizeMake(100, 100)
        )
        let text = Node(
            measure: { w in
                println("\(w)") // Nan
                label.text = text
                label.preferredMaxLayoutWidth = w
                return label.sizeThatFits(CGSizeMake(w, CGFloat.max))
        })
        let row = Node(
            direction: Direction.Row,
            children:[image, text]
        )
        return row
    }
)
println(imageText.layout(maxWidth: 375).frame)  // (0.0, 0.0, 7704.0, 240.0)

Notice the width wasn't obeying the maxWidth we've put into our layout.

So Basically I want to implement something like this: ios simulator screen shot 12 jul 2015 1 49 25 pm

I had some sample data setup here:

let strings : [String] = [
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ex dolor, imperdiet vel tellus sollicitudin, ultrices maximus nunc. Ut non vehicula magna. Etiam sit amet varius lectus, et luctus dui. Sed eget blandit turpis. Nullam laoreet at felis non fermentum. Integer elit sem, tempus eget ex non, mattis porta lorem. Sed ut quam vel nibh luctus bibendum quis sed mi.",
    "Fusce scelerisque rhoncus elementum. Maecenas ultricies est ex, ut varius mauris cursus at. Maecenas sollicitudin orci posuere, ultricies lacus vel, scelerisque nibh. Nullam a turpis a urna elementum posuere. Integer porttitor vestibulum urna lobortis tincidunt. Aliquam consectetur sem metus, et laoreet libero rutrum nec. Donec sed justo dapibus, mollis nibh volutpat, sollicitudin sem. Suspendisse tempor, velit ac ullamcorper pretium, sapien risus molestie enim, aliquam cursus ex massa a nisl. Duis gravida, diam eget rutrum sagittis, dui est malesuada mi, a dapibus eros odio sit amet tellus. Nunc porttitor nunc nec massa mollis, et pellentesque est egestas. Vivamus venenatis dignissim massa in euismod. Vestibulum rutrum ex a interdum varius. Donec convallis gravida dui eget viverra. Suspendisse tempor, lorem sit amet consequat mattis, libero ex dictum quam, eget iaculis felis velit eu nunc. Morbi eros lectus, aliquet at pulvinar sed, tempor malesuada elit. Integer blandit gravida felis.",
    ]

// Also setting up a label to calculate the size
let label = UILabel()
label.numberOfLines = 0

I tried a simpler setup and works as expected:

let textOnly = Node(
    direction: .Column,
    padding: Edges(top: 20, bottom: 20),
    children: strings.map { (text : String) -> Node in
        let text = Node(
            measure: { w in
                println("\(w)") // 375
                label.text = text
                label.preferredMaxLayoutWidth = w
                return label.sizeThatFits(CGSizeMake(w, CGFloat.max))
        })
        return text
    }
)

println(textOnly.layout(maxWidth: 375).frame) // (0.0, 0.0, 375.0, 669.0)

So is there something wrong with my setup or it's a bug that I encountered? Thanks for helping out!

jamztang avatar Jul 12 '15 06:07 jamztang

Yay I got it working!

let imageText = Node(
    direction: .Column,
    padding: Edges(top: 20, bottom: 20),
    size: CGSizeMake(375, CGFloat.NaN),     // I just have to make sure I defined the size here, height is important to be Nan
    children: strings.map { (text : String) -> Node in
        let image = Node(
            size: CGSizeMake(100, 100)
        )
        let text = Node(
            flex: 1,                        // And make sure flex are set
            measure: { w in
                label.text = text
                label.preferredMaxLayoutWidth = w
                return label.sizeThatFits(CGSizeMake(w, CGFloat.max))
        })
        let row = Node(
            direction: Direction.Row,
            children:[image, text]
        )
        return row
    }
)

println(imageText.layout().frame) // (0.0, 0.0, 375.0, 912.5)

jamztang avatar Jul 13 '15 04:07 jamztang

Glad you figured it out!

I'm going to re-open this because that does look like something's funny with maxWidth.

joshaber avatar Jul 13 '15 14:07 joshaber

Is maxWidth something inside original Flexbox implementation or no?

jamztang avatar Jul 13 '15 17:07 jamztang

Yeah it's in FB's flexbox implementation.

joshaber avatar Jul 15 '15 18:07 joshaber

Then we have to either help to fix facebook's impl or patch it in SwiftBox manually

jamztang avatar Jul 16 '15 04:07 jamztang

I just ran into a bug with maxWidth myself (it was setting the width of some flex: 1 children to zero).

To work around it, I just wrapped the root node inside an extra node with its width set to maxWidth, and then just grabbed the first child after calling layout():

  if let maxWidth = maxWidth {
    let wrapper = Node(size: CGSize(width: maxWidth, height: .nan), children: [node])
    let layout = wrapper.layout()
    return layout.children.first!
  } else {
    return node.layout()
  }

steadicat avatar Oct 14 '16 01:10 steadicat