1

我在滚动视图中有一个小部件列表,每行有 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 很难自定义样式,例如删除分隔线,删除填充。

有没有办法解决这个问题?

求救!!

4

0 回答 0