import SwiftUI //自动换行 //https://stackoverflow.com/questions/58842453/hstack-with-wrap RelativeJoe的回答 public struct OverflowGrid: Layout { private var horizontalSpacing: CGFloat private var vericalSpacing: CGFloat public init(horizontalSpacing: CGFloat, vericalSpacing: CGFloat? = nil) { self.horizontalSpacing = horizontalSpacing self.vericalSpacing = vericalSpacing ?? horizontalSpacing } public func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { let height = subviews.max(by: {$0.dimensions(in: proposal).height > $1.dimensions(in: proposal).height})?.dimensions(in: proposal).height ?? 0 var rows = [CGFloat]() subviews.indices.forEach { index in let rowIndex = rows.count - 1 let subViewWidth = subviews[index].dimensions(in: proposal).width guard !rows.isEmpty else { rows.append(subViewWidth) return } let newWidth = rows[rowIndex] + subViewWidth + horizontalSpacing if newWidth < proposal.width ?? 0 { rows[rowIndex] += (rows[rowIndex] > 0 ? horizontalSpacing: 0) + subViewWidth }else { rows.append(subViewWidth) } } let count = CGFloat(rows.count) return CGSize(width: rows.max() ?? 0, height: count * height + (count - 1) * vericalSpacing) } public func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { let height = subviews.max(by: {$0.dimensions(in: proposal).height > $1.dimensions(in: proposal).height})?.dimensions(in: proposal).height ?? 0 guard !subviews.isEmpty else {return} var x = bounds.minX var y = height/2 + bounds.minY subviews.indices.forEach { index in let subView = subviews[index] x += subView.dimensions(in: proposal).width/2 subviews[index].place(at: CGPoint(x: x, y: y), anchor: .center, proposal: ProposedViewSize(width: subView.dimensions(in: proposal).width, height: subView.dimensions(in: proposal).height)) x += horizontalSpacing + subView.dimensions(in: proposal).width/2 if x > bounds.width { x = bounds.minX y += height + vericalSpacing } } } }