如果没有足够的空间swiftui,我如何将网格项发送到下一行

vwoqyblh  于 2023-05-16  发布在  Swift
关注(0)|答案(1)|浏览(85)

我对swift有些陌生,正在努力解决这个看似简单的问题。我希望在我的网格中有三列,除非网格项的内容不适合设置的列宽度。具体来说,我有过滤器按钮,其中一些有很长的名称。我想将“Breakfast”的TagView发送到下一行,并移动每一行沿着以便它们都适合,并且文本不必换行。不知道该怎么做。
我尝试调整网格项中的最小值和最大值,并调整列中GridItem的数量。然而,不幸的是,这并没有奏效。任何建议将不胜感激。
下面是我的代码:

var filterBar: some View {
        VStack {
            filterBarTitle
            if filtersOpened {
                let columns = [GridItem(.adaptive(minimum: 85), spacing:0)]
                
                LazyVGrid(columns: columns) {
                    ForEach(allRecipeTags) { recipeTag in
                        TagView(tag: recipeTag, selected: selectedTags.contains(recipeTag), canToggle: true, onTap: {
                            if selectedTags.contains(recipeTag) {
                                print("removing \(recipeTag)")
                                selectedTags.removeAll(where: { $0 == recipeTag })
                            } else {
                                print("adding \(recipeTag)")
                                selectedTags.append(recipeTag)
                            }
                        })
                        .border(.red)
                    }
                }
                .border(.blue)
            }
        }
        .padding([.top, .bottom])
        .border(width: 1, edges: [.bottom], color: Color("24292F").opacity(0.3))
        .padding(.horizontal)
        .padding([.bottom], filtersOpened ? 8 : 0)
    }

FilterBar Image

ccrfmcuu

ccrfmcuu1#

下面是一个自定义Layout的简单实现,希望它能满足您的需求:

struct ContentView: View {
    
    let tags = ["Appetizers","Baking","Breakfast","Dessert","Dinner","Fish","Lunch","Main","Quick","Side","Snack","Spicy","Vegan","Vegetarian"]
    
    var body: some View {

        FlowLayout {
                ForEach(tags, id: \.self) { tag in
                    
                    HStack {
                        Text(tag)
                            .fixedSize()
                            .font(.headline)

                        Circle()
                    }
                    .padding(10)
                            .background(
                                Capsule().stroke(.red)
                            )
                            .padding(5)
                }
        }
    }
}

struct FlowLayout: Layout {
    
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        let sizes = subviews.map { $0.sizeThatFits(.unspecified) }

        var totalHeight: CGFloat = 0
        var totalWidth: CGFloat = 0

        var lineWidth: CGFloat = 0
        var lineHeight: CGFloat = 0

        for size in sizes {
            if lineWidth + size.width > proposal.width ?? 0 {
                totalHeight += lineHeight
                lineWidth = size.width
                lineHeight = size.height
            } else {
                lineWidth += size.width
                lineHeight = max(lineHeight, size.height)
            }

            totalWidth = max(totalWidth, lineWidth)
        }

        totalHeight += lineHeight

        return .init(width: totalWidth, height: totalHeight)
    }

    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        let sizes = subviews.map { $0.sizeThatFits(.unspecified) }

        var lineX = bounds.minX
        var lineY = bounds.minY
        var lineHeight: CGFloat = 0

        for index in subviews.indices {
            if lineX + sizes[index].width > (proposal.width ?? 0) {
                lineY += lineHeight
                lineHeight = 0
                lineX = bounds.minX
            }

            subviews[index].place(
                at: .init(
                    x: lineX + sizes[index].width / 2,
                    y: lineY + sizes[index].height / 2
                ),
                anchor: .center,
                proposal: ProposedViewSize(sizes[index])
            )

            lineHeight = max(lineHeight, sizes[index].height)
            lineX += sizes[index].width
        }
    }
}

相关问题