1

Whenever I click on a tab on tabview, it opens a view. I wish to change the background color of that view. Doesn't matter what I do, it always stays white. Please look at the code and screenshot below:

Note: In the screenshot below, ignore positioning of the tab bar. In my actual app it shows at the bottom, but due to lot of code, I just created a sample app.

How can I set the background to gray and how can I remove the line/separator highlighted in the screenshot?

Code:

import SwiftUI
import Foundation

struct ContentView: View {
    static let sliderHandleHeight: CGFloat = 15.0
    static let radius: CGFloat = 16
    @State private var tabViewPanelMinHeight: CGFloat = 250.0
    @State private var tabViewPanelMaxHeight: CGFloat = 750.0
    @State private var tabViewPanelCurrentHeight: CGFloat = 250.0
    
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Image(systemName: "touchid").resizable().scaledToFit()
            }
            .onAppear {
                tabViewPanelMinHeight = geometry.size.height * 0.25
                tabViewPanelMaxHeight = geometry.size.height * 0.91
                tabViewPanelCurrentHeight = tabViewPanelMinHeight
            }
            .overlay(alignment: .bottom) {
                VStack {
                    RoundedRectangle(cornerRadius: 5.0)
                        .foregroundColor(.secondary)
                        .frame(width: 50, height: 7.0)
                        .frame(height: ContentView.sliderHandleHeight)
                        .padding(.top, 5.0)
                        .simultaneousGesture(tap)
                    BottomTabBarView()
                }
                .background(Color(red: 0.98, green: 0.98, blue: 0.98).opacity(0.94))
                .cornerRadius(ContentView.radius)
                .shadow(radius: 10)
                .frame(width: geometry.size.width, height: tabViewPanelCurrentHeight + ContentView.sliderHandleHeight, alignment: .bottom)
            }
        }
    }
    
    var tap: some Gesture {
        TapGesture(count: 1).onEnded {
            tabViewPanelCurrentHeight = ((tabViewPanelCurrentHeight == tabViewPanelMinHeight) ? tabViewPanelMaxHeight : tabViewPanelMinHeight)
        }
    }
}

enum Tab: String, CaseIterable {
    case none
    case profile
    case search
}

struct BottomTabBarView: View {
    @State var activeTab = Tab.search

    var body: some View {
        TabView(selection: $activeTab) {
            Group {
                Text("Profile")
                    .tabItem {
                        Label("Profile", systemImage: "square.text.square.fill")
                    }
                    .tag(Tab.profile)
                SearchExploreModalView()
                    .tabItem {
                        Label("Search", systemImage: "magnifyingglass")
                        Text("Search")
                    }
                    .tag(Tab.search)
            }
        }
        .background(Color(red: 0.98, green: 0.98, blue: 0.98).opacity(0.94))
        .shadow(color: .black.opacity(0.3), radius: 0, x: 0, y: -0.5)
        .onAppear {
            let appearance = UITabBarAppearance()
            UITabBar.appearance().scrollEdgeAppearance = appearance
        }
    }
}

struct SearchExploreModalView: View {
    var body: some View {
        VStack {
            Text("Hello World")
        }
        .background(Color.gray)
    }
}

Screenshot:

enter image description here

tech_human
  • 6,592
  • 16
  • 65
  • 107
  • "How can I get rid of this line?" Do you mean you want the background of the tab to continue beyond the "grabber"? – Sweeper Jul 11 '23 at 05:27
  • Background of the grabber and background of the tab view are of different colors. But I can try your idea and see if that changes anything. How can I continue background of the tab beyond the "grabber"? – tech_human Jul 11 '23 at 05:32

1 Answers1

1

To make the grey color the entire background of the tab, just allow the VStack containing the Text expand infinitely:

struct SearchExploreModalView: View {
    var body: some View {
        VStack {
            Text("Hello World")
        }
        // here:
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.gray)
    }
}

The "line" that you see is part of the shadow you added to TabView:

.shadow(color: .black.opacity(0.3), radius: 0, x: 0, y: -0.5)

Removing this line removes the line.

If you actually want the background of the tab to continue beyond the "grabber", use a ZStack instead of VStack:

ZStack(alignment: .top) {
    BottomTabBarView()

    RoundedRectangle(cornerRadius: 5.0)
        .foregroundColor(.secondary)
        .frame(width: 50, height: 7)
        .frame(height: ContentView.sliderHandleHeight)
        .padding(.top, 5.0)
        .simultaneousGesture(tap)
}
.background(Color(red: 0.98, green: 0.98, blue: 0.98).opacity(0.94))
.cornerRadius(ContentView.radius)
.shadow(radius: 10)
.frame(width: geometry.size.width, height: tabViewPanelCurrentHeight + ContentView.sliderHandleHeight, alignment: .bottom)

Output:

enter image description here

This might cause the "grabber" to overlap with some of the tabs' contents. To avoid this, you can add a Spacer with height ContentView.sliderHandleHeight at the start of each tab.

That said, are you trying to reinvent sheet?

.sheet(isPresented: .constant(true)) {
    BottomTabBarView()
        .presentationDetents([.medium, .large])
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Yes, this is exactly what I wanted. Didn't realize that the ".shadow" is adding the line. I have to implement this in iOS 15, hence cannot use presentationDetents and reinventing the wheel. Thank you so so much!!! – tech_human Jul 11 '23 at 05:47
  • 1
    @tech_human In that case, you can also try wrapping [`UISheetPresentationController`](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller) in a `UIViewControllerRepresentable`. – Sweeper Jul 11 '23 at 06:02
  • That's right, but in this case I want to give the look that the sheet is behind tab bar. I did some research and also tried out, but sheet always covers the main view i.e. tab bar as well. From what I read, API to hide the sheet behind was available from iOS 16. So even if I use UISheetPresentationController, I may not achieve what I want. – tech_human Jul 11 '23 at 13:17