button - 为什么将 View 放在 Button 中会导致 LazyVGrid 严重滞后(错误?)?

标签 button scroll swiftui lazyvgrid

这是我的代码。没有按钮,但使用 onTapGesture,滚动非常流畅。伟大的!但是如果我将 Text() View 放在按钮中,那么延迟真的非常糟糕,甚至有点悬......

这是简化的代码。在我的实际项目中,我有一个名为 GridCell 的 View ,它本质上是一个带有字符串的彩色框。但是,如果我将该 View 放在按钮中(而不是在 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)
        }
    }

最佳答案

这看起来像是 SwiftUI 的限制。我遇到了同样的问题,并且找到了解决方法。我尝试使用时间分析器调查根本问题是什么,但我的调查最终发现似乎是 SwiftUI 中的缓存问题。 HVGrid.lengthAndSpacing 使用了 40% 的计算时间来访问缓存。根据其名称,我认为 VGrid 在内部使用它来计算每行大小,但由于某种原因,它不能很好地与按钮配合使用。

enter image description here

我尝试在叠加层中使用该按钮。这样,单个“单元格”的大小是根据 View 计算的,然后按钮从 View 中获取其大小。看来有效。

所以代码将如下所示:

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
            }
    }
}

关于button - 为什么将 View 放在 Button 中会导致 LazyVGrid 严重滞后(错误?)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63241221/

相关文章:

javascript - 根据滚动事件添加和删除类

ios - 使用页面 Controller 自动移动 ScrollView

ios - 自定义弹出窗口显示时的 SwiftUI 导航栏外观和功能

SwiftUI 不会更新第二个 NavigationLink 目的地

javascript - 检测可滚动 DIV 是否到达底部

ios - SwiftUI 自定义图像修改器

iphone - 为什么这会导致内存泄漏

android - 如何使用 color.xml 文件中的颜色资源动态应用按钮背景颜色

Android:如何使按钮导致 ListView 项目详细信息(在不同的 Activity 中)(主/详细流程)

html - 为什么我不能使用 CSS 来移动按钮?