13

iOS 15 sets the TabView's appearance depending on the loaded view's scroll position. However, this doesn't seem to update between views switched in the tab bar. How can I fix this so that the appearance updates properly?

  1. Opening a tabbed view without scrolling content ("no-scrolling view") uses a transparent background for the tab bar.

  2. After navigating to a tabbed view with scrolling content ("scrolling view"), a translucent background is used.

  3. However, when coming back to the "no-scrolling view", the translucent background still remains instead of being replaced with a transparent background.

I did notice that the appearance updates properly when I open the Control Center or App Switcher and come back.

no-scrolling view transparent scrolling view translucent no-scrolling view translucent

Reproduction:

enum Tab {
    case scroll
    case noScroll
}

struct ContentView: View {
    @State var selection: Tab = .noScroll
    
    var body: some View {
        TabView(selection: $selection) {     
            Text("Should have a transparent tab bar")
                .tabItem{ Label("No-scroll", systemImage: "xmark.circle") }
                .tag(Tab.noScroll)
            
            ScrollView {
                VStack(spacing: 10) {
                    ForEach(0..<100) {_ in
                        Text("Should have a translucent tab bar")
                    }
                }
            }
            .tabItem { Label("Scroll", systemImage: "circle") }
            .tag(Tab.scroll)
        }
    }
}

yklcs
  • 306
  • 2
  • 6
  • Please provide a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) – Visal Rajapakse Sep 24 '21 at 04:53
  • @VisalRajapakse added repro, thanks – yklcs Sep 24 '21 at 05:00
  • 1
    Try to pre-set tab bar appearance forcefully according the needs, like in https://stackoverflow.com/a/63702533/12299030. – Asperi Sep 24 '21 at 05:10
  • @Asperi I still would like to update the appearance between transparent and translucent, but forcefully setting the appearance would prevent that. I'm looking to have the proper appearance, not a custom one. – yklcs Sep 24 '21 at 05:21
  • Have you fixed it ? – Jim Feb 10 '22 at 09:13

4 Answers4

13
.onAppear {
    if #available(iOS 15.0, *) {
        let appearance = UITabBarAppearance()
        UITabBar.appearance().scrollEdgeAppearance = appearance
    }
}
Eric Ampire
  • 289
  • 2
  • 6
5

it's pretty much the same logic as @cole 's answer but here is my solution:

.introspectTabBarController(customize: { controller in

            let appearance = controller.tabBar.standardAppearance
            appearance.configureWithDefaultBackground()
            appearance.backgroundColor = .red
            if #available(iOS 15.0, *) {
                controller.tabBar.scrollEdgeAppearance = appearance
            } else {
                controller.tabBar.standardAppearance = appearance
            }
        })

to use introspectTabBarController SwiftUI-Introspect

miletliyusuf
  • 982
  • 1
  • 10
  • 12
2

After update to XCode 13 & iOS 15 I also faced some TabView issues with bar background color and items text & icons color for different states. The way I fixed it:

if #available(iOS 15, *) {
   let tabBarAppearance = UITabBarAppearance()
   tabBarAppearance.backgroundColor = backgroundColor
   tabBarAppearance.stackedLayoutAppearance.selected.titleTextAttributes = [.foregroundColor: selectedItemTextColor]
   tabBarAppearance.stackedLayoutAppearance.normal.titleTextAttributes = [.foregroundColor: unselectedItemTextColor]
   tabBar.standardAppearance = tabBarAppearance
   tabBar.scrollEdgeAppearance = tabBarAppearance
} else {
   UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor: selectedItemTextColor], for: .selected)
   UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor: unselectedItemTextColor], for: .normal)
   tabBar.barTintColor = backgroundColor
 }
1

I had a similar issue here, solved by using this for iOS 15

@available(iOS 15.0, *)
@NSCopying open var scrollEdgeAppearance: UITabBarAppearance?

Describes the appearance attributes for the tabBar to use when an observable scroll view is scrolled to the bottom. If not set, standardAppearance will be used instead.

//@available(iOS 15.0, *)
//@NSCopying open var scrollEdgeAppearance: UITabBarAppearance?

let appearance: UITabBarAppearance = UITabBarAppearance()
init() {
    UITabBar.appearance().scrollEdgeAppearance = appearance
}
cole
  • 1,039
  • 1
  • 8
  • 35