关于 UINavigationController 返回时,UITabBar 的 UITabBarButton 出现错位的问题

释放双眼,带上耳机,听听看~!

这个问题是苹果系统的问题,只要 UITabBar 是磨砂的,并且 push viewController 时 hidesBottomBarWhenPushed = YES 则手势返回的时候就会触发。

目前网上大部分的解决方法是在 AppDelegate 的 -application:didFinishLaunchingWithOptions: 方法里面对全局 TabBar 的 translucent 属性设置为 NO:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[UITabBar appearance] setTranslucent:NO];
    return YES;
}

虽然这方法的确奏效,但不知道为什么个所以然(估计都是复制粘贴的吧),而且这样设置之后 TabBar 就变得没有高斯模糊的效果了,所以这种做法是不靠谱的。

幸好搜到了这个问题的讨论链接,里面的ChenYilong大神解释道:

  • 这个问题是 iOS 12.1 Beta 2 的问题,只要 UITabBar 是磨砂的,并且 push viewController 时 hidesBottomBarWhenPushed = YES 则手势返回的时候就会触发。
  • 出现这个现象的直接原因是 tabBar 内的按钮 UITabBarButton 被设置了错误的 frame,frame.size 变为 (0, 0) 导致的。

并且给出了完美的解决方案:
写个 UITabBar 的分类,利用 runtime 进行判定

#import "UITabBar+JPExtensionn.h"
#import <objc/runtime.h>

@implementation UITabBar (JPExtensionn)

CG_INLINE BOOL
OverrideImplementation(Class targetClass, SEL targetSelector, id (^implementationBlock)(Class originClass, SEL originCMD, IMP originIMP)) {
    Method originMethod = class_getInstanceMethod(targetClass, targetSelector);
    if (!originMethod) {
        return NO;
    }
    IMP originIMP = method_getImplementation(originMethod);
    method_setImplementation(originMethod, imp_implementationWithBlock(implementationBlock(targetClass, targetSelector, originIMP)));
    return YES;
}

+ (void)load {
    /**
     * 参考:https://github.com/ChenYilong/CYLTabBarController/issues/312
     * 这个问题是 iOS 12.1 Beta 2 的问题,只要 UITabBar 是磨砂的,并且 push viewController 时 hidesBottomBarWhenPushed = YES 则手势返回的时候就会触发。
     * 出现这个现象的直接原因是 tabBar 内的按钮 UITabBarButton 被设置了错误的 frame,frame.size 变为 (0, 0) 导致的。如果12.1正式版Apple修复了这个bug可以移除调这段代码(来源于QMUIKit的处理方式)
     */
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (@available(iOS 12.1, *)) {
            OverrideImplementation(NSClassFromString(@"UITabBarButton"), @selector(setFrame:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP originIMP) {
                return ^(UIView *selfObject, CGRect firstArgv) {
                    
                    if ([selfObject isKindOfClass:originClass]) {
                        // 如果发现即将要设置一个 size 为空的 frame,则屏蔽掉本次设置
                        if (!CGRectIsEmpty(selfObject.frame) && CGRectIsEmpty(firstArgv)) {
                            return;
                        }
                    }
                    
                    // call super
                    void (*originSelectorIMP)(id, SEL, CGRect);
                    originSelectorIMP = (void (*)(id, SEL, CGRect))originIMP;
                    originSelectorIMP(selfObject, originCMD, firstArgv);
                };
            });
        }
    });
}

@end

看来是苹果系统的Bug呢!然而最新的手机版本还是会有该问题

ChenYilong大神说这是 iOS 12.1 Beta 2 的问题,听说现在已经修复了?但在 iOS 12.3.1 的正式版中,我自定义了一个pop动画,并且在里面用到了 tabBar ,却发现依然会有该问题…

pop回来时:

图标跟标题位置都错乱了

使用分类后:

图标跟标题位置正常了

所以,这个问题苹果还没有完全解决。

人已赞赏
iOS文章

iOS UIView常用的setNeedsDisplay和setNeedsLayout

2019-10-20 7:37:33

iOS文章

WKWebView系列--点击按钮无反应

2019-10-21 11:54:13

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索