
IOS
使用ScrollView包裹具有可变高度内容的LazyVStack时,可能会遇到卡顿或跳跃的问题。这是因为当LazyVStack中的内容高度发生变化时,ScrollView需要重新计算其内容的布局和尺寸,从而引起性能问题。为了解决这个问题,我们可以采取一些优化措施。
优化方案一:使用UITableView代替ScrollView和LazyVStackUITableView是IOS中专门用于展示大量数据的控件,它对于可变高度的内容具有更好的性能优化。我们可以将UITableView作为ScrollView的替代品,并使用UITableViewCell来展示可变高度的内容。UITableView会自动处理内容的布局和尺寸,从而减少卡顿和跳跃的问题。下面是一个示例代码,演示了如何使用UITableView替代ScrollView和LazyVStack:Swiftimport SwiftUIstruct ContentView: View { var body: some View { ScrollView { VStack { // 其他内容... // 使用UITableView替代ScrollView和LazyVStack UITableViewWrapper { ForEach(0..<10) { index in</p> UITableViewCellWrapper { Text("Row \(index)") .padding() } } } .frame(height: 500) // 设置UITableView的高度 .background(Color.gray) // 其他内容... } } }}struct UITableViewWrapper<Content: View>: UIViewRepresentable { let content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } func makeUIView(context: Context) -> UITableView { let tableView = UITableView() tableView.dataSource = context.coordinator tableView.delegate = context.coordinator tableView.separatorStyle = .none tableView.register(UITableViewCellWrapper<Content>.self, forCellReuseIdentifier: "Cell") return tableView } func updateUIView(_ uiView: UITableView, context: Context) { // 更新UITableView的数据源和委托 uiView.dataSource = context.coordinator uiView.delegate = context.coordinator uiView.reloadData() } func makeCoordinator() -> Coordinator { Coordinator(content: content) } class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate { let content: Content init(content: Content) { self.content = content } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 10 // 返回行数 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! UITableViewCellWrapper<Content> cell.setcontent(content) return cell } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { UITableView.automaticDimension // 自动计算行高 } }}struct UITableViewCellWrapper<Content: View>: UIViewRepresentable { let content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } func makeUIView(context: Context) -> UITableViewCell { let cell = UITableViewCell() let hostingController = UIHostingController(rootView: content) cell.contentView.addSubview(hostingController.view) hostingController.view.translatesAutoresizingMaskIntoConstrAInts = false hostingController.view.leadingAnchor.constrAInt(equalTo: cell.contentView.leadingAnchor).isActive = true hostingController.view.trAIlingAnchor.constrAInt(equalTo: cell.contentView.trAIlingAnchor).isActive = true hostingController.view.topAnchor.constrAInt(equalTo: cell.contentView.topAnchor).isActive = true hostingController.view.bottomAnchor.constrAInt(equalTo: cell.contentView.bottomAnchor).isActive = true return cell } func updateUIView(_ uiView: UITableViewCell, context: Context) { // 更新UITableViewCell的内容 let hostingController = uiView.contentView.subviews.first as! UIHostingController<Content> hostingController.rootView = content hostingController.view.invalidateIntrinsicContentSize() }}struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() }}在上面的代码中,我们首先在ScrollView中使用了UITableViewWrapper来展示可变高度的内容。UITableViewWrapper是一个UIViewRepresentable,它将UITableView封装成一个SwiftUI的View,以便能够在SwiftUI中使用。UITableViewWrapper利用UITableView的数据源和委托方法来实现内容的展示和布局。我们在UITableViewWrapper中创建了一个Coordinator来处理UITableView的数据源和委托,然后将内容作为UITableViewCellWrapper展示在每一行中。优化方案二:使用UITableView和动态高度的UITableViewCell如果你不想使用SwiftUI的ScrollView,你也可以在UIKit中直接使用UITableView,并自定义UITableViewCell的高度。这种方式也能有效解决可变高度内容导致的卡顿和跳跃问题。下面是一个示例代码,演示了如何使用UITableView和动态高度的UITableViewCell:Swiftimport UIKitclass ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { let tableView = UITableView() var cellHeights: [IndexPath: CGFloat] = [:] override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self tableView.delegate = self tableView.separatorStyle = .none tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "Cell") view.addSubview(tableView) tableView.translatesAutoresizingMaskIntoConstrAInts = false tableView.leadingAnchor.constrAInt(equalTo: view.leadingAnchor).isActive = true tableView.trAIlingAnchor.constrAInt(equalTo: view.trAIlingAnchor).isActive = true tableView.topAnchor.constrAInt(equalTo: view.topAnchor).isActive = true tableView.bottomAnchor.constrAInt(equalTo: view.bottomAnchor).isActive = true } // 设置UITableView的行数 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 10 } // 设置UITableViewCell的内容和高度 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomTableViewCell cell.setcontent("Row \(indexPath.row)") return cell } // 动态计算UITableViewCell的高度 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if let height = cellHeights[indexPath] { return height } else { let cell = CustomTableViewCell() cell.setcontent("Row \(indexPath.row)") let height = cell.systemLayoutSizeFitting(CGSize(width: tableView.frame.width, height: CGFloat.greatestFiniteMagnitude)).height cellHeights[indexPath] = height return height } }}class CustomTableViewCell: UITableViewCell { let label = UILabel() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) contentView.addSubview(label) label.translatesAutoresizingMaskIntoConstrAInts = false label.leadingAnchor.constrAInt(equalTo: contentView.leadingAnchor, constant: 16).isActive = true label.trAIlingAnchor.constrAInt(equalTo: contentView.trAIlingAnchor, constant: -16).isActive = true label.topAnchor.constrAInt(equalTo: contentView.topAnchor, constant: 8).isActive = true label.bottomAnchor.constrAInt(equalTo: contentView.bottomAnchor, constant: -8).isActive = true label.numberOfLines = 0 } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setcontent(_ text: String) { label.text = text }}在上面的代码中,我们使用了一个UIViewController来展示UITableView,并实现了UITableView的数据源和委托方法。我们自定义了一个CustomTableViewCell来展示可变高度的内容,并使用UILabel来展示文本。在UITableViewDelegate的heightForRowAt方法中,我们动态计算了UITableViewCell的高度,并将计算结果缓存到cellHeights字典中,以便下次使用。通过以上两种优化方案,我们可以有效解决ScrollView内LazyVStack中可变高度内容导致的卡顿和跳跃问题。根据具体需求选择合适的方案,可以提升用户体验并改善应用性能。Copyright © 2025 IZhiDa.com All Rights Reserved.
知答 版权所有 粤ICP备2023042255号