You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:43:13