SwiftUI中如何同时实现部分变量初始化与外部变量传入?
SwiftUI视图同时实现自定义初始化与外部传参的方案
你完全可以同时实现这两个需求,核心是自定义带参数的初始化方法,把需要外部传入的变量作为init的参数,同时在同一个初始化流程里完成滚动检测相关变量的初始化。
修改后的完整代码示例
import SwiftUI import Combine // 假设你的moodPics枚举定义如下 enum moodPics: String { case happy, sad, calm } struct ScrollDetectView: View { // 滚动状态回调(可选择外部自定义或用默认实现) let onScrollingStarted: () -> Void let onScrollingFinished: () -> Void // 滚动检测核心变量(私有化,内部使用) private let detector: CurrentValueSubject<CGFloat, Never> private let publisher: AnyPublisher<CGFloat, Never> // 需要外部传入的业务变量 let passedMood: moodPics // 自定义初始化方法:同时接收外部参数+初始化内部变量 init(passedMood: moodPics, onScrollingStarted: @escaping () -> Void = {}, onScrollingFinished: @escaping () -> Void = {}) { // 初始化外部传入的变量 self.passedMood = passedMood self.onScrollingStarted = onScrollingStarted self.onScrollingFinished = onScrollingFinished // 初始化滚动检测相关的Combine组件 let detector = CurrentValueSubject<CGFloat, Never>(0) self.publisher = detector.debounce(for: .seconds(0.2), scheduler: DispatchQueue.main) .dropFirst() .eraseToAnyPublisher() self.detector = detector // 订阅publisher,触发滚动结束回调 _ = self.publisher.sink { _ in onScrollingFinished() } } var body: some View { ScrollView { VStack(spacing: 20) { Text("当前心情:\(passedMood.rawValue)") .font(.title) // 模拟滚动内容 ForEach(0..<20) { index in Text("滚动项 \(index)") .frame(maxWidth: .infinity) .padding() .background(Color.gray.opacity(0.1)) } } .padding() // 绑定滚动偏移到detector,触发滚动检测 .background( GeometryReader { proxy in Color.clear .preference(key: ScrollOffsetKey.self, value: proxy.frame(in: .named("scroll")).minY) } ) .onPreferenceChange(ScrollOffsetKey.self) { offset in detector.send(offset) onScrollingStarted() } } .coordinateSpace(name: "scroll") } } // 自定义PreferenceKey用于获取滚动偏移 private struct ScrollOffsetKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {} }
关键说明
- 自定义带参初始化:将
passedMood作为必填参数传入,外部创建视图时直接传值即可,比如:ScrollDetectView(passedMood: .happy) - 回调的灵活性:
onScrollingStarted和onScrollingFinished设置了默认空实现,外部可以选择传入自定义逻辑,也可以使用默认行为,比如:ScrollDetectView(passedMood: .sad) { print("滚动开始了") } onScrollingFinished: { print("滚动结束了") } - 内部变量初始化:滚动检测相关的
detector和publisher在同一个init里完成初始化,和外部传参完全不冲突,保证了内部逻辑的封装性。
内容的提问来源于stack exchange,提问作者Mark George
相关产品推荐
相关产品推荐

