如何解决SwiftUI如何基于获取的数据更改视图的背景颜色?
我正在SwiftUI上开发一个基本的天气应用程序,该应用程序可以根据天气状况动态更改颜色。一切工作正常,但是我无法将通过JSON解析的OpenWeatherMap图标数据发送到我的View。看来它没有将从另一个Swift文件发送的信息分配给我声明的变量。我对普通的Swift有一定的经验,但是SwiftUI的概念肯定是不熟悉的。
这是我下面的ContentView.swift。
import SwiftUI
struct ContentView: View {
@State private var selected = 0
@ObservedObject var weather = CurrentWeatherViewModel()
@State var city : String = ""
private var height : CGFloat = UIScreen.main.bounds.height
var body: some View {
VStack{
HStack{
TextField("Enter your city",text: $city){
self.weather.fetchmetric(self.city)
}.padding(.horizontal)
}
GeometryReader{ gr in
CurrentWeather(weather: self.weather.current,height: self.selected == 0 ? gr.size.height : (gr.size.height*0.75)).frame(width: 375.0,height: 770).modifier(currentViewModifier()).animation(.easeInOut(duration: 0.5))
}.edgesIgnoringSafeArea(.all)
}.frame(width: 375,height: 735,alignment: .center)
}
}
这是我的CurrentWeather.swift文件。 @State颜色变量是我需要更改的变量。
import SwiftUI
import UIKit
struct CurrentWeather: View {
// Added color themes for potential weather scenarios
let bgColors = [
"Clear":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.6544341662,green: 0.9271220419,blue: 0.9764705896,alpha: 1)),Color( #colorLiteral(red: 0.2392156869,green: 0.6745098233,blue: 0.9686274529,alpha: 1))]),startPoint: .top,endPoint: .bottom),"Sunny":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.9764705896,green: 0.850980401,blue: 0.5490196347,Color( #colorLiteral(red: 0.9529411793,green: 0.8685067713,blue: 0.1800223484,"Partly cloudy":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.5644291786,green: 0.6156922265,blue: 0.8125274491,Color( #colorLiteral(red: 0.3611070699,green: 0.3893437324,blue: 0.5149981027,"Cloudy":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.5088317674,green: 0.5486197199,blue: 0.7256778298,Color( #colorLiteral(red: 0.3843137255,green: 0.4117647059,blue: 0.5450980392,"Broken clouds":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.4714559888,green: 0.41813849,blue: 0.4877657043,Color( #colorLiteral(red: 0.3823538819,green: 0.3384427864,blue: 0.3941545051,"Mist":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.8536048541,green: 0.8154317929,blue: 0.6934956985,Color( #colorLiteral(red: 0.5,green: 0.3992742327,blue: 0.3267588525,"Patchy rain possible":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.422871705,green: 0.486337462,blue: 0.7241632297,Color(#colorLiteral(red: 0.3826735404,green: 0.4012053775,blue: 0.9529411793,"Patchy snow possible":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.8229460361,green: 0.8420813229,Color( #colorLiteral(red: 0.6424972056,green: 0.9015246284,"Patchy sleet possible":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.9764705896,green: 0.7979655136,blue: 0.9493740175,Color( #colorLiteral(red: 0.6843526756,green: 0.7806652456,"Patchy freezing drizzle possible":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.6207757569,green: 0.9686274529,blue: 0.9110963382,Color( #colorLiteral(red: 0.4745098054,green: 0.8392156959,"Thundery outbreaks possible":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.3647058904,green: 0.06666667014,Color( #colorLiteral(red: 0.1764705926,green: 0.01176470611,blue: 0.5607843399,"Blowing snow":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.1764705926,Color( #colorLiteral(red: 0.09019608051,green: 0,blue: 0.3019607961,"Thunderstorm":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.9551106616,green: 0.9764705896,blue: 0.9351792135,Color( #colorLiteral(red: 0.6891936611,green: 0.7095901305,"Fog":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.6324083141,green: 0.8039215803,blue: 0.7850640474,Color( #colorLiteral(red: 0.4545597353,green: 0.393878495,blue: 0.5369011739,"Freezing fog":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.8039215803,blue: 0.8039215803,"Patchy light drizzle":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.5892893535,green: 0.7170531098,"Light rain":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.2392156869,Color( #colorLiteral(red: 0.2854045624,green: 0.4267300284,blue: 0.6992385787,"Moderate rain":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.3437546921,green: 0.6157113381,blue: 0.7179171954,Color( #colorLiteral(red: 0.4118283819,green: 0.5814552154,blue: 0.6975531409,"Heavy rain":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.1764705926,green: 0.4980392158,blue: 0.7568627596,Color( #colorLiteral(red: 0.1596036421,blue: 0.5802268401,"Light freezing rain":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.7433765433,green: 0.9529411793,blue: 0.8886958889,Color( #colorLiteral(red: 0.4561494407,green: 0.6342332627,"Heavy rain at times":LinearGradient(gradient: Gradient(colors: [Color( #colorLiteral(red: 0.1764705926,"defaultStatus":LinearGradient(gradient: Gradient(colors: [Color(#colorLiteral(red: 0.9372549057,green: 0.3490196168,blue: 0.1921568662,Color(#colorLiteral(red: 0.9686274529,green: 0.78039217,blue: 0.3450980484,endPoint: .bottom)
]
var weather : Weather?
var height : CGFloat = 0
@State var color : String = "defaultStatus"
var body: some View {
NavigationView{
VStack(alignment: .center,spacing: 10) {
Image(weather?.weather.last?.icon ?? "01d")
.resizable()
.frame(width: 130,height: 130)
.aspectRatio(contentMode: .fit)
Text("Today in \(weather?.name ?? "Unknown")")
.font(.title)
.foregroundColor(.white)
.bold()
.padding()
HStack{
Text("\(weather?.main.temp ?? 0)°")
.foregroundColor(.white)
.fontWeight(.heavy)
.font(.system(size: 50))
}
Text("\(weather?.weather.last?.description ?? "Unknown")")
.foregroundColor(.white)
.font(.body)
}.frame(width: height,height: height)
.background(bgColors[color])
.navigationBarItems(trailing:
NavigationLink(destination: Settings()) {
Image(systemName: "gear").imageScale(.large).accentColor(.black)
})
}.onAppear {} // Code Execution at startup
}
}
struct currentViewModifier : ViewModifier{
private var radius : CGFloat = 20
private var xAxis : CGFloat = 20
private var yAxis : CGFloat = 20
func body(content: Content) -> some View {
content
.cornerRadius(radius)
.opacity(1.0)
}
}
这是我的WeatherModel.swift文件,其中有执行提取的功能和使代码运行的background()函数。
import Foundation
import Combine
final class CurrentWeatherViewModel : ObservableObject{
@Published var current : Weather?
init() {
DispatchQueue.main.async {
//if Settings().selected == 0{
self.fetchmetric()
//}
// else{
self.fetchimperial()
// }
}
}
}
// fetch functions for metric and imperial and set color at the home screen
extension CurrentWeatherViewModel {
func fetchmetric(_ city : String = "london"){
let icon = current?.weather.last?.icon
API.fetchCurrentmetricWeather(by: city) {
// Work In Progress
self.current = $0
CurrentWeather().color = self.backgroundColor(code: icon ?? "aaa")
}
}
func fetchimperial(_ city : String = "london"){
API.fetchCurrentimperialWeather(by: city) {
self.current = $0
}
}
func backgroundColor(code : String) -> String {
switch code {
case "01d":
return "Clear"
case "02d":
return "Partly cloudy"
case "02n":
return "Partly cloudy"
case "03d":
return "Cloudy"
case "03n":
return "Cloudy"
case "04d":
return "Broken clouds"
case "04n":
return "Broken clouds"
case "09d":
return "Moderate Rain"
case "09n":
return "Heavy rain"
case "10d":
return "Moderate Rain"
case "10n":
return "Heavy rain"
case "11d":
return "Thunderstorm"
case "11n":
return "Thunderstorm"
case "13d":
return "Snow"
case "13n":
return "Snow"
case "50d":
return "Mist"
case "50n":
return "Mist"
default:
return "defaultStatus"
}
}
}
我的问题是,我不知道它没有将图标数据发送到CurrentWeather颜色变量吗?我必须说我不熟悉@State变量并尝试学习SwiftUI。
赞赏代码上的所有输入内容。
解决方法
表达式
CurrentWeather().color = self.backgroundColor(code: icon ?? "aaa")
毫无意义,因为修改了本地创建的值(CurrentWeather()
创建了结构值)。
相反,您需要在视图模型中为颜色创建发布的属性并使用它,例如
final class CurrentWeatherViewModel : ObservableObject{
@Published var current : Weather?
@Publisehd var color: String = "aaa"
然后将其更新为
API.fetchCurrentmetricWeather(by: city) { weather in
// Work In Progress
DispatchQueue.main.async { // update published on main queue !!!
self.current = weather
self.color = self.backgroundColor(code: icon ?? "aaa")
}
}
然后在类似的视图中使用它
}.frame(width: height,height: height)
.background(bgColors[self.weather?.color ?? "defaultStatus"])
不需要本地视图@State var color
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。