RDVTabBarController的一个布局bug

描述,当在tabBar 隐藏(push 了控制器的)的状态下,设置selectIndex 就会页面布局异常

解决办法:实现一个RootTabViewController的子类重写selectedIndex

 - (void)setSelectedIndex:(NSUInteger)selectedIndex{
//修正containView的frame 
     [self setTabBarHidden:NO animated:NO];
     [super setSelectedIndex:selectedIndex];
}

源码分析
  • setSelectedIndex 内部实现会根据contentView 的bounds修改selectedViewController 的frame

- (void)setSelectedIndex:(NSUInteger)selectedIndex {
    if (selectedIndex >= self.viewControllers.count) {
        return;
    }
    
    if ([self selectedViewController]) {
        [[self selectedViewController] willMoveToParentViewController:nil];
        [[[self selectedViewController] view] removeFromSuperview];
        [[self selectedViewController] removeFromParentViewController];
    }
    
    _selectedIndex = selectedIndex;
    [[self tabBar] setSelectedItem:[[self tabBar] items][selectedIndex]];
    
    [self setSelectedViewController:[[self viewControllers] objectAtIndex:selectedIndex]];
    [self addChildViewController:[self selectedViewController]];
/**这里是关键,如果contentView 的bounds 异常那么selectedViewController就会异常了**/
    [[[self selectedViewController] view] setFrame:[[self contentView] bounds]];
    [[self contentView] addSubview:[[self selectedViewController] view]];
    [[self selectedViewController] didMoveToParentViewController:self];
    
    [self setNeedsStatusBarAppearanceUpdate];
}
  • setTabBarHidden : animated: 内部会更新contentView 的frame
- (void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated {
    _tabBarHidden = hidden;
    
    __weak RDVTabBarController *weakSelf = self;
    
    void (^block)() = ^{
        CGSize viewSize = weakSelf.view.bounds.size;
        CGFloat tabBarStartingY = viewSize.height;
        CGFloat contentViewHeight = viewSize.height;
        CGFloat tabBarHeight = CGRectGetHeight([[weakSelf tabBar] frame]);
        
        if (!tabBarHeight) {
            tabBarHeight = 49;
        }
        
        if (!hidden) {
            tabBarStartingY = viewSize.height - tabBarHeight;
            if (![[weakSelf tabBar] isTranslucent]) {
                contentViewHeight -= ([[weakSelf tabBar] minimumContentHeight] ?: tabBarHeight);
            }
            [[weakSelf tabBar] setHidden:NO];
        }
        
        [[weakSelf tabBar] setFrame:CGRectMake(0, tabBarStartingY, viewSize.width, tabBarHeight)];
/**这里是关键**/
        [[weakSelf contentView] setFrame:CGRectMake(0, 0, viewSize.width, contentViewHeight)];
    };
    
    void (^completion)(BOOL) = ^(BOOL finished){
        if (hidden) {
            [[weakSelf tabBar] setHidden:YES];
        }
    };
    
    if (animated) {
        [UIView animateWithDuration:0.24 animations:block completion:completion];
    } else {
        block();
        completion(YES);
    }
}

场景说明: a是一个tab 下的根导航控制器 push 了 b ,此时tabBar 隐藏,现在点击b 上的按钮,通过set selectIndex 的方式跳转到 另外一个根控制器c ,问题发生了,因为在setSelected 方法在执行的时候,容器视图contentview 的高度是隐藏底部tabBar 的高度,可以简单理解成全屏高度,那么设置selectView 的frame 的时候就会高度不对,以为新的selectedView 是根控制器,根控制器显示的时候,tabBar 是需要显示的,frame 的高度应该是减去底部tabBar 的高度,但是此时的contentView 高度是全屏的高度,此时异常了

**声明,这里的前提是认识在根控制器显示的时候,tabBar 应该隐藏,如果你不是这么理解的,那么上面的讨论就没意义了

搭配隐藏显示tabBar 的代码如下:

@interface HqUINavigationController:UINavigationController
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController;
@end
@implementation HqUINavigationController

- (instancetype)initWithRootViewController:(UIViewController *)rootViewController{
    if (self = [super initWithRootViewController:rootViewController]) {
         rootViewController.navigationController.delegate = [HqNavigationDelegateHelper shareInstance];
    }
    return self;
}
@end


@interface HqNavigationDelegateHelper()
@end

@implementation HqNavigationDelegateHelper
+ (instancetype)shareInstance{
    static dispatch_once_t token;
    static HqNavigationDelegateHelper * obj = nil;
    dispatch_once(&token, ^{
        obj = [[HqNavigationDelegateHelper alloc] init];
    });
    return obj;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    if (navigationController.viewControllers.count > 1) {
        [viewController.rdv_tabBarController setTabBarHidden:YES animated:YES];
    }else
        [viewController.rdv_tabBarController setTabBarHidden:NO animated:YES];
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
 
}

@end


你可能感兴趣的:(RDVTabBarController的一个布局bug)