Search code examples
swiftuiswiftui-tabview

Tabview not switching tabs properly


I have a tabview (page style) that I am using to create an automatic slideshow. Each slide is not assigned to the currentIndex for some odd reason. Neither does the timer work or manually switching tabs with the default dot controls given with tabview.

If i set the tag to selectedIndex the tabview will default to the first slide. No errors to the console. Any help is greatly appreciated!

struct HomeView: View {
    @EnvironmentObject private var hvm: HomeViewModel
    
    @State private var selectedFilter: String = "Popular"
    @State private var selectedMedia: MediaModelResult? = nil
    @State private var showDetailView: Bool = false
    @State private var currentIndex: Int = 0
    @State var isFilterSelected: Bool = true
    
    @Namespace var animation
    
    private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
    
    var body: some View {
        NavigationView {
            ZStack {
                Color.theme.background.ignoresSafeArea()
                VStack {
                    header
                    VStack(alignment: .leading, spacing: 15) {
                        Text("Upcoming Movies")
                            .foregroundColor(Color.theme.secondaryAccent)
                            .font(.subheadline)
                            .padding(.leading, 15)
                        TabView(selection: $currentIndex) {
                            ForEach(hvm.upcomingFilms) { film in
                                MediaImageView(mediaPath: film, poster: false)
                                    .scaledToFill()
                                    .tag(film)
                            }
                        }
                        .tabViewStyle(PageTabViewStyle())
                        .clipShape(RoundedRectangle(cornerRadius: 5))
                        .padding(.horizontal, 15)
                        .frame(width: UIScreen.main.bounds.width, height: 180)
                        .onReceive(timer, perform: { _ in
                            withAnimation(.default) {
                                currentIndex = currentIndex < hvm.upcomingFilms.count ? currentIndex + 1 : 0
                            }
                        })
                    }
                    scrollViewContent
                }
            }
            .preferredColorScheme(.dark)
            .navigationBarHidden(true)
        }
    }
}
struct MediaImageView: View {
    @StateObject var mivm: MediaImageViewModel
    
    var poster: Bool
    
    init(mediaPath: MediaModelResult, poster: Bool) {
        self.poster = poster
        _mivm = StateObject(wrappedValue: MediaImageViewModel(mediaPath: mediaPath))
    }
    
    var body: some View {
        if poster {
            ZStack {
                if let image = mivm.poster {
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFit()
                } else if mivm.isLoading {
                    ProgressView()
                }
            }
        } else {
            ZStack {
                if let image = mivm.backdrop {
                    Image(uiImage: image)
                        .resizable()
                } else if mivm.isLoading {
                    ProgressView()
                }
            }
        }
    }
}
class HomeViewModel: ObservableObject {
    @Published var tabBarImageNames = ["house", "rectangle.stack", "clock.arrow.circlepath", "magnifyingglass"]
    @Published var filterTitles = ["Popular Now", "Top Rated", "New"]
    @Published var popularFilms: [MediaModelResult] = []
    @Published var topRatedFilms: [MediaModelResult] = []
    @Published var upcomingFilms: [MediaModelResult] = []
    @Published var popularTV: [MediaModelResult] = []
    @Published var topRatedTV: [MediaModelResult] = []
    
    private let dataService = MediaDataService()
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        addSubscribers()
    }
    
    func addSubscribers() {
        dataService.$popularFilms
            .sink { [weak self] (returnedFilms) in
                self?.popularFilms = returnedFilms
            }
            .store(in: &cancellables)
        dataService.$topRatedFilms
            .sink { [weak self] (returnedFilms) in
                self?.topRatedFilms = returnedFilms
            }
            .store(in: &cancellables)
        dataService.$upcomingFilms
            .sink { [weak self] (returnedFilms) in
                self?.upcomingFilms = returnedFilms
            }
            .store(in: &cancellables)
        dataService.$popularTV
            .sink { [weak self] (returnedFilms) in
                self?.popularTV = returnedFilms
            }
            .store(in: &cancellables)
        dataService.$topRatedTV
            .sink { [weak self] (returnedFilms) in
                self?.topRatedTV = returnedFilms
            }
            .store(in: &cancellables)
    }
}

Solution

  • Solution:

    TabView(selection: $currentIndex) {
        ForEach(0..<hvm.upcomingFilms.count) { film in
           MediaImageView(mediaPath: hvm.upcomingFilms[film], poster: false)
               .scaledToFill()
        }
    }