Closed rakuyoMo closed 4 years ago
当希望使用 Safe Area 时, 将 self.edgesForExtendedLayout
恢复成默认值,即 UIRectEdgeAll
。它们是冲突的。
当希望使用 Safe Area 时, 将
self.edgesForExtendedLayout
恢复成默认值,即UIRectEdgeAll
。它们是冲突的。
这样的话相当于不设置 isExtendedLayoutIncludesTopBar
吧,但是这样的话顶部导航栏的位置会有个黑条。
当希望使用 Safe Area 时, 将
self.edgesForExtendedLayout
恢复成默认值,即UIRectEdgeAll
。它们是冲突的。这样的话相当于不设置
isExtendedLayoutIncludesTopBar
吧,但是这样的话顶部导航栏的位置会有个黑条。
我去看下
可能是我翻译的问题... 我发现你的 demo 里,DemoViewController
push DemoViewController
的时候,开启 hbd_barHidden
,没有任何 edgesForExtendedLayout
的设置,导航栏的位置没有黑条....
但是为什么布局没有从顶部开始?没看到有基类呀。
ScrollView 的缘故
ScrollView 的缘故
soga,那看来黑边还是我的问题。我再研究一下。
这个翻译还是有点困难的...
经过我测试,当设置 self.hbd_barHidden = YES;
以及 self.edgesForExtendedLayout = UIRectEdgeAll;
时,SafeArea 能正常工作。
我提交了测试的代码
打开 Main.storyboard,将初始指针指向最上面的 Navigation Controller.
用于测试的两个 ViewController 分别是 EViewController 和 FViewController。
找到问题了,是我基类中关于 edgesForExtendedLayout
的判断出了问题。与本库无关。谢谢作者的耐心回复~
demo 中的这段代码是不是有些问题?
if (!(self.hbd_extendedLayoutIncludesTopBar || hasAlpha(self.hbd_barTintColor))) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
当我通过下面这种方法设置 barTintColor
:
UINavigationBar.appearance().barTintColor = UIColor(hex: 0x2a2a2a)
hbd_barTintColor
属性实际上是 nil
的,也就是控制器的 edgesForExtendedLayout
会被设置为 UIRectEdgeNone
。但是实际上我是有状态栏,并且不希望被这么设置的。
在下面的方法中,没有用 UINavigationBar.appearance().barTintColor
作为默认返回值,而且也不能用它作为默认返回值...
- (UIColor *)hbd_barTintColor {
return objc_getAssociatedObject(self, _cmd);
}
hbd_barTintColor
换成 hbd_computedBarTintColor
hbd_barTintColor
换成hbd_computedBarTintColor
换成 hbd_computedBarTintColor
也不行
- (UIColor *)hbd_computedBarTintColor {
if (self.hbd_barImage) {
return nil;
}
UIColor *color = self.hbd_barTintColor;
if (!color) {
if ([[UINavigationBar appearance] backgroundImageForBarMetrics:UIBarMetricsDefault]) {
return nil;
}
if ([UINavigationBar appearance].barTintColor) {
color = [UINavigationBar appearance].barTintColor;
} else {
color = [UINavigationBar appearance].barStyle == UIBarStyleDefault ? [UIColor colorWithRed:247/255.0 green:247/255.0 blue:247/255.0 alpha:0.8]: [UIColor colorWithRed:28/255.0 green:28/255.0 blue:28/255.0 alpha:0.729];
}
}
return color;
}
上面这是 hbd_computedBarTintColor
的代码,其中也会把 [UINavigationBar appearance].barTintColor
作为默认色。
当我的场景是隐藏导航栏的时候,下面这个判断的后半段,结果是 NO
,再取反,edgesForExtendedLayout
依然会被设置为 UIRectEdgeNone
。从而导致顶部导航栏的位置出现黑条
if (!(self.hbd_extendedLayoutIncludesTopBar || hasAlpha(self.hbd_barTintColor))) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
我感觉基类的这个逻辑判断是不是有点问题?感觉除了动态的,仅使用 self.hbd_extendedLayoutIncludesTopBar
来判断之外,好像没有别的办法?
或者像这样:
if (!(hbd_barHidden || hbd_barAlpha < 1 || hasAlpha(self. hbd_computedBarTintColor))) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
但是这样子类在修改 NavigationBar
的一些配置的时候,都要放在 [super viewDidLoad]
之前了...
我打算内部处理掉 edgesForExtendedLayout
edgesForExtendedLayout
好的!期待。那我先用 self.hbd_extendedLayoutIncludesTopBar
暂时凑合一下。
我把代码推上去了
你测试下有没有问题
好快啊。目前试了下来没有发现问题,感觉这个可以。
@listenzz 发现你这么改了之后,Safe Area 约束有问题了... demo 就可以直接复现,按上面提到的 这个 步骤
具体表现为,隐藏导航栏前后,“Test Safe Area” 文本框的位置不变。按理说隐藏导航栏之后,文本框的位置应该会上移的。
这样啊,哈哈。因为 NavigationBar 还在,并没有真正隐藏。
这样啊,哈哈。因为 NavigationBar 还在,并没有真正隐藏。
那这样的话 top
是不是就不能用 Safe Area 布局了😂
像下面那样修改 adjustLayout
void adjustLayout(UIViewController *vc) {
BOOL isTranslucent = vc.hbd_barHidden || vc.hbd_barAlpha < 1.0;
if (!isTranslucent) {
UIImage *image = vc.hbd_computedBarImage;
if (image) {
isTranslucent = imageHasAlphaChannel(image);
} else {
UIColor *color = vc.hbd_computedBarTintColor;
isTranslucent = colorHasAlphaComponent(color);
}
}
if (isTranslucent || vc.extendedLayoutIncludesOpaqueBars) {
vc.edgesForExtendedLayout |= UIRectEdgeTop;
} else {
vc.edgesForExtendedLayout &= ~UIRectEdgeTop;
}
if (vc.hbd_barHidden) {
if (@available(iOS 11.0, *)) {
vc.additionalSafeAreaInsets = UIEdgeInsetsMake(-44, 0, 0, 0);
} else {
// Fallback on earlier versions
}
}
}
像下面那样修改 adjustLayout
这样修改是有效果的。建议把 -44 改为获取导航栏的高度吧。写死好像不太好。
不过看你更新了 1.7.1 版本但没有包含这个修改?
1.7.1 确保只调用一次 adjustLayout
动态获取导航栏高度有什么建议没,考虑屏幕旋转的情况
动态获取导航栏高度有什么建议没,考虑屏幕旋转的情况
测了一下屏幕旋转的情况,发现导航栏的高度没必要动态获取。我是这么写的:
if viewController.mbc.isBarHidden {
if #available(iOS 11.0, *) {
if let height = viewController.navigationController?.navigationBar.frame.size.height {
let insets = viewController.additionalSafeAreaInsets
viewController.additionalSafeAreaInsets = UIEdgeInsets(
top: -height + insets.top,
left: insets.left,
bottom: insets.bottom,
right: insets.right
)
}
}
}
布局还是按照最上面提到的写的,打开了 Safe Area 的注释。实测 UI 方面没有什么问题。
需求:
隐藏 NavigationBar 后,顶部 View 距离
view.safeAreaLayoutGuide.top
10px 的距离。前提:
barHidden
为YES
isExtendedLayoutIncludesTopBar = YES
,即self.edgesForExtendedLayout = UIRectEdgeNone;
问题:
我发现隐藏了导航栏后,无法使用 Safe Area 进行布局,会有以下问题:
顶部 view 的布局是从 NavigationBar 下面开始的,仿佛导航栏还在,即使它成功隐藏了。
当我放弃使用 Safe Area ,直接使用
view.mas_top
进行布局的时候,view 又延伸到了 Status Bar 下面,所以我还要额外加上UIApplication.shared.statusBarFrame.size.height
的高度。请问这个有办法避免吗?即继续使用
safeAreaLayoutGuide
进行布局。ps:
我是在 Swift 环境下进行操作的,我将本库整个翻译成了 Swift,后续可能会考虑提 pr。
修改后
viewDidLayoutSubviews
中的布局代码大致如下(使用 SnapKit,Swift 下的 Masonry):