siteline / swiftui-introspect

Introspect underlying UIKit/AppKit components from SwiftUI
MIT License
5.58k stars 344 forks source link

TabBarController does not honor tabBarItem.imageInsets #198

Closed DevboiDesigns closed 1 year ago

DevboiDesigns commented 1 year ago

This is an example of something I am working on. The imageInsets are not seemingly doing anything. Is there something I am missing?

struct ContentView: View {
    var body: some View {
        TabView {
            TestView(label: "One")
                .tabItem {
                    Image(systemName: "globe")
                }

            TestView(label: "Two")
                .tabItem {
                    Image(systemName: "globe")
                }

            TestView(label: "Three")
                .tabItem {
                    Image(systemName: "globe")
                }

            TestView(label: "Four")
                .tabItem {
                    Image(systemName: "globe")
                }
        }
        .accentColor(.white)
        .introspectTabBarController { tabBar in
            tabBar.tabBarItem.imageInsets = UIEdgeInsets(top: 20, left: 20, bottom: -20, right: 20)
            tabBar.tabBar.backgroundColor = UIColor(Color.gray)
        }
    }
}

struct TestView: View {
    let label: String
    var body: some View {
        Text(label)
            .foregroundColor(.black)
    }
}

My goal is to center the tab bar images in the tab bar

davdroman commented 1 year ago

@DevboiDesigns here's how to do it:

struct ContentView: View {
    var body: some View {
        TabView {
            TestView(label: "One")
                .tabItem {
                    Image(uiImage: UIImage(systemName: "globe")!.imageWithoutBaseline())
                }

            TestView(label: "Two")
                .tabItem {
                    Image(uiImage: UIImage(systemName: "globe")!.imageWithoutBaseline())
                }

            TestView(label: "Three")
                .tabItem {
                    Image(uiImage: UIImage(systemName: "globe")!.imageWithoutBaseline())
                }

            TestView(label: "Four")
                .tabItem {
                    Image(uiImage: UIImage(systemName: "globe")!.imageWithoutBaseline())
                }
        }
        .accentColor(.white)
        .introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { tabBarController in
            for controller in tabBarController.viewControllers ?? [] {
                controller.tabBarItem.imageInsets = UIEdgeInsets(top: 10, left: 0, bottom: -10, right: 0)
            }
            tabBarController.tabBar.backgroundColor = UIColor.gray
        }
    }
}

struct TestView: View {
    let label: String
    var body: some View {
        Text(label)
            .foregroundColor(.black)
    }
}

Explanation

SF Symbols have a default baseline offset, so if you're using SF Symbols you need to get the raw image without a baseline offset instead, and the only way to accomplish it is by bridging via UIImage.

Also, when setting imageInsets you need to set it for each specific tab's view controller, not the parent UITabBarController.

Closing.

DevboiDesigns commented 1 year ago

Thank you very much!