現(xiàn)在我們使用的APP框架,大部分都是
UINavigationController + UITabBarController
的模式。如果使用的是默認(rèn)的UITabBar
磨砂效果,而且在pushViewController
時(shí),設(shè)置了hidesBottomBarWhenPushed
屬性為true
,則在iOS 12.1系統(tǒng),使用手勢返回的時(shí)候,就會觸發(fā)UITabBarButton
被設(shè)置frame.size
為 (0, 0)的錯(cuò)誤布局, 導(dǎo)致的tabBar
上的圖標(biāo)和文字偏移錯(cuò)位。
extension UINavigationController {
@objc open func ck_pushViewController(_ viewController: UIViewController, animated: Bool) {
viewController.hidesBottomBarWhenPushed = true
self.ck_pushViewController(viewController, animated: animated)
if self.viewControllers.count == 1 {
viewController.hidesBottomBarWhenPushed = false
}
}
}
方案一:修改tabBar
的isTranslucent
透明度(不推薦)或添加背景圖片
1、可以通過修改tabBar
的透明度達(dá)到我們想要的效果:
if #available(iOS 12.1, *) {
UITabBar.appearance().isTranslucent = false
} else {
UITabBar.appearance().isTranslucent = true
}
但是這個(gè)會引入其它的問題:
- (1)
tabBar
想保留原來的磨砂效果; - (2)會影響
tableView
的布局,底部間距多了tabBar的高度;
所以這種方式pass
。
2、可以統(tǒng)一給tabBar
添加背景圖片,則不會有這個(gè)問題。
方案二:使用runtime
過濾UITabBarButton
的frame
設(shè)置(推薦)
為了達(dá)到既不修改原先的設(shè)計(jì)又達(dá)到解決這個(gè)問題,我這邊通過交換UITabBarButton
的setFrame
方法,過濾一些錯(cuò)誤的大小設(shè)置,來達(dá)到我們的目的,這里提供了OC
和Swift
兩個(gè)版本的代碼,如下:
-
OC
版
添加
UIView
的分類,并在+load
方法中,交換UITabBarButton
的setFrame
方法,過濾錯(cuò)誤的大小
#import <UIKit/UIKit.h>
@interface UIView (CKTabBarItem)
@end
#import "UIView+CKTabBarItem.h"
#import <objc/runtime.h>
@implementation UIView (CKTabBarItem)
+ (void)load
{
if (@available(iOS 12.1, *)) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = NSClassFromString(@"UITabBarButton");
SEL originalSelector = @selector(setFrame:);
SEL swizzledSelector = @selector(ck_setFrame:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL isSuccess = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (isSuccess) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
}
- (void)ck_setFrame:(CGRect)frame
{
if (!CGRectIsEmpty(self.frame)) {
if (CGRectIsEmpty(frame)) {
return;
}
frame.size.height = MAX(frame.size.height, 48.0);
}
[self ck_setFrame: frame];
}
@end
-
Swift
版
Swift4 不支持dispatch_once,靜態(tài)變量默認(rèn)用dispatch_once初始化,可以替代dispatch_once的實(shí)現(xiàn)
import UIKit
extension UIView {
/// Swift4 不支持dispatch_once,靜態(tài)變量默認(rèn)用dispatch_once初始化,可以替代dispatch_once的實(shí)現(xiàn)
private static let swizzlingTabBarButtonFrame: Void = {
guard #available(iOS 12.1, *) else {
return
}
guard let cls = NSClassFromString("UITabBarButton") else {
return
}
let originalSelector = #selector(setter: UIView.frame)
let swizzledSelector = #selector(UIView.ck_setFrame)
guard let originalMethod = class_getInstanceMethod(cls, originalSelector) else {
return
}
guard let swizzledMethod = class_getInstanceMethod(cls, swizzledSelector) else {
return
}
let isSuccess = class_addMethod(cls,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod))
if (isSuccess) {
class_replaceMethod(cls,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}()
@objc func ck_setFrame(frame: CGRect) {
var newFrame: CGRect = frame
if !self.frame.isEmpty {
guard !newFrame.isEmpty else {
return
}
newFrame.size.height = newFrame.size.height > 48.0 ? newFrame.size.height : 48.0
}
self.ck_setFrame(frame: newFrame)
}
open class func swizzledTabBarButtonFrame() {
UIView.swizzlingTabBarButtonFrame
}
}
Swift
因?yàn)闆]有+load
方法,所以需要手動去觸發(fā),我這里直接放到UIApplicationDelegate
的代理方法中。
// MARK: - <UIApplicationDelegate>
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ...
// 處理iOS 12.1系統(tǒng)tabBar圖標(biāo)偏移錯(cuò)位問題
UIView.swizzledTabBarButtonFrame()
return true
}
如果有任何疑問,歡迎留言或私信交流。