From 2b51baa1981fb445b938e64bdce539e58fe70264 Mon Sep 17 00:00:00 2001
From: Runt <qingingrunt2010@qq.com>
Date: Sat, 26 Jul 2025 13:17:14 +0000
Subject: [PATCH] 小窗缩放, 相机转小窗显示 小窗旋转,相机画面旋转 关闭按钮优化

---
 LiveProject/views/FlowLayout.swift |  190 ++++++++++++++---------------------------------
 1 files changed, 58 insertions(+), 132 deletions(-)

diff --git a/LiveProject/views/FlowLayout.swift b/LiveProject/views/FlowLayout.swift
index 151cd68..038d158 100644
--- a/LiveProject/views/FlowLayout.swift
+++ b/LiveProject/views/FlowLayout.swift
@@ -5,163 +5,89 @@
 //  Created by 倪路朋 on 6/26/25.
 //
 import SwiftUI
-import SwiftUI
 
-/// 完全自定义的自动换行布局容器
-struct FlowLayout<Data: RandomAccessCollection, Content: View>: View where Data.Element: Hashable {
-    // MARK: - 属性
-    
-    /// 要显示的数据集合
-    let data: Data
-    /// 水平间距
-    let horizontalSpacing: CGFloat
-    /// 垂直间距
-    let verticalSpacing: CGFloat
-    /// 对齐方式
-    let alignment: HorizontalAlignment
-    /// 内容构建闭包
-    let content: (Data.Element) -> Content
-    /// 总高度状态
-    @State private var totalHeight: CGFloat = 0
-    
-    // MARK: - 初始化
-    
-    /// 初始化FlowLayout
-    /// - Parameters:
-    ///   - data: 要显示的数据集合
-    ///   - horizontalSpacing: 水平间距,默认为8
-    ///   - verticalSpacing: 垂直间距,默认为8
-    ///   - alignment: 对齐方式,默认为.leading
-    ///   - content: 内容构建闭包
-    init(
-        _ data: Data,
-        horizontalSpacing: CGFloat = 8,
-        verticalSpacing: CGFloat = 8,
-        alignment: HorizontalAlignment = .leading,
-        @ViewBuilder content: @escaping (Data.Element) -> Content
-    ) {
-        self.data = data
-        self.horizontalSpacing = horizontalSpacing
-        self.verticalSpacing = verticalSpacing
-        self.alignment = alignment
-        self.content = content
-    }
-    
-    // MARK: - 主体视图
-    
-    var body: some View {
-        GeometryReader { geometry in
-            self.contentView(in: geometry)
-                .background(
-                    HeightReader(height: $totalHeight)
-                )
-        }
-        .frame(height: totalHeight)
-    }
-    
-    // MARK: - 私有方法
-    
-    /// 构建内容视图
-    private func contentView(in geometry: GeometryProxy) -> some View {
+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 lastHeight: CGFloat = 0
-        
-        return ZStack(alignment: Alignment(horizontal: alignment, vertical: .top)) {
-            ForEach(data.map { $0 }, id: \.self) { item in
-                content(item)
-                    .padding(.trailing, horizontalSpacing)
-                    .padding(.bottom, verticalSpacing)
-                    .alignmentGuide(.leading) { dimensions in
-                        // 检查是否需要换行
-                        if abs(width - dimensions.width) > geometry.size.width {
-                            width = 0
-                            height += lastHeight + verticalSpacing
-                        }
-                        
-                        let result = width
-                        
-                        // 更新宽度计算
-                        if item == data.last {
-                            width = 0 // 重置为0,最后一项
-                        } else {
-                            width -= dimensions.width + horizontalSpacing
-                        }
-                        
-                        // 记录当前行高度
-                        lastHeight = dimensions.height
-                        return result
-                    }
-                    .alignmentGuide(.top) { dimensions in
-                        let result = height
-                        
-                        // 如果是最后一项,更新总高度
-                        if item == data.last {
-                            height += lastHeight + verticalSpacing
-                        }
-                        
-                        return result
-                    }
+        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)
     }
-}
 
-// MARK: - 高度读取器
+    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
+        var x: CGFloat = 0
+        var y: CGFloat = 0
+        var lineHeight: CGFloat = 0
 
-/// 用于读取视图高度的辅助视图
-private struct HeightReader: View {
-    @Binding var height: CGFloat
-    
-    var body: some View {
-        GeometryReader { geometry in
-            Color.clear
-                .preference(
-                    key: HeightPreferenceKey.self,
-                    value: geometry.size.height
-                )
-        }
-        .onPreferenceChange(HeightPreferenceKey.self) { newHeight in
-            DispatchQueue.main.async {
-                self.height = newHeight
+        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: - 高度偏好键
-
-/// 用于传递高度值的PreferenceKey
-private struct HeightPreferenceKey: PreferenceKey {
-    static var defaultValue: CGFloat = 0
-    
-    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
-        value = nextValue()
-    }
-}
-
 // MARK: - 使用示例
 
 struct FlowLayoutExample: View {
     let tags = [
-        "Swift", "SwiftUI", "UIKit", "Combine", "Core Data",
-        "Xcode", "Interface Builder", "Core Animation", "ARKit",
-        "Metal", "Core ML", "Vision", "MapKit", "CloudKit"
+        "Swift"
     ]
     
     @State private var newTag = ""
     @State private var customTags = ["自定义标签1", "自定义标签2"]
     
     var body: some View {
-        VStack {
-            FlowLayout(customTags + tags, horizontalSpacing: 10, verticalSpacing: 10) { tag in
-                MButton(text:tag){
+        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)
             }
-            .padding()
-            .animation(.default, value: customTags)
+            .frame(maxWidth: .infinity,alignment:.leading)
         }
+        .background(Color.black)
     }
     
     private func addTag() {

--
Gitblit v1.9.1