Customise UITabBar height in Xcode11 / iOS13 or 13

2020-07-22 20:17发布

问题:

I used to use the following code to adjust the height of my tab bar. However after I upgrade to Xcode 11 and using swift 5, the UI doesn't appear correctly anymore.

class MyTabBarController: UITabBarController {

    private lazy var defaultTabBarHeight = { [unowned self] in
        return self.tabBar.frame.size.height
    }()

    let higherTabBarInset: CGFloat = 24
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        let newTabBarHeight = defaultTabBarHeight + higherTabBarInset
        var newFrame = tabBar.frame
        newFrame.size.height = newTabBarHeight
        newFrame.origin.y = view.frame.size.height - newTabBarHeight
        tabBar.items?.forEach({e in
            e.titlePositionAdjustment = UIOffset(horizontal: 0, vertical: -(higherTabBarInset / 2))
        })
    }
}

It is supposed to appear like this, with the height of tab bar being 72:

However using Xcode 11 it looks like this in iOS 12, the tab bar height goes back to the default 49:

and in iOS 13, it displays like in .inlineLayoutAppearance even if my app was set for portrait layout only and the target device is iPhone only. My customised font also goes back to the system default one, too. Like in iOS 12, the UITabBar height goes back to default 49:

I referred to this similar question but the solution doesn't work for me, and it doesn't look like a proper solution anyway.

Another thing I don't understand related to this is that, when I tried to set the UITabBarItem's appearance with the following code:

tabBar.items?.forEach({e in
    if #available(iOS 13.0, *) {
        let appearance = UITabBarItemAppearance()
        appearance.configureWithDefault(for: .stacked)
        e.standardAppearance = appearance
    }
})

I got an error saying that Cannot assign value of type 'UITabBarItemAppearance' to type 'UITabBarAppearance?. Then I found that even if the type of my iteration variable e is UITabBarItem, the type of its appearance is UITabBarAppearance?... I couldn't figure out a way to set my UITabBarItem's appearance either, which is really confusing...

Does anyone know if there is any reasonable reason for this, or it's a possible bug here? Thanks ahead for any answer.

回答1:

Setting different tab bar height seems to work for me when a new frame is set with viewDidLayoutSubviews() instead of viewWillLayoutSubviews()

As for setting text offset please try

if #available(iOS 13, *) {
   let appearance = self.tabBar.standardAppearance.copy()
   appearance.stackedLayoutAppearance.normal.titlePositionAdjustment = UIOffset(horizontal: 0, vertical: -4)
   tabBar.standardAppearance = appearance
}


回答2:

This is how I finally solve the tab bar height problem, however the position of title is still not solved, at the moment I have to use the icon image with text instead.

@IBDesignable class MyTabBar: UITabBar {

    let higherTabBarInset: CGFloat = 24

    lazy var isIphoneXOrHigher: Bool = {
        return UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height >= 2436
    }()

    lazy var TAB_BAR_HEIGHT: CGFloat = {
        // Return according to default tab bar height
        if GlobalData.isIphoneXOrHigher {
            return 83 + higherTabBarInset
        }
        else {
            return 49 + higherTabBarInset
        }
    }()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        if #available(iOS 13.0, *) {
            self.standardAppearance.compactInlineLayoutAppearance = UITabBarItemAppearance.init(style: .stacked)
            self.standardAppearance.inlineLayoutAppearance = UITabBarItemAppearance.init(style: .stacked)
            self.standardAppearance.stackedLayoutAppearance = UITabBarItemAppearance.init(style: .stacked)
            self.standardAppearance.stackedItemPositioning = .centered
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var size = super.sizeThatFits(size)
        size.height = TAB_BAR_HEIGHT
        return size
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        self.items?.forEach({ e in
            if #available(iOS 13.0, *) {
                e.standardAppearance = self.standardAppearance
            }
            else {
                e.titlePositionAdjustment = UIOffset(horizontal: 0, vertical: -(higherTabBarInset / 2))
            }
        })
    }
}