1

I am learning TabView and have a requirement where my main/content view will display map and will have TabView at the bottom. Whenever any of the tab's on TabView is tapped, a custom modal sheet (with slider handle to adjust sizes... more like bottom sheet) will be opened. Whenever I slide the modal down completely or close the modal sheet, the selected tab on tabview should get de-selected i.e. no tabs on the TabView should be selected by default.

Is this achievable with SwiftUI TabView? I am noticing first tab is always selected by default. Or will I have to create a custom tab view to achieve this?

Code:

import SwiftUI
import Foundation

struct ContentView: View {
    
    var body: some View {
        VStack {
            SimpleDataView()
            BottomTabView()
        }
    }
}

struct SimpleDataView: View {    
    var body: some View {
        VStack {
            Text("Map will be displayed over here").background(Color.gray).frame(maxWidth: .infinity, maxHeight: .infinity)
            Spacer()
        }
        .background(Color.gray)
        .ignoresSafeArea()
    }
}

struct BottomTabView: View {
    @State var selection: Int = -4
    var body: some View {
        TabView(selection: $selection) {
            Group {
                /// Custom modal view with slider handle/bottom sheet will be displayed.
                Text("Home tab's view")
                    .tabItem {
                        Label("Home", systemImage: "house")
                    }
                    .tag(0)
                    .frame(height: 100.0)
                Text("Search tab's view")
                    .tabItem {
                        Label("Search", systemImage: "magnifyingglass")
                    }
                    .tag(1)
                    .frame(height: 100.0)
            }
        }.onAppear {
            UITabBar.appearance().backgroundColor = .lightGray
        }
    }
}

To keep the code short and simple, I am using Text() element in my BottomTabView struct for now, but it will be replaced with CustomModalSheet which when closed, so de-select the selected tab on tab view and no tabs should be selected by default.

tech_human
  • 6,592
  • 16
  • 65
  • 107
  • I don't think this is possible with the built-in `TabView`. Perhaps take a look at [my answer here](https://stackoverflow.com/a/76627243/5133585) for how to create your own tab view. – Sweeper Jul 08 '23 at 02:46
  • 1
    Yes, the default behavior of TabView is to have a selected tab when it first appears, You have to find another way i.e. @Sweeper suggested or any other way. But using Tabview it's not possible I believe. – B25Dec Jul 08 '23 at 02:58

1 Answers1

0

Use this custom tab bar, and onDismiss sheet, set nil to the selectedTab. You can modify code as per your needs

Custom TabBar Item:

struct TabBarItem: View {
let title: String
let imageName: String
let tag: Int
@Binding var selectedTab: Int?

var body: some View {
    
    Button {
        selectedTab = selectedTab == tag ? nil : tag
    } label: {
        VStack(spacing: 4) {
            Image(systemName: imageName)
            Text(title)
        }
        .foregroundColor(selectedTab == tag ? .blue : .gray)
    }
  }
}

TabBar

struct TabBar: View {
@Binding var selectedTab: Int?

var body: some View {
    HStack {
        Spacer()
        TabBarItem(title: "Home", imageName: "house", tag: 0, selectedTab: $selectedTab)
        Spacer()
        TabBarItem(title: "Search", imageName: "magnifyingglass", tag: 1, selectedTab: $selectedTab)
        Spacer()
    }
  }
}

TabBar Container

struct BottomTabView: View {

@Binding var selectedTab: Int?

var body: some View {
    
    TabBar(selectedTab: $selectedTab)
        .padding(10)
        .background(Color.gray.opacity(0.1))
    
    }
}

Usage

struct ContentView: View {
@State private var isModalVisible = false
@State private var selectedTab: Int? = nil

var body: some View {
    VStack {
        
        Spacer()

        Button {
            isModalVisible = true
        } label: {
            Text("Present sheet")
        }

        Spacer()
    }
    .safeAreaInset(edge: .bottom) {
        BottomTabView(selectedTab: $selectedTab)
    }
    .sheet(isPresented: $isModalVisible, onDismiss: {
        selectedTab = nil
    }) {
        // Present your custom modal sheet here
        CustomModalSheet()
    }
  }
}
Umer Khan
  • 193
  • 12
  • This works but I was the custom modal sheet to be behind the tab bar i.e. with this solution it covers the tab bar. – tech_human Aug 08 '23 at 00:25