tvOS 18升级后SwiftUI ScrollView严重卡顿问题求助
临时解决方案:tvOS 18 SwiftUI LazyVStack 滚动卡顿问题
针对tvOS 18升级后SwiftUI应用在LazyVStack滚动时的严重卡顿(关联_UIFocusRegionEvaluator焦点区域计算耗时),以下是几个可落地的临时修复方案:
1. 用UIKit UITableView替代SwiftUI LazyVStack
既然UIKit实现的相同界面无性能问题,可通过UIViewRepresentable封装UITableView绕过SwiftUI的焦点计算bug:
struct UIKitTableView: UIViewRepresentable { typealias UIViewType = UITableView func makeUIView(context: Context) -> UITableView { let tableView = UITableView() tableView.delegate = context.coordinator tableView.dataSource = context.coordinator tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") return tableView } func updateUIView(_ uiView: UITableView, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator() } class Coordinator: NSObject, UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 1000 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = "Item \(indexPath.row)" return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // 在这里处理原Button的点击逻辑 } } } // 应用中替换使用 @main struct MyApp: App { var body: some Scene { WindowGroup { UIKitTableView() } } }
2. 优化焦点区域计算逻辑
卡顿根源是系统对焦点区域的遮挡评估耗时,可尝试减少焦点计算的复杂度:
- 将多个元素封装到单个可焦点容器中,减少独立焦点目标的数量(需根据业务调整焦点交互逻辑)
- 自定义Button的焦点效果,避免系统默认的复杂区域计算:
struct OptimizedButton: View { let title: String let action: () -> Void var body: some View { Button(action: action) { Text(title) .padding() } .focusable() .focusEffect(.custom) { focused in Text(title) .padding() .background(focused ? Color.blue : Color.clear) .cornerRadius(8) } } } // 在LazyVStack中替换原Button使用 LazyVStack { ForEach(0..<1000) { nb in OptimizedButton(title: "Item \(nb)", action: {}) } }
3. 限制LazyVStack同时加载的元素数量
通过ScrollViewReader手动控制可见区域外的元素加载状态,减少系统需要计算的焦点区域数量:
struct ControlledLazyStack: View { @State private var visibleRange = 0..<20 var body: some View { ScrollView { ScrollViewReader { proxy in LazyVStack { ForEach(visibleRange) { nb in Button("Item \(nb)") {} .id(nb) } } .onChange(of: proxy.scrollViewContentOffset) { offset in // 根据滚动偏移计算并更新可见范围,示例逻辑需根据实际布局调整 let newStart = max(0, Int(offset.y / 50) - 10) visibleRange = newStart..<newStart+30 } } } } }
补充提示
- 对于不愿重置设备的用户,可建议其前往「设置 > 通用 > 存储」清理对应应用的缓存,部分场景下可缓解问题
- 务必向Apple反馈该bug,附上你的最小复现示例和Instruments追踪数据,推动官方修复进程
内容的提问来源于stack exchange,提问作者Jul
相关产品推荐
相关产品推荐

