Search code examples
iosswiftimageuitabbarshadow

Remove UITabBar line not working


I would like to remove the separator of UITabBar. I have set custom background image for UITabBar. With the following code the separator is above UITabBar image.

class myTabBarController: UITabBarController {

    override func viewDidLoad() {
                UITabBar.appearance().backgroundImage = UIImage(named: "secretTab.png")

}

enter image description here

I have added following code but it removed not only line but also custom image.(shadow)

    class myTabBarController: UITabBarController {

        override func viewDidLoad() {
            self.tabBar.clipsToBounds = true
            self.tabBarController?.tabBar.autoresizesSubviews = false
            UITabBar.appearance().backgroundImage = UIImage(named: "secretTab.png")
}

enter image description here


Solution

  • This certainly looks like a bug. Prior to iOS 10, it worked fine: set a .backgroundImage and then set UITabBar.appearance().shadowImage = nil (or empty image or transparent image).

    With iOS 10, however...

    IF your background image is taller than the tab bar, the "shadow image" gets placed at the top of the background image; is 0.5-pts tall, and it will be visible.

    IF your background image is NOT taller than the tab bar, the "shadow image" is no longer visible.

    And... if you compare the structures between iOS 9 and 10 via Debug Hierarchy, you can see the "shadow image" is a subview of a different view.

    So... you can get rid of it, but with caveats...

    A. use a background image shorter than the tab bar.

    B. clip to bounds (but then you lose the top of your background image).

    C. use a fully-transparent background... set both .backgroundImage and .shadowImage to nil or UIImage(). Of course, then you need to find some other way to display the image you want as the background of the tab bar.

    or... but not recommended...

    D. on viewDidAppear, step through the tabBar subviews, find the "shadow image", and hide it. This will work - but it could fail if / when Apple changes the structure of the tab bar (and, I suppose, is technically "non-documented", so...):

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    
        var b = false
        for v in tabBar.subviews {
            for sv in v.subviews {
                if sv.frame.size.height == 0.5 && sv is UIImageView {
                    // found it
                    b = true
                    sv.isHidden = true
                    break
                }
            }
            if b { break }
        }
    
    }