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

SwiftUI中UserDefaults存储镜头焦距值不一致问题求助

SwiftUI中UserDefaults存储镜头焦距值不一致问题求助

大家好,我在SwiftUI里开发了一个计算相机视野的视图,用户可以通过滑块或步进器调整镜头焦距(lensFocalLength),需求是用户调整后的值能被保存,下次打开视图时自动加载上次的设置。我用了UserDefaults来实现持久化,但现在遇到了一个很头疼的问题:比如用户把焦距设为100mm,下次打开视图时显示的却是98、105这类接近但不准确的数值,完全不一致,试了好几次都是这样,找不到原因。

以下是我的完整代码,麻烦各位帮忙排查一下问题所在:

import SwiftUI
import Foundation

struct Calc2View: View {
    @State private var lensFocalLength: Double
    let sensorWidth = 36.0 // Full frame sensor width

    init() {
        _lensFocalLength = State(initialValue: UserDefaults.standard.double(forKey: "selectedLens") != 0 ? UserDefaults.standard.double(forKey: "selectedLens") : 50.0)
    }

    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    HStack{
                        Text("Camera input")
                            .font(.headline)
                            .fontWeight(.bold)
                        Spacer()
                    }
                    Divider()

                    VStack{
                        HStack {
                            Text("Lens")
                                .font(.headline)
                                .multilineTextAlignment(.leading)
                            Spacer()
                            Text("\(lensFocalLength, specifier: "%.0f") mm")
                            Spacer()
                            Stepper("", value: $lensFocalLength, in: 1...1000)
                        }
                        HStack {
                            Slider(value: $lensFocalLength, in: 10...1000, step: 1)
                                .accentColor(.blue)
                        }
                    }
                    .onChange(of: lensFocalLength) { newValue, _  in
                        UserDefaults.standard.set(newValue, forKey: "selectedLens")
                    }

                    if lensFocalLength > 0 {
                        let fov = 2 * atan(sensorWidth / (2 * lensFocalLength)) * (180 / .pi) // New formula
                        let humanFOV = 200.0
                        let fovealFOV = 120.0
                        let nikonSensorWidth = 23.6
                        let canonSensorWidth = 22.3
                        let microFourThirdsSensorWidth = 17.3
                        let nikonFOV = 2 * atan(nikonSensorWidth / (2 * lensFocalLength)) * (180 / .pi)
                        let canonFOV = 2 * atan(canonSensorWidth / (2 * lensFocalLength)) * (180 / .pi)
                        let microFourThirdsFOV = 2 * atan(microFourThirdsSensorWidth / (2 * lensFocalLength)) * (180 / .pi)
                        let nikonEquivalentFocalLength = lensFocalLength / 1.5
                        let canonEquivalentFocalLength = lensFocalLength / 1.6
                        let microFourThirdsEquivalentFocalLength = lensFocalLength / 2.0

                        VStack(alignment: .leading) {
                            Divider()
                            Color.clear.frame(height: 5)

                            VStack(alignment: .leading){
                                Text("Lens Field of View:")
                                    .font(.headline)
                                    .fontWeight(.bold)
                                HStack {
                                    Text("FullFrame")
                                    Spacer()
                                    Text("\(fov, specifier: "%.1f") degrees")
                                }
                                HStack {
                                    Text("APS-C")
                                    Spacer()
                                    Text("\(nikonFOV, specifier: "%.1f") degrees")
                                }
                                HStack {
                                    Text("APS-C Canon")
                                    Spacer()
                                    Text("\(canonFOV, specifier: "%.1f") degrees")
                                }
                                HStack {
                                    Text("Micro 4/3rd")
                                    Spacer()
                                    Text("\(microFourThirdsFOV, specifier: "%.1f") degrees")
                                }

                                Divider()
                                Color.clear.frame(height: 5)

                                Text("Equivalent lens:")
                                    .font(.headline)
                                    .fontWeight(.bold)
                                HStack {
                                    Text("Full Frame")
                                    Spacer()
                                    Text("\(lensFocalLength, specifier: "%.0f") mm")
                                }
                                HStack {
                                    Text("APS-C")
                                    Spacer()
                                    Text("\(nikonEquivalentFocalLength, specifier: "%.0f") mm")
                                }
                                HStack {
                                    Text("APS-C Canon")
                                    Spacer()
                                    Text("\(canonEquivalentFocalLength, specifier: "%.0f") mm")
                                }
                                HStack {
                                    Text("Micro 4/3rd")
                                    Spacer()
                                    Text("\(microFourThirdsEquivalentFocalLength, specifier: "%.0f") mm")
                                }

                                Divider()
                                Color.clear.frame(height: 5)

                                Text("Full Frame Field of View:")
                                    .font(.headline)
                                    .fontWeight(.bold)
                                Color.clear.frame(height: 5)
                            }
                        }

                        VStack {
                            ZStack {
                                FOVTriangle(fov: humanFOV)
                                    .fill(Color.green.opacity(0.5))
                                FOVTriangle(fov: fovealFOV)
                                    .fill(Color.blue.opacity(0.5))
                                FOVTriangle(fov: fov)
                                    .fill(Color.pink.opacity(1.0))
                            }
                            .frame(height: 200)
                            .frame(width: 200)

                            Image(systemName: "camera") // Add SF Symbol
                                .font(.largeTitle)

                            Spacer()

                            HStack{
                                Image(systemName: "square.fill")
                                    .foregroundColor(.green)
                                    .opacity(0.5)
                                    .font(.system(size: 20))
                                Text("FoV both eyes")
                                Spacer()

                                Image(systemName: "square.fill")
                                    .foregroundColor(.red)
                                    .opacity(1.0)
                                    .font(.system(size: 20))
                                Text("Lens")
                                Spacer()

                                HStack{
                                    Image(systemName: "square.fill")
                                        .foregroundColor(.blue)
                                        .opacity(0.5)
                                        .font(.system(size: 20))
                                    Text("Binocular")
                                }
                            }
                        }
                    } else {
                        Text("Please enter a valid focal length")
                    }
                }
                .navigationTitle("Field of View")
                .navigationBarTitleDisplayMode(.inline)
                .padding()
            }
        }
        .navigationViewStyle(.stack)
    }
}

struct FOVTriangle: Shape {
    var fov: Double

    func path(in rect: CGRect) -> Path {
        var path = Path()
        let radians = fov * (.pi / 180.0)
        let height = Double(rect.height) / 3.1
        let width = tan(radians / 2) * height / 3.1
        let startPoint = CGPoint(x: rect.midX, y: rect.maxY)
        let leftPoint = CGPoint(x: rect.midX - CGFloat(width), y: 0)
        let rightPoint = CGPoint(x: rect.midX + CGFloat(width), y: 0)

        path.move(to: startPoint)
        path.addLine(to: leftPoint)
        path.addLine(to: rightPoint)
        path.addLine(to: startPoint)

        return path
    }
}

#Preview {
    Calc2View()
}

试了好多次都没解决这个问题,实在没办法了,希望各位能帮我找出问题所在,谢谢大家!

备注:内容来源于stack exchange,提问作者Serge Benati

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 13:00:31