美文网首页
SwiftUI-FlexibleView-自动预估高度-Grid

SwiftUI-FlexibleView-自动预估高度-Grid

作者: 慧煎蛋 | 来源:发表于2024-01-15 10:04 被阅读0次

import SwiftUI

struct FlexibleView<Data: Collection, Content: View>: View where Data.Element: Hashable {
    let data: Data //数据元
    let spacing: CGFloat //行/列间距
    let availableWidth: CGFloat //总宽度
    var alignment: HorizontalAlignment = .leading
    var targetline: Int = 3 //预估行数, 使高度能空白填充, 和其他数量不同的地方保持高度一致

    let content: (Data.Element) -> Content
    @State var elementsSize: [Data.Element: CGSize] = [:]

    var body: some View {
        if data.isEmpty {
            EmptyView()
        }else{
            ZStack(alignment: .topLeading) {
                VStack(alignment: alignment, spacing: spacing) {
                    ForEach(0..<targetline, id: \.self) { _ in
                        content(data.first!)//每个
                            .fixedSize()
                            .opacity(0)
                    }
                }
                
                VStack(alignment: alignment, spacing: spacing) {
                    ForEach(computeRows(), id: \.self) { rowElements in
                        HStack(spacing: spacing) {//每行
                            ForEach(rowElements, id: \.self) { element in
                                content(element)//每个
                                    .fixedSize()
                                    .readSize { size in
                                        elementsSize[element] = size
                                    }
                            }
                        }
                    }
                }
            }
        }
        
    }

    func computeRows() -> [[Data.Element]] {//计算行数和每个
        var rows: [[Data.Element]] = [[]]
        var currentRow = 0
        var remainingWidth = availableWidth

        for element in data {
            let elementSize = elementsSize[element, default: CGSize(width: availableWidth, height: 1)]

            if remainingWidth - (elementSize.width + spacing) >= -4 {
                rows[currentRow].append(element)
            } else {
                currentRow = currentRow + 1
                rows.append([element])
                remainingWidth = availableWidth
            }

            remainingWidth = remainingWidth - (elementSize.width + spacing)
        }

        return rows
    }
}

struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}

public extension View {
    func readSize(onChange: @escaping (CGSize) -> Void) -> some View {//size识别
        return background(
            GeometryReader { geometryProxy in
                Color.clear
                    .preference(key: SizePreferenceKey.self, value: geometryProxy.size)
            }
        )
        .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
    }
}

以上

相关文章

网友评论

      本文标题:SwiftUI-FlexibleView-自动预估高度-Grid

      本文链接:https://www.haomeiwen.com/subject/jufhodtx.html