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

如何设置环境值,让CustomPresentationDetent读取外部参数?

问题:如何给CustomPresentationDetent传入外部参数并读取正确环境值

我想实现一个CustomPresentationDetent,它的高度依赖外部传入的值,比如高度为maxDetentValue减去指定的x值,代码框架如下:

struct MyDetent: CustomPresentationDetent {
    static func height(in context: Context) -> CGFloat? {
        context.maxDetentValue - x
    }
}

但CustomPresentationDetent.height(in:)是静态方法,无法编写带参数的初始化器,使用时只能传入元类型(.custom(MyDetent.self)而非.custom(MyDetent(x: 100))),因此考虑通过环境传递值。

官方文档指出height(in:)的context环境来自sheet展示的位置,但我尝试在多个位置添加.environment,height(in:)始终只能读到默认值0,以下是最小复现代码:

struct ContentView: View {
    var body: some View {
        SheetPresenter()
            .environment(\.myValue, 1)
    }
}

struct SheetPresenter: View {
    @State private var shown = false
    
    var body: some View {
        Button("Show Sheet") {
            shown = true
        }
        .environment(\.myValue, 2)
        .sheet(isPresented: $shown) {
            Text("Sheet")
                .environment(\.myValue, 3)
                .presentationDetents([.custom(MyDetent.self)])
                .environment(\.myValue, 4)
        }
        .environment(\.myValue, 5)
    }
}

struct MyEnvKey: EnvironmentKey {
    static let defaultValue: Int = 0
}

extension EnvironmentValues {
    var myValue: Int {
        get { self[MyEnvKey.self] }
        set { self[MyEnvKey.self] = newValue }
    }
}

struct MyDetent: CustomPresentationDetent {
    static func height(in context: Context) -> CGFloat? {
        print(context.myValue)
        return 100
    }
}

在iOS 17.4模拟器中,print(context.myValue)始终输出0。


解决方案

核心问题

普通的.environment modifier只能影响视图本身及其子视图,无法触及sheet的presentation环境上下文。CustomPresentationDetent.Context读取的是专门的presentation环境,需要用presentationEnvironment modifier来配置。

正确实现方式

使用.presentationEnvironment(\.myValue, value: 目标值)传递环境值,这个modifier专门用于修改sheet、popover等presentation组件的环境,能被CustomPresentationDetent.Context正确读取。

修改后的SheetPresenter代码:

struct SheetPresenter: View {
    @State private var shown = false
    
    var body: some View {
        Button("Show Sheet") {
            shown = true
        }
        .sheet(isPresented: $shown) {
            Text("Sheet")
                .presentationDetents([.custom(MyDetent.self)])
        }
        // 关键:用presentationEnvironment传递值给detent的context
        .presentationEnvironment(\.myValue, 5)
    }
}

此时MyDetent的height(in:)方法就能正确读取到5。

动态参数优化

如果需要动态调整传入的x值,可结合@State或@Binding实现:

struct SheetPresenter: View {
    @State private var shown = false
    @State private var offset: CGFloat = 100 // 可动态调整的偏移值
    
    var body: some View {
        Button("Show Sheet") {
            shown = true
        }
        .sheet(isPresented: $shown) {
            Text("Sheet")
                .presentationDetents([.custom(MyDetent.self)])
        }
        .presentationEnvironment(\.myValue, Int(offset))
        
        // 添加滑块动态修改偏移值
        Slider(value: $offset, in: 0...200)
            .padding()
    }
}

原理说明

presentationEnvironment是iOS 16+引入的modifier,专门用于配置presentation组件的环境参数,这些参数会被注入到CustomPresentationDetent.Context中,而普通.environment无法触达这个层级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 07:34:57