美文网首页
iphoneX适配的问题

iphoneX适配的问题

作者: 大亮code | 来源:发表于2022-04-15 23:08 被阅读0次

1.为什么会有这个问题?

因为iphoneX为了实现全面屏,iPhone X之前的手机 状态栏高度(20.f) + 导航栏高度(44.f) = 64.f,iPhone X是 状态栏高度(44.f) + 导航栏高度(44.f) = 88.f.

差别在于状态栏差了24.因为现在是刘海屏幕,中间的部分被摄像头等部件等硬件挡住就显示不全了.

还有一个区别是底部是34的小黑条,小黑条的作用是替代被取消的Home键的作用, 原来手机如果之前是有home键,可以按住Home键从当前应用回到桌面,现在按键被取消了,可以通过往上滑动小黑条从当前应用回到桌面.

总结一下,对于一般的应用有导航栏和tabBar的情况来说,内容一般都是从导航栏的下面开始显示,到tabbar上面,这一般是应用的显示范围.但是对于上下滑动的比方说scrollView,tableView,collectionView来说,我们显示在整个屏幕,这时就可以提现全面屏的更大显示空间.还有对于webview,如果底部没有需要点击的按钮,或者tabar,我们都是可以将内容显示到屏幕的最下面.

核心是顶部是遮挡的内容你是否在意,下面是否有点击操作和下面的小黑条的操作冲突.如果你在意上面遮挡的部分,就要从刘海下面开始布局UI,如果你的底部有按钮点击的操作,按钮的底部要距离屏幕在34以上,以防止误操作,影响用户体验.

下面是两个案例:

适配前:


Snip20220415_16.png

适配后:


Snip20220415_17.png

适配前:


Snip20220415_19.png

适配后:


Snip20220415_20.png

如何解决iPhone X这类的问题:

第一种方法:给导航栏或tabbar增加一个固定的距离,比如顶部增加44pt(状态栏,刘海的高度),底部增加34pt.一开始有不少开发者都是这么干的,但是这样在某些状态下有一些问题:

  1. 如果以后摄像头做小了,上面的状态栏不是44,比方说34,可能又要增加这种情况适配.
  2. 还有一个横竖屏就完蛋了,本来是竖屏,转过去,应该左侧距离44,上部靠顶布置,右侧留34.下面顶住下面.如果按照写死就会导致上面 44,下面34,左右需要间距的却没有间距.不过对于手机的应用来说,大部分都不要求页面都是不让旋转屏幕的.
  3. 还有一个确定是不够动态,还是举个例子,假如有电话打进来了,导航栏应该会下移,这时候view可能还是会被挡住

第二种方法:使用safeAreaLayoutGuide 和 safeAreaInsets

autolayout使用系统提供的属性safeAreaLayoutGuide

1.它是UIView的一个只读属性,意味着所有UIView对象都有并且是系统帮我们创建好的
2.它继承UILayoutGuide,有layoutFrame意味着它能代表一块区域
3.它代表的区域避开了诸如导航栏、tabbar或者其他有可能挡住你这个UIView对象显示的所有父view,意味着你的view对象只要相对另一个view的safeLayoutGuide做布局就不用担心她被奇奇怪怪的东西挡住
4.对于控制器的view的safeAreaLayoutGuide,他的区域同样避开了statusbar或其他有可能挡住view显示的东西,我们甚至可以用控制器的additionalSafeAreaInsets属性,来额外指定inset
5.如果view完全在父view的安全区域内,或者view不在视图层级或屏幕上,那么view的safeAreaLayoutGuide区域其实和view自身是一样大的.

上面是对官方文档的翻译,个人理解的系统其实的解决方案是给所有的View 添加一个属性,然后所有的被创建出来的View 的safeAreaLayoutGuide都会被赋一个值,这个值是系统根据当前机型计算,都是同一个值.
这个其实就是安全区域的范围,但是并不是我们一定要按照安全区域布局,我们可用可不用,我们可以根据实际情况进行具体的选择.比方说我们有时可能是一个webview,我们完全可以忽略安全区域,让他全屏滑动.还有视频播放器,全屏播放时我们也是忽略刘海和底部bar

常见用法

在一种常见的使用场景里,以前我的某个view是相对于控制器的view做布局,现在是相对控制器view的safeAreaLayoutGuide做布局了

以前是这样写 self.vc.view

[NSLayoutConstraint constraintWithItem:someView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.vc.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];

现在是这样 self.vc.view.safeAreaLayoutGuide

[NSLayoutConstraint constraintWithItem:someView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.vc.view.safeAreaLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];

这里有两种情况:
1.A控制的View 加在rootViewcontroller的view 中,其实我们需要的对A控制器的View对于安全的区域作用布局就好,因为控制器的View没有被遮挡,子控件是相对于父控件布局的,自然也不会有影响.子控件对不对安全区域布局都没有影响.

2.A控制的View 加在rootViewcontroller的view 中,如果A控制器的View 没有对安全区域进行布局, 我们在创建这个View 的子控件来说,如果我们是用xib布局的,因为默认是勾选了下面的选项,子控件依然能够布局正确,按照安全区域进行布局.

Snip20220415_15.png

如果我们想扩大自定义安全区域

对于上面勾选的这个safe Area Relative Margins, 网上是说可以通过在 A控制器中里面加上下面的代码,安全区域增加一个额外的Margins.
下面代码放在控制器里面:

- (void)viewDidLayoutSubviews {
    self.additionalSafeAreaInsets = UIEdgeInsetsMake(50, 50, 50, 50);
}

可以使用这个属性调整安全区域,安全区域仅仅指的是不被系统的status bar或者navigation bar所遮挡,你可以通过这个属性扩大安全区域,举个例子,一个画画的app,你可以通过这个属性防止内容被工具调色板遮挡.

如果我们是Frame布局呢

如果你是使用Frame进行布局,可以利用系统提供的这个safeAreaInsets

有没有觉得和safeAreaLayoutGuide很像?safeAreaLayoutGuide可能就是根据safeAreaInsets来调整自己的bounds的
iPhone X竖屏时占满整个屏幕的控制器的view的safeAreaInsets是(44,0,34,0),横屏是(0,44,21,44),inset后的区域正好是safeAreaLayoutGuide区域

既然如此,对于自定义的顶部导航栏来说,我们可以给导航栏的高度加上一个vc.view.safeAreaInsets.top,让他变高一点就可以了,这样在X上,竖屏时top = 44, 横屏时top = 0,导航栏的高度能响应改变

需要注意的是,无论safeAreaLayoutGuide还是safeAreaInsets都是iOS11才能使用的。
对于safeAreaInsets,我们可以把版本判断写在一个函数里

我们可以这样写

static inline UIEdgeInsets sgm_safeAreaInset(UIView *view) {
    if (@available(iOS 11.0, *)) {
        return view.safeAreaInsets;
    }
    return UIEdgeInsetsZero;
}
UIEdgeInsets safeAreaInsets = sgm_safeAreaInset(self.view);
CGFloat height = kDefaultTopViewHeight; // 导航栏原本的高度,通常是44.0
height += safeAreaInsets.top > 0 ? safeAreaInsets.top : 20.0; // 20.0是statusbar的高度

问题又来了,这段代码放在什么地方合适呢?前面官方文档提到过,如果view不在屏幕上或显示层级里,view的safeAreaInsets = UIEdgeInsetsZero,所以我们需要明确知道safeAreaInsets改变的时机

应该放在下面的位置

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    UIEdgeInsets safeAreaInsets = sgm_safeAreaInset(self.view);
    CGFloat height = 44.0; // 导航栏原本的高度,通常是44.0
    height += safeAreaInsets.top > 0 ? safeAreaInsets.top : 20.0; // 20.0是statusbar的高度,这里假设statusbar不消失
    if (_navigationbar && _navigationbar.height != height) {
        _navigationbar.height = height;
    }

相关文章

网友评论

      本文标题:iphoneX适配的问题

      本文链接:https://www.haomeiwen.com/subject/jqsqertx.html