描述,当在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
网友评论