我在滚动视图中有一个小部件列表,每行有 3 个元素。某些元素将通过 SwiftUI 文本计时器显示秒表。文本计时器将每秒增加 1。一开始一切都很好,但如果我滚动列表太快,文本计时器将被冻结,不再更新,除非再次滚动列表。
Bellow 录制是我在 iPhone 12 Pro Max 上的屏幕录制。第一次,从“Category 2”位置慢慢滚动到顶部,秒表正常刷新。第二次和第三次,快速滚动到顶部,秒表停止并且从不刷新。
这是我的代码:
import SwiftUI
extension Date {
func formatDate(_ format: String) -> String {
let formatter = DateFormatter()
formatter.dateFormat = format
return formatter.string(from: self)
}
func getZeroData() -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
var startDateStr = self.formatDate("yyyy-MM-dd")
startDateStr = "\(startDateStr) 00:00:00"
return dateFormatter.date(from: startDateStr) ?? Date()
}
}
struct SectionHeaderView: View {
let title: String
var body: some View {
HStack() {
Text(title)
.font(.system(size: 19.0))
.fontWeight(.bold)
Spacer()
}
.padding(.leading, 10.0)
.frame(height: 44.0)
}
}
struct CellView: View {
let date: Date
let categoryIndex: Int
let rowIndex: Int
init(date: Date, categoryIndex: Int, rowIndex: Int) {
self.date = date
self.categoryIndex = categoryIndex
self.rowIndex = rowIndex
//print("CellView init is \(self.categoryIndex)->\(self.rowIndex)")
}
var body: some View {
print("CellView show is \(self.categoryIndex)->\(self.rowIndex)")
// 1. cellview has a very complex layout, so I need to use GeometryReader to get size for inner complex component.
// 2. In order to show the problem conveniently, only the test code is shown here, but the problem in the video above can also be reproduced
return GeometryReader { geo in
VStack() {
Text("\(categoryIndex) -> \(rowIndex)")
if((self.categoryIndex==0 || self.categoryIndex==2) && self.rowIndex<=4) {
Text(date.getZeroData(), style: .timer)
Text(date.formatDate("HH:mm:ss"))
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.background(Color.gray.opacity(0.2))
}
}
}
struct ContentView: View {
let date: Date = Date()
let widgetGap: CGFloat = 10.0
let widgetWidth: CGFloat
let widgetHeight: CGFloat
let columns: [GridItem]
//let columns: [GridItem] = Array(repeating: .init(.fixed(UIScreen.main.bounds.width/3.0), spacing: 0), count: 3)
init() {
let col: Int = 3
widgetWidth = (UIScreen.main.bounds.width - widgetGap * CGFloat(col + 1))/CGFloat(col)
//let widgetSize = CGSize(width: 160, height: 160)
widgetHeight = widgetWidth
columns = Array(repeating: .init(.fixed(widgetWidth), spacing: widgetGap), count: col)
}
var body: some View {
print("ContentView show")
return ScrollView() {
ForEach(0 ..< 6, id: \.self) { categoryIndex in
Section(header: SectionHeaderView(title: "Category \(categoryIndex)") ){
LazyVGrid(columns: columns, spacing: widgetGap + 5.0) {
ForEach(0 ..< 13, id: \.self) { rowIndex in
// 1. cellview has a very complex layout, so I need to use compositingGroup before cornerRadius to get a high accuracy radius
CellView(date: date, categoryIndex: categoryIndex, rowIndex: rowIndex)
.frame(width: widgetWidth, height: widgetHeight, alignment: .center)
.compositingGroup()
.cornerRadius(10)
.shadow(color: .black.opacity(0.05), radius: 6)
}
}
}
}
}
}
}
我也尝试使用 List 来替换 Scrollview + Lazyvgrid。这种情况有所改善。但是 List 很难自定义样式,例如删除分隔线,删除填充。
有没有办法解决这个问题?
求救!!