Home > Mobile >  How would I set each instance of a class to a specific page for a TabView
How would I set each instance of a class to a specific page for a TabView

Time:07-01

I am trying to assign each weather location in my app a page in a tab view but am unsure on how to achieve this. I have a currentPage variable in my location view which should add 1 every time a weather location is shown on screen but instead it just keeps adding one throughout the entire foreach loop I have so a page number isn't actually assigned to a weather view. I was wondering if anyone knew how I could assign a page number to each location when iterating through my for each loop. My location view is shown below. The code I tried is at the bottom in the onAppear modifier in the if statement but it doesn't work like I said above and I am not sure if this is even the right approach for doing something like this. Any help would be great!

LocationView

'''

import SwiftUI

struct LocationView: View {
@ObservedObject var weatherVM: WeatherViewViewModel
@ObservedObject var multiLocationVM: MultiLocationViewModel
@State private var pageSelection = 1
@State var currentPage: Int = 0

var body: some View {
    ZStack {
        LinearGradient(colors: [Color("BackgroundColorSun"), Color("BackgroundColorSky")], startPoint: .topLeading, endPoint: UnitPoint(x: 0.5, y: 0.5)).ignoresSafeArea()
    
        if multiLocationVM.weatherVM.count == 0 {
            BlankLocationView(multiLocationVM: multiLocationVM)
        } else {
            TabView(selection: $pageSelection) {
                ForEach(multiLocationVM.weatherVM, id: \.self.city) { location in
                    VStack(spacing: 0) {
                        VStack(spacing: -10) {
                            ZStack(alignment: .center) {
                                Text("\(location.getWeatherIconFor(icon: location.weatherIcon))")
                                    //.innerShadow(Color(.red))
                                    .font(.custom("SF Pro Text", size: 64))
                                    .innerShadow()
                                    //.foregroundColor(.gray)
                                    .offset(x: -70, y: -35)

                                Text("\(location.getTempFor(temp: location.weather.current.temp))°")
                                    .font(.system(size: 96, weight: .semibold, design: .rounded))
                                    .tracking(-0.41)
                                    .shadow(color: .black.opacity(0.25), radius: 4, x: 0, y: 4)
                            }
                            .offset(x: 15)
                            Text(location.conditions)
                                .font(.custom("SF Pro Display", size: 24))
                        }
                        .padding(EdgeInsets(top: -8, leading: 0, bottom: -8, trailing: 0))


                        VStack(spacing: -20) {
                            HourlyWeatherView(weatherVM: location)

                            DailyWeatherView(weatherVM: location)
                        }

                        Spacer()

                    }
                    .onAppear() {
                        if location.city != weatherVM.city {
                            weatherVM.city = location.city
                            currentPage  = multiLocationVM.weatherVM.firstIndex(of: location)!
                            location.page = currentPage
                            
                            print("current \(currentPage)")
                            print("Location \(location.page)")
                        } else {
                            return
                        }
                    }
                    .tag(currentPage)
                }
            }
            .tabViewStyle(.page(indexDisplayMode: .automatic))
            .indexViewStyle(.page(backgroundDisplayMode: .interactive))
        }
    }
    .padding(.bottom, 70)
    .ignoresSafeArea()
}
}

struct LocationView_Previews: PreviewProvider {
static var previews: some View {
    LocationView(weatherVM: WeatherViewViewModel(city: "Phoenix"), multiLocationVM: MultiLocationViewModel())
}
}

'''

CodePudding user response:

IMHO you don't need the currentPage counter as TabView(selection: )is handling that for you. The selection, in your case pageSelection will update when the user swipes, or you can set it programmatically. You just have to provide a fitting .tag:

//  dummy test data
struct Weather {
    var city: String
    var icon: String
    var temp: Int
    var condition: String
}

let multiLocationVM = [
    Weather(city: "Vancouver", icon: "cloud", temp: 64, condition: " Mostly Cloudy"),
    Weather(city: "New York", icon: "cloud.sun", temp: 78, condition: " Mostly Sunny"),
    Weather(city: "Los Angeles", icon: "sun.max", temp: 91, condition: " Sunny"),
]

struct ContentView: View {
    
    @State private var pageSelection = "Vancouver" // default here
    @State var currentPage: Int = 0
    
    var body: some View {
        ZStack {
            LinearGradient(colors: [Color(.yellow), Color(.blue)], startPoint: .topLeading, endPoint: UnitPoint(x: 0.5, y: 0.5)).ignoresSafeArea()
            
            if multiLocationVM.count == 0 {
                // BlankLocationView(multiLocationVM: multiLocationVM)
            } else {
                TabView(selection: $pageSelection) {
                    ForEach(multiLocationVM, id: \.city) { location in
                        LocalWeather(location: location)
                            .tag(location.city) // set tab id here
                    }
                }
                .tabViewStyle(.page(indexDisplayMode: .automatic))
            }
        }
        .padding(.bottom, 70)
        .ignoresSafeArea()
    }
}


struct LocalWeather: View {
    
    let location: Weather
    
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            VStack(alignment: .center, spacing: -10) {
                ZStack(alignment: .center) {
                    Image(systemName: location.icon)
                        .font(.custom("SF Pro Text", size: 32))
                        .offset(x: -90, y: -35)
                    
                    Text("\(location.temp)")
                        .font(.system(size: 96, weight: .semibold, design: .rounded))
                        .tracking(-0.41)
                        .shadow(color: .black.opacity(0.25), radius: 4, x: 0, y: 4)
                }
                .offset(x: 15)
                Text(location.condition)
                    .font(.custom("SF Pro Display", size: 24))
            }
            .padding(EdgeInsets(top: -8, leading: 0, bottom: -8, trailing: 0))
            
            Spacer()
        }
    }
}

enter image description here

  • Related