再会。我正在尝试根据元素的大小发布元素的动态放置。在空项目中工作,但有时不显示整个文本。在一个工作项目中,最多显示 2-3 个元素。也许我走错了路。请告诉我看哪个方向。我想使用 UICollectionView 和 UIViewRepresentable 但无法弄清楚到底如何。网上有例子,但有一个通用的网格,列的宽度相同。我只需要从左到右逐行铺设不同宽度的元素。
struct CustomFlexBoxView<Content> : View where Content: View {
let alignment: Alignment
let spacing: CGFloat
let content: [Content]
@State private var sizeBody: CGSize? = nil
@State private var sizeItems: [Int:CGSize] = [:]
init(alignment: Alignment = .center, spacing: CGFloat = 0, content: [Content]) {
self.spacing = spacing
self.alignment = alignment
self.content = content
}
var body: some View {
GeometryReader { (geo) in
if let sizeBody = self.sizeBody {
self.contentView(sizeBody: sizeBody)
}
else {
self.contentFirstView
.onAppear {
self.sizeBody = geo.frame(in: .global).size
}
}
}
}
private var contentFirstView: some View {
let items = self.content
return VStack(spacing: 0) {
ForEach(0 ..< items.count) { (index) in
HStack(spacing: 0) {
items[index]
}
.background(
GeometryReader { (geo) in
Color.clear.onAppear {
self.sizeItems[index] = geo.frame(in: .global).size
}
}
)
}
}
}
private func contentView(sizeBody: CGSize) -> some View {
let items = self.content
var rowWidth: CGFloat = 0
var rowItems: [Content] = []
var rows: [AnyView] = []
for index in 0 ..< items.count {
if let size = self.sizeItems[index] {
if rowWidth + size.width + self.spacing <= sizeBody.width {
let addSpacing = (rowItems.isEmpty ? 0 : self.spacing)
rowItems.append(items[index])
rowWidth = rowWidth + size.width + addSpacing
}
else {
if rowItems.isEmpty == false {
rows.append(
AnyView(
self.createRow(items: rowItems)
)
)
rowWidth = 0
rowItems = []
}
rowWidth = size.width
rowItems = [ items[index] ]
}
}
else {
if rowItems.isEmpty == false {
rows.append(
AnyView(
self.createRow(items: rowItems)
)
)
rowWidth = 0
rowItems = []
}
rows.append(AnyView(items[index]))
}
}
if rowItems.isEmpty == false {
rows.append(
AnyView(
self.createRow(items: rowItems)
)
)
rowWidth = 0
rowItems = []
}
return AnyView (
VStack(alignment: self.alignment.horizontal, spacing: self.spacing) {
ForEach(0 ..< rows.count) { ind in
rows[ind]
}
}
)
}
private func createRow(items: [Content]) -> some View {
HStack(alignment: self.alignment.vertical, spacing: self.spacing) { [items] in
ForEach(0 ..< items.count) { ind in
items[ind]
}
}
}
}
在一个空项目上一切正常,在工作项目中显示前 2-3 个元素。:
struct ContentView: View {
@State var data: [Int] = [
113, 2, 2342343, 234, 234234234234324, 3,
45345435345345, 545, 34, 4, 345345345, 45345, 5, 5
]
var body: some View {
ScrollView {
CustomFlexBoxView(
alignment: .topLeading,
spacing: 10,
content: self.data.map { TestText(text: "\($0)") }
)
}
.padding()
}
}
struct TestText : View {
let text: String
@State private var color: Bool = false
var body: some View {
Text(self.text)
.lineLimit(1)
.fixedSize()
.background(self.color ? Color.orange : Color.gray)
.foregroundColor(self.color ? Color.green : Color.black)
.onTapGesture {
self.color.toggle()
}
}
}
但是,如果您添加更多元素,则由于某种原因,无法正确估计 CustomFlexBoxView 的总大小:
var body: some View {
ScrollView {
Rectangle()
.fill(Color.orange)
.frame(maxWidth: .infinity, minHeight: 100)
CustomFlexBoxView(
alignment: .topLeading,
spacing: 10,
content: self.data.map { TestText(text: "\($0)") }
)
Rectangle()
.fill(Color.orange)
.frame(maxWidth: .infinity, minHeight: 100)
}
.padding()
}