Files
App/ios/WatchRunner Watch App/Layouts/FlowLayout.swift
2025-10-29 01:26:27 +08:00

89 lines
2.9 KiB
Swift

//
// FlowLayout.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
// MARK: - Custom Layouts
struct FlowLayout: Layout {
var alignment: HorizontalAlignment = .leading
var spacing: CGFloat = 10
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let containerWidth = proposal.width ?? 0
let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
var currentX: CGFloat = 0
var currentY: CGFloat = 0
var lineHeight: CGFloat = 0
var totalHeight: CGFloat = 0
for size in sizes {
if currentX + size.width > containerWidth {
// New line
currentX = 0
currentY += lineHeight + spacing
totalHeight = currentY + size.height
lineHeight = 0
}
currentX += size.width + spacing
lineHeight = max(lineHeight, size.height)
}
totalHeight = currentY + lineHeight
return CGSize(width: containerWidth, height: totalHeight)
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let containerWidth = bounds.width
let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
var currentX: CGFloat = 0
var currentY: CGFloat = 0
var lineHeight: CGFloat = 0
var lineElements: [(offset: Int, size: CGSize)] = []
func placeLine() {
let lineWidth = lineElements.map { $0.size.width }.reduce(0, +) + CGFloat(lineElements.count - 1) * spacing
var startX: CGFloat = 0
switch alignment {
case .leading:
startX = bounds.minX
case .center:
startX = bounds.minX + (containerWidth - lineWidth) / 2
case .trailing:
startX = bounds.maxX - lineWidth
default:
startX = bounds.minX
}
var xOffset = startX
for (offset, size) in lineElements {
subviews[offset].place(at: CGPoint(x: xOffset, y: bounds.minY + currentY), proposal: ProposedViewSize(size)) // Use bounds.minY + currentY
xOffset += size.width + spacing
}
lineElements.removeAll() // Clear elements for the next line
}
for (offset, size) in sizes.enumerated() {
if currentX + size.width > containerWidth && !lineElements.isEmpty {
// New line
placeLine()
currentX = 0
currentY += lineHeight + spacing
lineHeight = 0
}
lineElements.append((offset, size))
currentX += size.width + spacing
lineHeight = max(lineHeight, size.height)
}
placeLine() // Place the last line
}
}