LinkedInAttic / LayoutKit

LayoutKit is a fast view layout library for iOS, macOS, and tvOS.
http://layoutkit.org
Apache License 2.0
3.16k stars 267 forks source link

StackLayout last item height seems wrong #182

Open itskoBits opened 6 years ago

itskoBits commented 6 years ago

Hi guys,

I have some experience using LayoutKit, but I am struggling with a really simple use case. I am not sure if I I am missing something or if it is an issue within the library.

What I want to achieve.

I have a view(P) with fixed size and I want to place two subviews inside. The first(S1) one is with fixed size, the second one(S2) has a fixed width and should fill the remaining height. I also want to have some spacing between the two subviews.

Here is an image of what I try to achieve: stack-correct

The blue view is the parent view with fixed size. The red view is the subview with fixed size. The black vertical line is what I want to fill the available space.

What I tried

I tried implementing what I described earlier using StackLayout. However the last item (S2) in that layout has his height calculated wrongly. It's height ignores the item spacing defined by the StackLayout. Below is a sample code I tried.

let iconLayout = SizeLayout<UIView>(width: 22, height: 22, config: { view in
    view.backgroundColor = .red
})
let verticalLineLayout = SizeLayout<UIView>(width: 3, config: { view in
    view.backgroundColor = UIColor.black
})

let stackLayout = StackLayout(axis: .vertical, spacing: 10, sublayouts: [iconLayout, verticalLineLayout])

let sizeLayout = SizeLayout(size: CGSize(width: self.view.frame.width, height: 100), sublayout: stackLayout, config: { view in
    view.backgroundColor = .blue
})

Here is an image of what I get as result. stack-incorrect

Am I missing something or is this an issue with LayoutKit? Thank you!

staguer commented 6 years ago

Hello @itskoBits, I think you've indeed found a bug, thank you for reporting it. I have reproduced it with the help of the code that you've provided. I don't have a fix at this moment, but I think there's a workaround, please try setting a minHeight (any positive value should work, like 1 or 0.000001) on the verticalLineLayout.

nicksnyder commented 6 years ago

Yeah, this looks like a bug. That said, I was not able to reproduce it in a playground:

image

import UIKit
import PlaygroundSupport
import LayoutKit

let iconLayout = SizeLayout<UIView>(width: 22, height: 22, config: { view in
    view.backgroundColor = .red
})
let verticalLineLayout = SizeLayout<UIView>(width: 3, config: { view in
    view.backgroundColor = UIColor.black
})

let stackLayout = StackLayout(axis: .vertical, spacing: 10, sublayouts: [iconLayout, verticalLineLayout])

let sizeLayout = SizeLayout(size: CGSize(width: 100, height: 100), sublayout: stackLayout, config: { view in
    view.backgroundColor = .blue
})

sizeLayout.arrangement().makeViews()
itskoBits commented 6 years ago

The black bar goes outside of the bounds of the blue view. The playground is displaying the blue view only within its bounds. Here is sample playground code that displays the issue.

playground

import UIKit
import PlaygroundSupport
import LayoutKit

let iconLayout = SizeLayout<UIView>(width: 22, height: 22, config: { view in
    view.backgroundColor = .red
})
let verticalLineLayout = SizeLayout<UIView>(width: 3, config: { view in
    view.backgroundColor = UIColor.black
})

let stackLayout = StackLayout(axis: .vertical, spacing: 10, sublayouts: [iconLayout, verticalLineLayout])

let sizeLayout = SizeLayout(size: CGSize(width: 100, height: 100), sublayout: stackLayout, config: { view in
    view.backgroundColor = .blue
})

let otherView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
sizeLayout.arrangement().makeViews(in: otherView, direction: .leftToRight)
staguer commented 6 years ago

Another way to reproduce it is by adding a print(arrangement.debugDescription)

staguer commented 6 years ago

@itskoBits Have you had a chance to try the workaround? Does it work for you?

itskoBits commented 6 years ago

@staguer Yes, it did work for me.