Skip to content

☁️ SwiftUI 实战项目:天气应用

本项目演示如何用 SwiftUI 构建一个简易的天气应用,涵盖网络请求、JSON 解析、数据绑定和动态界面更新。

🎯 项目目标

  • 通过城市名称查询天气
  • 显示温度、天气状况和图标
  • 使用 @State 和异步网络请求更新 UI
  • 展示基础错误处理和加载状态

🧱 数据模型

定义天气数据模型:

swift
struct WeatherResponse: Codable {
    let name: String
    let main: Main
    let weather: [Weather]

    struct Main: Codable {
        let temp: Double
    }
    struct Weather: Codable {
        let description: String
        let icon: String
    }
}

🧠 状态管理

swift
@State private var cityName: String = ""
@State private var weather: WeatherResponse?
@State private var isLoading = false
@State private var errorMessage: String?

🔎 查询天气函数

使用 OpenWeatherMap API(需注册获取 API Key):

swift
func fetchWeather() {
    guard !cityName.isEmpty else { return }
    isLoading = true
    errorMessage = nil

    let apiKey = "你的API_KEY"
    let urlString = "https://api.openweathermap.org/data/2.5/weather?q=\\(cityName)&appid=\\(apiKey)&units=metric&lang=zh_cn"
    guard let url = URL(string: urlString) else {
        errorMessage = "无效的URL"
        isLoading = false
        return
    }

    URLSession.shared.dataTask(with: url) { data, response, error in
        DispatchQueue.main.async {
            isLoading = false
            if let error = error {
                errorMessage = error.localizedDescription
                return
            }
            guard let data = data else {
                errorMessage = "未收到数据"
                return
            }
            do {
                let decoded = try JSONDecoder().decode(WeatherResponse.self, from: data)
                weather = decoded
            } catch {
                errorMessage = "解析失败"
            }
        }
    }.resume()
}

📱 主视图布局

swift
VStack(spacing: 20) {
    TextField("输入城市名称", text: $cityName)
        .textFieldStyle(.roundedBorder)
        .padding()

    Button("查询天气") {
        fetchWeather()
    }
    .disabled(cityName.isEmpty)

    if isLoading {
        ProgressView("加载中...")
    } else if let weather = weather {
        VStack(spacing: 10) {
            Text(weather.name)
                .font(.title)
                .bold()
            Text("\\(Int(weather.main.temp))℃")
                .font(.system(size: 50))
            Text(weather.weather.first?.description.capitalized ?? "")
                .font(.headline)

            if let icon = weather.weather.first?.icon {
                let iconUrl = "https://openweathermap.org/img/wn/\\(icon)@2x.png"
                AsyncImage(url: URL(string: iconUrl)) { image in
                    image.resizable()
                } placeholder: {
                    ProgressView()
                }
                .frame(width: 100, height: 100)
            }
        }
        .padding()
    } else if let error = errorMessage {
        Text(error)
            .foregroundColor(.red)
    }
    Spacer()
}
.padding()

✅ 总结

该项目帮助你熟悉: • SwiftUI 与异步网络请求结合 • 使用 Codable 解析 JSON 数据 • 动态界面更新与状态管理 • 处理加载状态和错误提示

你可以进一步扩展: • 支持多城市切换 • 展示未来几天天气预报 • 美化界面,添加动画效果 • 集成 CoreLocation 实现自动定位天气查询

让你的天气应用更加实用与美观!

Released under the MIT License.