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

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) {}
}

关键说明

  1. 自定义带参初始化:将passedMood作为必填参数传入,外部创建视图时直接传值即可,比如:
    ScrollDetectView(passedMood: .happy)
    
  2. 回调的灵活性:onScrollingStarted和onScrollingFinished设置了默认空实现,外部可以选择传入自定义逻辑,也可以使用默认行为,比如:
    ScrollDetectView(passedMood: .sad) {
        print("滚动开始了")
    } onScrollingFinished: {
        print("滚动结束了")
    }
    
  3. 内部变量初始化:滚动检测相关的detector和publisher在同一个init里完成初始化,和外部传参完全不冲突,保证了内部逻辑的封装性。

内容的提问来源于stack exchange,提问作者Mark George

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 09:22:09