У меня проблемы с просмотром прокрутки и GeometryReader. Я хочу иметь список предметов под изображением. И каждый предмет должен иметь следующие ширину и высоту: ((width of the entire screen - leading padding - trailing padding) / 2)
. Я пробовал два подхода для своего варианта использования. Это структура кода моего первого стека:
Подход № 1
ScrollView
- VStack
- Image
- GeometryReader
- ForEach
- Text
Я использую считыватель геометрии, чтобы получить ширину VStack, поскольку он имеет отступы, а я не Я хочу иметь всю ширину прокрутки.
Но с GeometryReader в пользовательском интерфейсе отображается только последний элемент из ForEach l oop. А у GeometryReader только небольшая высота. См. Снимок экрана.
Код:
import SwiftUI
struct Item: Identifiable {
var id = UUID().uuidString
var value: String
}
struct ContentView: View {
func items() -> [Item] {
var items = [Item]()
for i in 0..<100 {
items.append(Item(value: "Item #\(i)"))
}
return items
}
var body: some View {
ScrollView {
VStack {
Image(systemName: "circle.fill")
.resizable()
.scaledToFill()
.frame(width: 150, height: 150)
.padding()
.foregroundColor(.green)
GeometryReader { geometry in
ForEach(self.items()) { item in
Text(item.value)
.frame(width: geometry.size.width / CGFloat(2), height: geometry.size.width / CGFloat(2))
.background(Color.red)
}
}
.background(Color.blue)
}
.frame(maxWidth: .infinity)
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Красный цвет - это элементы в ForEach l oop. Синий цвет для GeometryReader и зеленый только изображение.
Подход №2
ScrollView
-GeometryReader
- VStack
- Image
- ForEach
-Text
Тогда элементы в моем ForEach l oop отображаются правильно, но прокручивать больше нельзя.
Код
import SwiftUI
struct Item: Identifiable {
var id = UUID().uuidString
var value: String
}
struct ContentView: View {
func items() -> [Item] {
var items = [Item]()
for i in 0..<100 {
items.append(Item(value: "Item #\(i)"))
}
return items
}
var body: some View {
ScrollView {
GeometryReader { geometry in
VStack {
Image(systemName: "circle.fill")
.resizable()
.scaledToFill()
.frame(width: 150, height: 150)
.padding()
.foregroundColor(.green)
ForEach(self.items()) { item in
Text(item.value)
.frame(width: geometry.size.width / CGFloat(2), height: geometry.size.width / CGFloat(2))
.background(Color.red)
}
}
.frame(maxWidth: .infinity)
}
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Как заархивировать, чтобы пользовательский интерфейс отображался правильно. Я что-то здесь упускаю? Я был бы очень признателен за помощь.
Спасибо.
РЕДАКТИРОВАТЬ
Я нашел обходной путь, чтобы пользовательский интерфейс правильно отображался с рабочим scrollView, но мне это кажется довольно хакерским. Я использую PreferenceKey для этого обходного пути. Я использую geometryReader внутри scrollview с высотой 0. Только для получения ширины моего VStack. В разделе preferenceKeyChange я обновляю переменную состояния и использую ее для своего элемента, чтобы установить его ширину и высоту.
import SwiftUI
struct Item: Identifiable {
var id = UUID().uuidString
var value: String
}
struct ContentView: View {
@State var width: CGFloat = 0
func items() -> [Item] {
var items = [Item]()
for i in 0..<100 {
items.append(Item(value: "Item #\(i)"))
}
return items
}
struct WidthPreferenceKey: PreferenceKey {
typealias Value = [CGFloat]
static var defaultValue: [CGFloat] = [0]
static func reduce(value: inout [CGFloat], nextValue: () -> [CGFloat]) {
value.append(contentsOf: nextValue())
}
}
var body: some View {
ScrollView {
VStack(spacing: 0) {
Image(systemName: "circle.fill")
.resizable()
.scaledToFill()
.frame(width: 150, height: 150)
.padding()
.foregroundColor(.green)
GeometryReader { geometry in
VStack {
EmptyView()
}.preference(key: WidthPreferenceKey.self, value: [geometry.size.width])
}
.frame(height: 0)
ForEach(self.items()) { item in
Text(item.value)
.frame(width: self.width / CGFloat(2), height: self.width / CGFloat(2))
.background(Color.red)
}
}
.padding()
}
.onPreferenceChange(WidthPreferenceKey.self) { value in
self.width = value[0]
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Это единственный способ сделать это или есть более элегантный и простой способ сделать это?