Skip to content

Commit

Permalink
Flexibility behavior (#23)
Browse files Browse the repository at this point in the history
* Preparing for flexible views

* Flexibility behavior

* Justified

* Line breaking improvements

* Manual line break awareness

* Cleanup

* Handle maximum flexibility more gracefully

* New tests covering flexibility
  • Loading branch information
tevelee authored Dec 19, 2024
1 parent c8e85a7 commit 599c97a
Show file tree
Hide file tree
Showing 10 changed files with 474 additions and 355 deletions.
52 changes: 28 additions & 24 deletions Sources/Flow/HFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public struct HFlow<Content: View>: View {
/// want the flow to choose a default distance for each pair of subviews.
/// - rowSpacing: The distance between rows of subviews, or `nil` if you
/// want the flow to choose a default distance for each pair of rows.
/// - justification: Whether the layout should fill the remaining
/// available space in each row by stretching either items or spaces.
/// - justified: Whether the layout should fill the remaining
/// available space in each row by stretching spaces.
/// - distributeItemsEvenly: Instead of prioritizing the first rows, this
/// mode tries to distribute items more evenly by minimizing the empty
/// spaces left in each row, while respecting their order.
Expand All @@ -45,7 +45,7 @@ public struct HFlow<Content: View>: View {
alignment: VerticalAlignment = .center,
itemSpacing: CGFloat? = nil,
rowSpacing: CGFloat? = nil,
justification: Justification? = nil,
justified: Bool = false,
distributeItemsEvenly: Bool = false,
@ViewBuilder content contentBuilder: () -> Content
) {
Expand All @@ -54,7 +54,7 @@ public struct HFlow<Content: View>: View {
alignment: alignment,
itemSpacing: itemSpacing,
rowSpacing: rowSpacing,
justification: justification,
justified: justified,
distributeItemsEvenly: distributeItemsEvenly
)
}
Expand All @@ -66,8 +66,8 @@ public struct HFlow<Content: View>: View {
/// guide has the same vertical screen coordinate for every child view.
/// - spacing: The distance between adjacent subviews, or `nil` if you
/// want the flow to choose a default distance for each pair of subviews.
/// - justification: Whether the layout should fill the remaining
/// available space in each row by stretching either items or spaces.
/// - justified: Whether the layout should fill the remaining
/// available space in each row by stretching spaces.
/// - distributeItemsEvenly: Instead of prioritizing the first rows, this
/// mode tries to distribute items more evenly by minimizing the empty
/// spaces left in each row, while respecting their order.
Expand All @@ -76,15 +76,15 @@ public struct HFlow<Content: View>: View {
public init(
alignment: VerticalAlignment = .center,
spacing: CGFloat? = nil,
justification: Justification? = nil,
justified: Bool = false,
distributeItemsEvenly: Bool = false,
@ViewBuilder content contentBuilder: () -> Content
) {
self.init(
alignment: alignment,
itemSpacing: spacing,
rowSpacing: spacing,
justification: justification,
justified: justified,
distributeItemsEvenly: distributeItemsEvenly,
content: contentBuilder
)
Expand All @@ -97,8 +97,8 @@ public struct HFlow<Content: View>: View {
/// - horizonalSpacing: The distance between subviews on the horizontal axis.
/// - verticalAlignment: The guide for aligning the subviews vertically.
/// - verticalSpacing: The distance between subviews on the vertical axis.
/// - justification: Whether the layout should fill the remaining
/// available space in each row by stretching either items or spaces.
/// - justified: Whether the layout should fill the remaining
/// available space in each row by stretching spaces.
/// - distributeItemsEvenly: Instead of prioritizing the first rows, this
/// mode tries to distribute items more evenly by minimizing the empty
/// spaces left in each row, while respecting their order.
Expand All @@ -109,7 +109,7 @@ public struct HFlow<Content: View>: View {
verticalAlignment: VerticalAlignment,
horizontalSpacing: CGFloat? = nil,
verticalSpacing: CGFloat? = nil,
justification: Justification? = nil,
justified: Bool = false,
distributeItemsEvenly: Bool = false,
@ViewBuilder content contentBuilder: () -> Content
) {
Expand All @@ -119,15 +119,19 @@ public struct HFlow<Content: View>: View {
verticalAlignment: verticalAlignment,
horizontalSpacing: horizontalSpacing,
verticalSpacing: verticalSpacing,
justification: justification,
justified: justified,
distributeItemsEvenly: distributeItemsEvenly
)
}

@usableFromInline
@Environment(\.flexibility) var flexibility

@inlinable
public var body: some View {
layout {
content
.layoutValue(key: FlexibilityLayoutValueKey.self, value: flexibility)
}
}
}
Expand All @@ -146,8 +150,8 @@ extension HFlow: Layout where Content == EmptyView {
/// want the flow to choose a default distance for each pair of subviews.
/// - rowSpacing: The distance between rows of subviews, or `nil` if you
/// want the flow to choose a default distance for each pair of rows.
/// - justification: Whether the layout should fill the remaining
/// available space in each row by stretching either items or spaces.
/// - justified: Whether the layout should fill the remaining
/// available space in each row by stretching spaces.
/// - distributeItemsEvenly: Instead of prioritizing the first rows, this
/// mode tries to distribute items more evenly by minimizing the empty
/// spaces left in each row, while respecting their order.
Expand All @@ -156,14 +160,14 @@ extension HFlow: Layout where Content == EmptyView {
alignment: VerticalAlignment = .center,
itemSpacing: CGFloat? = nil,
rowSpacing: CGFloat? = nil,
justification: Justification? = nil,
justified: Bool = false,
distributeItemsEvenly: Bool = false
) {
self.init(
alignment: alignment,
itemSpacing: itemSpacing,
rowSpacing: rowSpacing,
justification: justification,
justified: justified,
distributeItemsEvenly: distributeItemsEvenly
) {
EmptyView()
Expand All @@ -177,22 +181,22 @@ extension HFlow: Layout where Content == EmptyView {
/// guide has the same vertical screen coordinate for every child view.
/// - spacing: The distance between adjacent subviews, or `nil` if you
/// want the flow to choose a default distance for each pair of subviews.
/// - justification: Whether the layout should fill the remaining
/// available space in each row by stretching either items or spaces.
/// - justified: Whether the layout should fill the remaining
/// available space in each row by stretching spaces.
/// - distributeItemsEvenly: Instead of prioritizing the first rows, this
/// mode tries to distribute items more evenly by minimizing the empty
/// spaces left in each row, while respecting their order.
@inlinable
public init(
alignment: VerticalAlignment = .center,
spacing: CGFloat? = nil,
justification: Justification? = nil,
justified: Bool = false,
distributeItemsEvenly: Bool = false
) {
self.init(
alignment: alignment,
spacing: spacing,
justification: justification,
justified: justified,
distributeItemsEvenly: distributeItemsEvenly
) {
EmptyView()
Expand All @@ -206,8 +210,8 @@ extension HFlow: Layout where Content == EmptyView {
/// - horizonalSpacing: The distance between subviews on the horizontal axis.
/// - verticalAlignment: The guide for aligning the subviews vertically.
/// - verticalSpacing: The distance between subviews on the vertical axis.
/// - justification: Whether the layout should fill the remaining
/// available space in each row by stretching either items or spaces.
/// - justified: Whether the layout should fill the remaining
/// available space in each row by stretching spaces.
/// - distributeItemsEvenly: Instead of prioritizing the first rows, this
/// mode tries to distribute items more evenly by minimizing the empty
/// spaces left in each row, while respecting their order.
Expand All @@ -217,15 +221,15 @@ extension HFlow: Layout where Content == EmptyView {
verticalAlignment: VerticalAlignment,
horizontalSpacing: CGFloat? = nil,
verticalSpacing: CGFloat? = nil,
justification: Justification? = nil,
justified: Bool = false,
distributeItemsEvenly: Bool = false
) {
self.init(
horizontalAlignment: horizontalAlignment,
verticalAlignment: verticalAlignment,
horizontalSpacing: horizontalSpacing,
verticalSpacing: verticalSpacing,
justification: justification,
justified: justified,
distributeItemsEvenly: distributeItemsEvenly
) {
EmptyView()
Expand Down
16 changes: 8 additions & 8 deletions Sources/Flow/HFlowLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public struct HFlowLayout: Sendable {
/// guide has the same vertical screen coordinate for every child view.
/// - spacing: The distance between adjacent subviews, or `nil` if you
/// want the flow to choose a default distance for each pair of subviews.
/// - justification: Whether the layout should fill the remaining
/// available space in each row by stretching either items or spaces.
/// - justified: Whether the layout should fill the remaining
/// available space in each row by stretching spaces.
/// - distributeItemsEvenly: Instead of prioritizing the first rows, this
/// mode tries to distribute items more evenly by minimizing the empty
/// spaces left in each row, while respecting their order.
Expand All @@ -23,15 +23,15 @@ public struct HFlowLayout: Sendable {
alignment: VerticalAlignment = .center,
itemSpacing: CGFloat? = nil,
rowSpacing: CGFloat? = nil,
justification: Justification? = nil,
justified: Bool = false,
distributeItemsEvenly: Bool = false
) {
self.init(
horizontalAlignment: .leading,
verticalAlignment: alignment,
horizontalSpacing: itemSpacing,
verticalSpacing: rowSpacing,
justification: justification,
justified: justified,
distributeItemsEvenly: distributeItemsEvenly
)
}
Expand All @@ -43,8 +43,8 @@ public struct HFlowLayout: Sendable {
/// - horizonalSpacing: The distance between subviews on the horizontal axis.
/// - verticalAlignment: The guide for aligning the subviews vertically.
/// - verticalSpacing: The distance between subviews on the vertical axis.
/// - justification: Whether the layout should fill the remaining
/// available space in each row by stretching either items or spaces.
/// - justified: Whether the layout should fill the remaining
/// available space in each row by stretching spaces.
/// - distributeItemsEvenly: Instead of prioritizing the first rows, this
/// mode tries to distribute items more evenly by minimizing the empty
/// spaces left in each row, while respecting their order.
Expand All @@ -54,15 +54,15 @@ public struct HFlowLayout: Sendable {
verticalAlignment: VerticalAlignment,
horizontalSpacing: CGFloat? = nil,
verticalSpacing: CGFloat? = nil,
justification: Justification? = nil,
justified: Bool = false,
distributeItemsEvenly: Bool = false
) {
layout = .horizontal(
horizontalAlignment: horizontalAlignment,
verticalAlignment: verticalAlignment,
horizontalSpacing: horizontalSpacing,
verticalSpacing: verticalSpacing,
justification: justification,
justified: justified,
distributeItemsEvenly: distributeItemsEvenly
)
}
Expand Down
Loading

0 comments on commit 599c97a

Please sign in to comment.