SwiftUI自定义拖拽底部视图:避免拖拽时调用content()方法
解决自定义底部弹窗拖拽时content()频繁调用的问题
问题根源
拖拽过程中DragGesture的updating闭包会实时更新dragOffset,触发整个视图的body重计算,而content()方法在body中被调用,导致每次重绘都会执行content(),出现频繁打印的情况。我们需要让内容视图仅在offsetViewState变化时才重建,而非每次拖拽都刷新。
解决方案
1. 用@ViewBuilder重构content方法,避免AnyView类型擦除
AnyView会丢失视图的类型信息,导致SwiftUI无法复用已有视图,每次都会重新创建。改用@ViewBuilder返回明确的视图类型,让SwiftUI能跟踪视图身份,仅在状态变化时切换视图:
@ViewBuilder private func content(offsetViewState: OffsetViewState) -> some View { print("ONLY PRINTED WHEN offsetViewState CHANGES") switch offsetViewState { case .searchState, .zoneListState, .shortZoneListState, .default: viewModel.createSearchZonesView() case .zoneInfoState, .shortZoneInfoState: viewModel.createZoneDetailsView(baseFlowModel: baseFlowModel) } }
2. 用EquatableView包装内容视图(可选)
如果createSearchZonesView和createZoneDetailsView返回的视图遵循Equatable,可以用EquatableView强制SwiftUI仅在视图数据变化时更新:
@ViewBuilder private func content(offsetViewState: OffsetViewState) -> some View { switch offsetViewState { case .searchState, .zoneListState, .shortZoneListState, .default: EquatableView(content: viewModel.createSearchZonesView()) case .zoneInfoState, .shortZoneInfoState: EquatableView(content: viewModel.createZoneDetailsView(baseFlowModel: baseFlowModel)) } }
注:需要确保视图的依赖数据(如viewModel中的相关状态)正确实现Equatable,否则无法生效。
3. 提取独立子视图,简化body复杂度
将不同状态的内容拆分为独立子视图,让SwiftUI更高效地管理视图生命周期,仅在子视图的依赖状态变化时更新:
// 定义独立子视图 private struct SearchZonesContentView: View { let viewModel: YourViewModelType var body: some View { viewModel.createSearchZonesView() } } private struct ZoneDetailsContentView: View { let viewModel: YourViewModelType let baseFlowModel: BaseFlowModelType var body: some View { viewModel.createZoneDetailsView(baseFlowModel: baseFlowModel) } } // 重构content方法 @ViewBuilder private func content(offsetViewState: OffsetViewState) -> some View { switch offsetViewState { case .searchState, .zoneListState, .shortZoneListState, .default: SearchZonesContentView(viewModel: viewModel) case .zoneInfoState, .shortZoneInfoState: ZoneDetailsContentView(viewModel: viewModel, baseFlowModel: baseFlowModel) } }
额外注意
确保dragOffset是@State变量,仅用于控制视图的偏移位置,不要让内容视图依赖这个变量。这样拖拽时只会更新视图的位置,不会触发内容视图的重建。
内容的提问来源于stack exchange,提问作者Gullit
相关产品推荐
相关产品推荐

