I have an iOS app with UITabBarController
on a master screen, navigating to a detail screen hiding the UITabBarController
with setting hidesB
You can override - (UIEdgeInsets)safeAreaInsets
method for few iOS 12 subversions with this:
- (UIEdgeInsets)safeAreaInsets {
UIEdgeInsets insets = [super safeAreaInsets];
CGFloat h = CGRectGetHeight(self.frame);
if (insets.bottom >= h) {
insets.bottom = [self.window safeAreaInsets].bottom;
}
return insets;
}
Here's a solution that can handle rotation and tab bar items being added or removed:
class FixedTabBar: UITabBar {
var buttonFrames: [CGRect] = []
var size: CGSize = .zero
override func layoutSubviews() {
super.layoutSubviews()
if UIDevice.current.systemVersion >= "12.1" {
let buttons = subviews.filter {
String(describing: type(of: $0)).hasSuffix("Button")
}
if buttonFrames.count == buttons.count, size == bounds.size {
zip(buttons, buttonFrames).forEach { $0.0.frame = $0.1 }
} else {
buttonFrames = buttons.map { $0.frame }
size = bounds.size
}
}
}
}
I guess it's Apple's bug But you can try this as a hot fix: just create a class for your tabBar with following code:
import UIKit
class FixedTabBar: UITabBar {
var itemFrames = [CGRect]()
var tabBarItems = [UIView]()
override func layoutSubviews() {
super.layoutSubviews()
if itemFrames.isEmpty, let UITabBarButtonClass = NSClassFromString("UITabBarButton") as? NSObject.Type {
tabBarItems = subviews.filter({$0.isKind(of: UITabBarButtonClass)})
tabBarItems.forEach({itemFrames.append($0.frame)})
}
if !itemFrames.isEmpty, !tabBarItems.isEmpty, itemFrames.count == items?.count {
tabBarItems.enumerated().forEach({$0.element.frame = itemFrames[$0.offset]})
}
}
}
If you still want to keep your tab bar translucent you need to subclass from UITabBar
and override property safeAreaInsets
class MyTabBar: UITabBar {
private var safeInsets = UIEdgeInsets.zero
@available(iOS 11.0, *)
override var safeAreaInsets: UIEdgeInsets {
set {
if newValue != UIEdgeInsets.zero {
safeInsets = newValue
}
}
get {
return safeInsets
}
}
}
The idea is to not allow system to set zero
insets, so tab bar won't jump.
here is the swift code
extension UIApplication {
open override var next: UIResponder? {
// Called before applicationDidFinishLaunching
SwizzlingHelper.enableInjection()
return super.next
}
}
class SwizzlingHelper {
static func enableInjection() {
DispatchQueue.once(token: "com.SwizzlingInjection") {
//what to need inject
UITabbarButtonInjection.inject()
}
} more information https://github.com/tonySwiftDev/UITabbar-fixIOS12.1Bug
Apple has now fixed that in iOS 12.1.1