Last active
June 2, 2022 16:15
-
-
Save robhasacamera/379fe5a88fc5bd5cbfddd1994fe5b96a to your computer and use it in GitHub Desktop.
This file contains 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 characters
import SwiftUI | |
// Adapted from: https://stackoverflow.com/questions/62102647/swiftui-hstack-with-wrap-and-dynamic-height/62103264#62103264 | |
struct WrappingHStack<Model, V>: View where Model: Hashable, V: View { | |
typealias ViewGenerator = (Model) -> V | |
var models: [Model] | |
var viewGenerator: ViewGenerator | |
var horizontalSpacing: CGFloat = 2 | |
var verticalSpacing: CGFloat = 0 | |
@State private var totalHeight | |
= CGFloat.zero // << variant for ScrollView/List | |
// = CGFloat.infinity // << variant for VStack | |
var body: some View { | |
VStack { | |
GeometryReader { geometry in | |
self.generateContent(in: geometry) | |
} | |
} | |
.frame(height: totalHeight)// << variant for ScrollView/List | |
//.frame(maxHeight: totalHeight) // << variant for VStack | |
} | |
private func generateContent(in geometry: GeometryProxy) -> some View { | |
var width = CGFloat.zero | |
var height = CGFloat.zero | |
return ZStack(alignment: .topLeading) { | |
ForEach(self.models, id: \.self) { models in | |
viewGenerator(models) | |
.padding(.horizontal, horizontalSpacing) | |
.padding(.vertical, verticalSpacing) | |
.alignmentGuide(.leading, computeValue: { dimension in | |
if (abs(width - dimension.width) > geometry.size.width) | |
{ | |
width = 0 | |
height -= dimension.height | |
} | |
let result = width | |
if models == self.models.last! { | |
width = 0 //last item | |
} else { | |
width -= dimension.width | |
} | |
return result | |
}) | |
.alignmentGuide(.top, computeValue: {dimension in | |
let result = height | |
if models == self.models.last! { | |
height = 0 // last item | |
} | |
return result | |
}) | |
} | |
}.background(viewHeightReader($totalHeight)) | |
} | |
private func viewHeightReader(_ binding: Binding<CGFloat>) -> some View { | |
return GeometryReader { geometry -> Color in | |
let rect = geometry.frame(in: .local) | |
DispatchQueue.main.async { | |
binding.wrappedValue = rect.size.height | |
} | |
return .clear | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is great.
how can I make align right, rather than with left?