我以前曾创造过你需要的东西。
我HStack
在VStack
.
您传入geometryProxy
用于确定最大行宽的 a。我把它传入了,所以它可以在滚动视图中使用
我将 SwiftUI 视图包装在 UIHostingController 中,以获得每个孩子的大小。
然后,我循环浏览视图,将它们添加到行中,直到达到最大宽度,在这种情况下,我开始添加到新行。
这只是组合和输出 VStack 中的行的初始和最终阶段
struct WrappedHStack<Content: View>: View {
private let content: [Content]
private let spacing: CGFloat = 8
private let geometry: GeometryProxy
init(geometry: GeometryProxy, content: [Content]) {
self.content = content
self.geometry = geometry
}
var body: some View {
let rowBuilder = RowBuilder(spacing: spacing,
containerWidth: geometry.size.width)
let rowViews = rowBuilder.generateRows(views: content)
let finalView = ForEach(rowViews.indices) { rowViews[$0] }
VStack(alignment: .center, spacing: 8) {
finalView
}.frame(width: geometry.size.width)
}
}
extension WrappedHStack {
init<Data, ID: Hashable>(geometry: GeometryProxy, @ViewBuilder content: () -> ForEach<Data, ID, Content>) {
let views = content()
self.geometry = geometry
self.content = views.data.map(views.content)
}
init(geometry: GeometryProxy, content: () -> [Content]) {
self.geometry = geometry
self.content = content()
}
}
魔法发生在这里
extension WrappedHStack {
struct RowBuilder {
private var spacing: CGFloat
private var containerWidth: CGFloat
init(spacing: CGFloat, containerWidth: CGFloat) {
self.spacing = spacing
self.containerWidth = containerWidth
}
func generateRows<Content: View>(views: [Content]) -> [AnyView] {
var rows = [AnyView]()
var currentRowViews = [AnyView]()
var currentRowWidth: CGFloat = 0
for (view) in views {
let viewWidth = view.getSize().width
if currentRowWidth + viewWidth > containerWidth {
rows.append(createRow(for: currentRowViews))
currentRowViews = []
currentRowWidth = 0
}
currentRowViews.append(view.erasedToAnyView())
currentRowWidth += viewWidth + spacing
}
rows.append(createRow(for: currentRowViews))
return rows
}
private func createRow(for views: [AnyView]) -> AnyView {
HStack(alignment: .center, spacing: spacing) {
ForEach(views.indices) { views[$0] }
}
.erasedToAnyView()
}
}
}
这是我使用的扩展
extension View {
func erasedToAnyView() -> AnyView {
AnyView(self)
}
func getSize() -> CGSize {
UIHostingController(rootView: self).view.intrinsicContentSize
}
}
您可以在此处查看带有一些示例的完整代码:
https ://gist.github.com/kanesbetas/63e719cb96e644d31bf027194bf4ccdb