Почему размещение представления в кнопке приводит к ужасному отставанию LazyVGrid (ошибка?)?
Вот мой код. Без кнопки, но с onTapGesture, прокрутка очень плавная. Большой! Но если я помещаю представление Text() в кнопку, то лаг действительно очень, очень плох, даже немного зависает...
Это упрощенный код. В моем реальном проекте у меня есть представление под названием GridCell, которое по сути представляет собой цветной прямоугольник со строкой внутри него. Но если я помещу это представление в кнопку (вместо использования кнопки в ForEach с GridCell в качестве содержимого / метки), задержка также будет. Стоит ли избегать кнопок в LazyVGrids или это какая-то ошибка?
import SwiftUI
let columnCount: Int = 11
let gridSpacing: CGFloat = 1
struct SimpleGridView: View {
@State private var selected: String? = nil
let data = (1...1000).map { "\($0)" }
let columns: [GridItem] = Array(repeating: .init(.flexible(), spacing: gridSpacing), count: columnCount)
let colCount: CGFloat = CGFloat(columnCount)
var body: some View {
GeometryReader { geo in
ScrollView (showsIndicators: false) {
LazyVGrid(columns: columns, spacing: gridSpacing) {
ForEach(data, id: \.self) { item in
// This code creates lag when scrolling
// Button(action: {
// selected = item
// }) {
// Text(item)
// }
/// This code is fine, apparently.
Text(item)
.onTapGesture(count: 1, perform: {
selected = item
})
}
}
.sheet(item: $selected) { item in // activated on selected item
DetailView(item: item)
}
.padding(.horizontal)
}
}
}
}
struct DetailView: View {
let item: String
var body: some View {
Text(item)
}
}
1 ответ
Это похоже на ограничение SwiftUI. У меня была такая же проблема, и я нашел обходной путь для нее. Я попытался выяснить с помощью профилировщика времени, в чем была основная проблема, но мое расследование закончилось тем, что выглядело как проблема с кэшированием в SwiftUI. 40% вычислительного времени было использовано
HVGrid.lengthAndSpacing
для доступа к кешу. Основываясь на его названии, я думаю, что он используется внутри VGrid для вычисления размера каждой строки, но по какой-то причине он плохо работает с кнопками.
Я пытался использовать кнопку в оверлее. Таким образом, размер одной «ячейки» рассчитывается на основе представления, а затем кнопка берет свой размер из представления. Кажется, это работает.
Таким образом, код будет выглядеть так:
ForEach(data, id: \.self) { item in
Text(item) // This is the UI of the cell.
.overlay {
Button {
print("Button pressed")
selected = item
} label: {
Color.clear
}
}
}