问题
兼容性测试发现 iOS 13.3的iPhone 8 Plus上,一个TabBar页面底部BarItem文案变成省略号
![](https://img.haomeiwen.com/i1859439/5bc397cbb781eac7.png)
影响范围
设备类型 | 结果 |
---|---|
iOS >= 13.4的iPhone 8 Plus | 正常 |
iOS 13.0~13.3的刘海屏iPhone | 异常省略号 |
iOS 13.0~13.3的其他非刘海屏iPhone | 异常省略号 |
iOS < 13.0的iPhone 8 Plus | 正常 |
问题排查
iOS 13开始,UITabBar样式设置用standardAppearance,并且iOS 15又新增了scrollEdgeAppearance。所以一般写如下兼容性代码:
- (void)setUpTabBarAppearance {
UIViewController *codeVC = [[UIViewController alloc] init];
codeVC.tabBarItem.title = @"扫码1";
[self addChildViewController:codeVC];
UIViewController *ticketVC2 = [[UIViewController alloc] init];
ticketVC2.tabBarItem.title = @"扫码2";
[self addChildViewController:ticketVC2];
……………………
UIColor *selectedColor = kSelectedColor;
NSDictionary *textAttNormal = @{ NSForegroundColorAttributeName : [UIColor whiteColor],
NSFontAttributeName : [UIFont systemFontOfSize:18]};
NSDictionary *textAttSelected = @{ NSForegroundColorAttributeName : selectedColor,
NSFontAttributeName : [UIFont boldSystemFontOfSize:18]};
if (@available(iOS 13.0, *)) {
UITabBarAppearance * tabBarAppearance = [UITabBarAppearance new];
UITabBarItemAppearance *barItemAppearance= [[UITabBarItemAppearance alloc] initWithStyle:UITabBarItemAppearanceStyleInline];
barItemAppearance.normal.titleTextAttributes = textAttNormal;
barItemAppearance.selected.titleTextAttributes = textAttSelected;
tabBarAppearance.stackedLayoutAppearance = barItemAppearance;
tabBarAppearance.stackedLayoutAppearance = barItemAppearance;
self.tabBar.standardAppearance = tabBarAppearance;
if (@available(iOS 15.0, *)) {
self.tabBar.scrollEdgeAppearance = tabBarAppearance;
}
}
else {
// 问题出在这里
[self.viewControllers enumerateObjectsUsingBlock:^(__kindof UIViewController * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj.tabBarItem setTitleTextAttributes:textAttNormal forState:UIControlStateNormal];
[obj.tabBarItem setTitleTextAttributes:textAttSelected forState:UIControlStateSelected];
}];
}
}
查看UILabel尺寸
用Xcode自带的Debug View Hierarchy查看界面元素,确定TabBarItem的文案是UILabel,内容、样式都是上面设置的。对比正常、异常的情况,发现异常时UILabel的尺寸不同
![](https://img.haomeiwen.com/i1859439/ec6b04cfcf5ecc6b.png)
打印UILabel
在viewDidLayoutSubviews中、viewDidAppear中打印UILabel
// 不使用UITabBarController.selectedIndex, if the selected view controller is currently the More navigation controller, this property contains the value NSNotFound.
NSUInteger index = [self.tabBar nvm_selectedIndex];
UIView *tabBarView = [self.tabBar nvm_tabBarButtonAtIndex:index];
for (UILabel *obj in tabBarView.subviews) {
if ([obj isKindOfClass:[UILabel class]]) {
NSLog(@"== Label %@ : %@", obj.text, obj.font);
}
}
发现viewDidLayoutSubviews时,文字已生效,但字号未生效。
== Label 扫码1 : <UICTFont: 0x139eaaca0> font-family: ".SFUI-Medium"; font-weight: normal; font-style: normal; font-size: 10.00pt
而viewDidAppear时,文字、字号才设置上,但字号并未生效。此时调用sizeToFit可触发生效。同时注意到UICTFont属性的实例对象变了。
== Label 扫码1 : <UICTFont: 0x139f67740> font-family: ".SFUI-Semibold"; font-weight: bold; font-style: normal; font-size: 18.00pt
至此,明确问题原因在文字属性未生效。
返回去看上面代码:title设置都会执行,而字号设置,>= iOS 13、 < iOS 13的设备会执行不同逻辑,推测@available(iOS 13.0, *) 块中的代码导致titleTextAttributes未生效问题。
看起来是iOS 13.0~13.3上,standardAppearance会延迟生效?
尝试1
@available(iOS 13.0, *)改为@available(iOS 13.4, *)
titleTextAttributes部分生效,省略号问题解决,文字大小展示正确,但未选中状态颜色不符合预期
尝试2
看代码的else代码块,在 < iOS 13.0时,用UIBarItem setTitleTextAttributes设置样式,查看此方法:
/* You may specify the font, text color, and shadow properties for the title in the text attributes dictionary, using the keys found in NSAttributedString.h.
*/
- (void)setTitleTextAttributes:(nullable NSDictionary<NSAttributedStringKey,id> *)attributes forState:(UIControlState)state API_AVAILABLE(ios(5.0)) UI_APPEARANCE_SELECTOR;
注意到setTitleTextAttributes并未废弃,可以在任何版本上调用。所以先统一设置UIBarItem的setTitleTextAttributes,再针对iOS 13.0以上设置standardAppearance,尝试后问题解决。
解决方案
最终解决方案,先继续设置未废弃的旧方法,再根据iOS设置新方法。此种方案,作为日后新接口适配的策略执行下去。
附上正确代码:
- (void)setUpTabBarAppearance {
UIViewController *codeVC = [[UIViewController alloc] init];
codeVC.tabBarItem.title = @"扫码1";
[self addChildViewController:codeVC];
UIViewController *ticketVC2 = [[UIViewController alloc] init];
ticketVC2.tabBarItem.title = @"扫码2";
[self addChildViewController:ticketVC2];
……………………
UIColor *selectedColor = kSelectedColor;
NSDictionary *textAttNormal = @{ NSForegroundColorAttributeName : [UIColor whiteColor],
NSFontAttributeName : [UIFont systemFontOfSize:18]};
NSDictionary *textAttSelected = @{ NSForegroundColorAttributeName : selectedColor,
NSFontAttributeName : [UIFont boldSystemFontOfSize:18]};
// 在iOS 13.3上,UITabBarAppearance在首次appear时不生效,包括viewDidLayoutSubviews结束时,而iOS 13.4开始无此问题
// 因此无论iOS版本,都设置老方法,解决兼容性问题
[self.viewControllers enumerateObjectsUsingBlock:^(__kindof UIViewController * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj.tabBarItem setTitleTextAttributes:textAttNormal forState:UIControlStateNormal];
[obj.tabBarItem setTitleTextAttributes:textAttSelected forState:UIControlStateSelected];
}];
if (@available(iOS 13.0, *)) {
UITabBarAppearance * tabBarAppearance = [UITabBarAppearance new];
UITabBarItemAppearance *barItemAppearance= [[UITabBarItemAppearance alloc] initWithStyle:UITabBarItemAppearanceStyleInline];
barItemAppearance.normal.titleTextAttributes = textAttNormal;
barItemAppearance.selected.titleTextAttributes = textAttSelected;
tabBarAppearance.stackedLayoutAppearance = barItemAppearance;
tabBarAppearance.stackedLayoutAppearance = barItemAppearance;
self.tabBar.standardAppearance = tabBarAppearance;
if (@available(iOS 15.0, *)) {
self.tabBar.scrollEdgeAppearance = tabBarAppearance;
}
}
}
网友评论