2 min read

SwiftUI - Weather Hourly Forecast example

Hourly Forecast SwiftUI Component Example
SwiftUI - Weather Hourly Forecast example

Let’s see how can we build this component of Apple’s weather app in SwiftUI.

First, what do we need to display within the view?

  • The headline of the forecast
  • Hours
  • Rain percentage
  • Weather State

Let’s define that in a data model:

struct HourlyForecastModel {
    let headline: String
    let forecasts: [HourForecast]
    static private var staticRandomHeadlines = [
        "Lower temperatures expected tomorrow, with a high of 16°.",
        "Higher temperatures expected today, with a high of 20°",
    static func makeRandom() -> HourlyForecastModel {
        let randomHourForecasts = (0...24).map { HourForecast.makeRandom(
            hour: Calendar.current.component(
                from: Calendar.current.date(
                    byAdding: .hour,
                    value: $0,
                    to: Date()
        return HourlyForecastModel(
            headline: self.staticRandomHeadlines.randomElement()!,
            forecasts: randomHourForecasts

struct HourForecast {
    let hour: Int
    let celsius: Int
    let weatherType: WeatherType
    static func makeRandom(hour: Int) -> HourForecast {
            hour: hour,
            celsius: Int.random(in: -10...20),
            weatherType: WeatherType.allCases.randomElement()!

extension HourForecast: Hashable { }

enum WeatherType {
    case sunny
    case cloud
    case rain
    case snow
    case hail
    case lightning
    var systemNameIcon: String {
        switch self {
        case .sunny:
            return "sun.min.fill"
        case .cloud:
            return "cloud.fill"
        case .rain:
            return "cloud.rain.fill"
        case .snow:
            return "cloud.sleet.fill"
        case .hail:
            return "cloud.hail.fill"
        case .lightning:
            return "cloud.bolt.fill"

extension WeatherType: CaseIterable { }

To help us with displaying, we’ve also added a few static random data generators.

Then let’s create a data service provider and a ViewModel to allow a view to display the data to a UI.

protocol ForecastProviding {
    func getHourlyForecastData() -> HourlyForecastModel

final class MockForecastProvider: ForecastProviding {
    func getHourlyForecastData() -> HourlyForecastModel {
        return .makeRandom()

final class ContentViewModel: ObservableObject {
    @Published var data: HourlyForecastModel
    private let forecastProvider: ForecastProviding
    init(forecastProvider: ForecastProviding = MockForecastProvider()) {
        self.forecastProvider = forecastProvider
        self.data = self.forecastProvider.getHourlyForecastData()

Now, our ContentViewModel receives a provider that allows data to be fetched, and then once the data is retrieved, we publish it.

Lastly, let’s create a view similar to the one of the official Apple weather app, which subscribes to the provided data.

struct ContentView: View {
    @StateObject private var viewModel = ContentViewModel()
    var body: some View {
    private var hourForecastView: some View {
        VStack(alignment: .leading) {

            ScrollView(.horizontal, showsIndicators: false) {
                LazyHStack(alignment: .top, spacing: 24) {
                    ForEach(viewModel.data.forecasts, id: \.self) { forecast in
                        VStack {
                            Image(systemName: forecast.weatherType.systemNameIcon)
                                .frame(height: 40)
        .frame(height: 200)
            LinearGradient(gradient: Gradient(colors: [.accentColor.opacity(0.8), .accentColor.opacity(0.6)]), startPoint: .leading, endPoint: .trailing)

Let’s see it in action.

Although, not exactly like the official Apple weather app hourly forecast component, it’s a start!

Now hopefully, you have a better idea of how to create a similar component for your app.

The full source code is available here.

Happy coding!