Search code examples
swiftuiswiftui-tabview

SwiftUI Only hide dot indicator on the last screen of Tabview


I'm working on a project written in SwiftUI and I want to create an Onboarding screen which has 4 pages. Each page has a full-screen image introducing about app. I use Tabview and enable page indicators. I can see the dot indicator at bottom, but requirement is when user slide on the last page, the dot should be hidden.

Here is my code

var body: some View {
        VStack {
            TabView {
                Image("onboard_1")
                    .resizable()
                    .scaledToFill()
                    .ignoresSafeArea()
                Image("onboard_2")
                    .resizable()
                    .scaledToFill()
                    .ignoresSafeArea()
                Image("onboard_3")
                    .resizable()
                    .scaledToFill()
                    .ignoresSafeArea()
                Image("onboard_4")
                    .resizable()
                    .scaledToFill()
                    .ignoresSafeArea()
            }
            .tabViewStyle(.page(indexDisplayMode: .automatic))
            .frame(maxHeight: .infinity, alignment: .top)
            .padding(.top, 0)
            .background(.black)
        }
        .ignoresSafeArea()
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
    }

I read on Apple document, it said the dot will be hidden automatically when using no more page left but it seems not working as expected

.tabViewStyle(.page(indexDisplayMode: .automatic))

Here is Apple document

public struct PageTabViewStyle : TabViewStyle {

    /// A style for displaying the page index view
    public struct IndexDisplayMode : Sendable {

        /// Displays an index view when there are more than one page
        public static let automatic: PageTabViewStyle.IndexDisplayMode

        /// Always display an index view regardless of page count
        @available(watchOS 8.0, *)
        public static let always: PageTabViewStyle.IndexDisplayMode

        /// Never display an index view
        @available(watchOS 8.0, *)
        public static let never: PageTabViewStyle.IndexDisplayMode
    }

    /// Creates a new `PageTabViewStyle` with an index display mode
    public init(indexDisplayMode: PageTabViewStyle.IndexDisplayMode = .automatic)
}

Solution

  • Try this approach using TabView(selection: ...) with .tag() and hiding the desired last page dots, such as in this example code:

    struct ContentView: View {
        @State private var currentTab = 0  // <--- here
        
        var body: some View {
            VStack {
                TabView(selection: $currentTab) {  // <--- here
                    Image(systemName: "globe")
                        .resizable()
                        .scaledToFill()
                        .ignoresSafeArea()
                        .tag(0) // <--- here
                    
                    Image(systemName: "info")
                        .resizable()
                        .scaledToFill()
                        .ignoresSafeArea()
                        .tag(1) // <--- here
                    
                    Image(systemName: "circle")
                        .resizable()
                        .scaledToFill()
                        .ignoresSafeArea()
                        .tag(2) // <--- here
                    
                    Image(systemName: "tray")
                        .resizable()
                        .scaledToFill()
                        .ignoresSafeArea()
                        .tag(3) // <--- here
                    
                }
                .tabViewStyle(.page(indexDisplayMode: currentTab == 3 ? .never : .always)) // <--- here
                .frame(maxHeight: .infinity, alignment: .top)
                .padding(.top, 0)
                //  .background(.black)
            }
            .ignoresSafeArea()
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
        }
        
    }