WeatherKit扩展switch匹配天气状态失效,始终返回默认值问题
问题:天气APP背景视频无法根据天气条件切换
我正在开发一款简易天气APP,希望根据不同天气状况(晴、雨、雪等)设置不同的背景视频。已实现视频在View中循环播放,但无法根据天气条件切换。视频存储在Bundle中,以字符串名称("deer"、"lake"、"snow")调用。
已实现的代码
WeatherCondition扩展
extension WeatherCondition { var videoBG : String { switch self { case .blizzard: return "snow" case .blowingDust: return "lake" case .blowingSnow: return "lake" case .breezy: return "lake" case .clear: return "deer" case .cloudy: return "lake" case .drizzle: return "lake" case .flurries: return "lake" case .foggy: return "lake" case .freezingDrizzle: return "lake" case .freezingRain: return "lake" case .frigid: return "lake" case .hail: return "lake" case .haze: return "lake" case .heavyRain: return "lake" case .heavySnow: return "lake" case .hot: return "lake" case .hurricane: return "lake" case .isolatedThunderstorms: return "lake" case .mostlyClear: return "deer" case .mostlyCloudy: return "lake" case .partlyCloudy: return "lake" case .rain: return "lake" case .scatteredThunderstorms: return "lake" case .sleet: return "lake" case .smoky: return "lake" case .snow: return "lake" case .strongStorms: return "lake" case .sunFlurries: return "lake" case .sunShowers: return "lake" case .thunderstorms: return "deer" case .tropicalStorm: return "lake" case .windy: return "lake" case .wintryMix: return "lake" @unknown default: return "deer" } } }
WeatherKitManager实现
@MainActor class WeatherKitManager: ObservableObject { @Published var weather: Weather? func getWeather() async { do { weather = try await Task.detached(priority: .userInitiated) { return try await WeatherService.shared.weather(for: .init(latitude: 42.34779, longitude: 13.39943)) // 示例坐标 }.value } catch { fatalError("\(error)") } } var videoAppBG: String { weather?.currentWeather.condition.videoBG ?? "snow" } }
View中的背景设置
var body: some View { NavigationView { ZStack { BgdFullScreenVideoView(videoName: weatherKitManager.videoAppBG) .zIndex(-10) VStack (alignment: .leading, spacing: 10) { Spacer() VStack(alignment: .leading) { Text("\(weatherKitManager.temp)") .foregroundColor(.white) .font(.system(size: 75)) .fontWeight(.black) .shadow(radius: 8) Text("L'Aquila") .foregroundColor(.white) .font(.system(size: 30)) .fontWeight(.medium) .shadow(radius: 8) } .padding(.bottom, 80) } .padding(.leading,25) .frame(maxWidth: .infinity, alignment: .leading) } .toolbar { ToolbarItem(placement: .navigationBarLeading) { ZStack { Image("logo") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 30, height: 30) .shadow(radius: 3) .zIndex(10) } .padding(.top,40) } } } .onAppear() { Task { await weatherKitManager.getWeather() } } .frame(maxWidth: .infinity, maxHeight: .infinity) .ignoresSafeArea() }
问题现象
无论实际天气如何,始终播放"snow"视频。使用相同方式获取温度、symbolName等属性均正常工作,说明weather对象是正常获取的,但videoAppBG始终返回默认值。
解决方案
核心问题是videoAppBG是普通计算属性,不会随着weather的更新自动触发视图刷新。虽然weather是@Published属性,但视图不会监听计算属性的变化,导致它一直停留在初始的默认值"snow"。
方案一:直接在View中访问目标属性(推荐)
修改View中的视频视图参数,跳过中间的videoAppBG属性,直接通过weather对象获取视频名称:
BgdFullScreenVideoView(videoName: weatherKitManager.weather?.currentWeather.condition.videoBG ?? "snow")
这样当weather更新时,视图会自动读取最新的condition.videoBG值,触发视频切换。
方案二:同步更新@Published属性(可选)
如果想保留videoAppBG属性,可以将其改为@Published,并在获取到天气后手动更新:
@MainActor class WeatherKitManager: ObservableObject { @Published var weather: Weather? @Published var videoAppBG: String = "snow" // 改为@Published func getWeather() async { do { weather = try await Task.detached(priority: .userInitiated) { return try await WeatherService.shared.weather(for: .init(latitude: 42.34779, longitude: 13.39943)) }.value // 获取天气后同步更新videoAppBG videoAppBG = weather?.currentWeather.condition.videoBG ?? "snow" } catch { fatalError("\(error)") } } }
此方案需要手动维护属性同步,不如方案一简洁。
内容的提问来源于stack exchange,提问作者helloimbrando
相关产品推荐
相关产品推荐

