Created
December 11, 2021 13:05
-
-
Save globulus/5ac8aacfb68c3ee3007ac98a7dbf63f8 to your computer and use it in GitHub Desktop.
Revisions
-
globulus created this gist
Dec 11, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,158 @@ // Full recipe at https://swiftuirecipes.com/blog/weighted-layout-hstack-and-vstack-in-swiftui import SwiftUI class WeightedProxy { let kind: Kind var geo: GeometryProxy? = nil private(set) var totalWeight: CGFloat = 0 init(kind: Kind) { self.kind = kind } func register(with weight: CGFloat) { totalWeight += weight } func dimensionForRelative(weight: CGFloat) -> CGFloat { guard let geo = geo, totalWeight > 0 else { return 0 } let dimension = (kind == .vertical) ? geo.size.height : geo.size.width return dimension * weight / totalWeight } enum Kind { case vertical, horizontal } } struct Weighted: ViewModifier { private let weight: CGFloat private let proxy: WeightedProxy init(_ weight: CGFloat, proxy: WeightedProxy) { self.weight = weight self.proxy = proxy proxy.register(with: weight) } @ViewBuilder func body(content: Content) -> some View { if proxy.kind == .vertical { content.frame(height: proxy.dimensionForRelative(weight: weight)) } else { content.frame(width: proxy.dimensionForRelative(weight: weight)) } } } extension View { func weighted(_ weight: CGFloat, proxy: WeightedProxy) -> some View { self.modifier(Weighted(weight, proxy: proxy)) } } struct WeightedHStack<Content>: View where Content : View { private let proxy = WeightedProxy(kind: .horizontal) @State private var initialized = false @ViewBuilder let content: (WeightedProxy) -> Content var body: some View { GeometryReader { geo in HStack(spacing: 0) { if initialized { content(proxy) } else { Color.clear.onAppear { proxy.geo = geo initialized.toggle() } } } } } } struct WeightedVStack<Content>: View where Content : View { private let proxy = WeightedProxy(kind: .vertical) @State private var initialized = false @ViewBuilder let content: (WeightedProxy) -> Content var body: some View { GeometryReader { geo in VStack(spacing: 0) { if initialized { content(proxy) } else { Color.clear.onAppear { proxy.geo = geo initialized.toggle() } } } } } } struct WeightsTest: View { var body: some View { // VStack { // WeightedHStack { proxy in // Text("50%") // .weighted(5, proxy: proxy) // .background(Color.blue) // Text("20%") // .weighted(2, proxy: proxy) // .background(Color.green) // Text("30%") // .weighted(3, proxy: proxy) // .background(Color.red) // } // WeightedHStack { proxy in // Text("15%") // .weighted(0.15, proxy: proxy) // .background(Color.brown) // Text("15%") // .weighted(0.15, proxy: proxy) // .background(Color.cyan) // Text("55%") // .weighted(0.55, proxy: proxy) // .background(Color.black) // Text("15%") // .weighted(0.15, proxy: proxy) // .background(Color.pink) // } // WeightedHStack { proxy in // Text("30%") // .weighted(3, proxy: proxy) // .background(Color.purple) // Text("40%") // .weighted(4, proxy: proxy) // .background(Color.yellow) // Text("30%") // .weighted(3, proxy: proxy) // .background(Color.indigo) // } // Spacer() // } WeightedVStack { proxy in Text("20%") .frame(minWidth: 0, maxWidth: .infinity) .weighted(2, proxy: proxy) .background(Color.green) Text("50%") .frame(minWidth: 0, maxWidth: .infinity) .weighted(5, proxy: proxy) .background(Color.red) Text("30%") .frame(minWidth: 0, maxWidth: .infinity) .weighted(3, proxy: proxy) .background(Color.cyan) } .padding() .foregroundColor(.white) } }