//
|
// Untitled.swift
|
// LiveProject
|
//
|
// Created by 倪路朋 on 6/26/25.
|
//
|
import SwiftUI
|
|
struct FlowLayout: Layout {
|
var spacing: CGFloat = 8
|
var lineSpacing: CGFloat = 8
|
|
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
|
var width: CGFloat = 0
|
var height: CGFloat = 0
|
var currentLineWidth: CGFloat = 0
|
var currentLineHeight: CGFloat = 0
|
let maxWidth = proposal.width ?? .infinity
|
|
for view in subviews {
|
let size = view.sizeThatFits(.unspecified)
|
if currentLineWidth + size.width > maxWidth {
|
width = max(width, currentLineWidth)
|
height += currentLineHeight + lineSpacing
|
currentLineWidth = size.width
|
currentLineHeight = size.height
|
} else {
|
currentLineWidth += size.width + spacing
|
currentLineHeight = max(currentLineHeight, size.height)
|
}
|
}
|
|
width = max(width, currentLineWidth)
|
height += currentLineHeight
|
|
return CGSize(width: width, height: height)
|
}
|
|
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
|
var x: CGFloat = 0
|
var y: CGFloat = 0
|
var lineHeight: CGFloat = 0
|
|
for view in subviews {
|
let size = view.sizeThatFits(.unspecified)
|
|
if x + size.width > bounds.width {
|
x = 0
|
y += lineHeight + lineSpacing
|
lineHeight = 0
|
}
|
|
view.place(
|
at: CGPoint(x: bounds.minX + x, y: bounds.minY + y),
|
proposal: ProposedViewSize(width: size.width, height: size.height)
|
)
|
|
x += size.width + spacing
|
lineHeight = max(lineHeight, size.height)
|
}
|
}
|
}
|
// MARK: - 使用示例
|
|
struct FlowLayoutExample: View {
|
let tags = [
|
"Swift"
|
]
|
|
@State private var newTag = ""
|
@State private var customTags = ["自定义标签1", "自定义标签2"]
|
|
var body: some View {
|
VStack{
|
VStack(spacing: 20) {
|
FlowLayout(){
|
|
ForEach(tags, id: \.self) { item in
|
Text(item)
|
.padding(.horizontal, 12)
|
.padding(.vertical, 6)
|
.background(Color.blue.opacity(0.2))
|
.cornerRadius(8)
|
}
|
}.frame(alignment:.leading)
|
.background(Color.red)
|
}
|
.frame(maxWidth: .infinity,alignment:.leading)
|
}
|
.background(Color.black)
|
}
|
|
private func addTag() {
|
withAnimation {
|
customTags.append(newTag)
|
newTag = ""
|
}
|
}
|
}
|
|
/// 标签视图
|
struct TagView: View {
|
let text: String
|
|
var body: some View {
|
Text(text)
|
.padding(.horizontal, 12)
|
.padding(.vertical, 8)
|
.background(Color.blue.opacity(0.2))
|
.foregroundColor(.blue)
|
.cornerRadius(10)
|
.overlay(
|
RoundedRectangle(cornerRadius: 10)
|
.stroke(Color.blue, lineWidth: 1)
|
)
|
.fixedSize(horizontal: true, vertical: false) // 确保文本不被截断
|
}
|
}
|
|
// MARK: - 预览
|
|
struct FlowLayout_Previews: PreviewProvider {
|
static var previews: some View {
|
FlowLayoutExample()
|
}
|
}
|