iOS开发技巧iOS开发大神总结ios开发小技巧

iOS 11和iPhoneX适配遇到坑

2017-11-30  本文已影响1244人  骑行天下

一.iPhone X尺寸问题 

1. 高度增加了145pt,变成812pt. 

2.屏幕圆角显示,注意至少留10pt边距。

3. 状态栏高度由20pt变成44pt,留意这个距离就能避开“刘海”的尴尬,相应的导航栏以上变化64--->88。 

4.底部工具栏需要为home indicator留出34pt边距。 5.物理分辨率为1125px * 2436px

非iPhone X :

StatusBar高20px,NavigationBar高44px,底部TabBar高49px

iPhone X:

StatusBar高44px,NavigationBar高44px,底部TabBar高83px

二.适配用到的宏

// status bar height.

#define  kStatusBarHeight      (IS_iPhoneX ? 44.f : 20.f)

// Navigation bar height.

#define  kNavigationBarHeight  44.f

// Tabbar height.

#define  kTabbarHeight        (IS_iPhoneX ? (49.f+34.f) : 49.f)

// Tabbar safe bottom margin.

#define  kTabbarSafeBottomMargin        (IS_iPhoneX ? 34.f : 0.f)

// Status bar & navigation bar height.

#define  kStatusBarAndNavigationBarHeight  (IS_iPhoneX ? 88.f : 64.f)

//判断是否iPhone X

#define IS_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)

三.APP启动样式适配,屏幕未充满

1.启动页屏幕未充满

APP在iPhone X上占满整个屏幕, 而是保持着原有的高度 在屏幕中心位置, 屏幕的顶部和底部都有黑边.

适配前 适配前首页

通过LaunchScreen.storyboard方式启动

如果使用的是Assets中的LaunchImage, 在增加了iPhone X尺寸的图片配置后.

LaunchScreen.storyboard方式不用多说, 这里说一下如何在LaunchImage中增加iPhone X尺寸的图片配置.

方法一:

准备一张尺寸:1125 * 2436的 3x启动图片, 移动到LaunchImage的Finder目录中, 并在LaunchImage中的Contents.json文件中增加 (注意Json格式):

{

"extent" : "full-screen",

"idiom" : "iphone",

"subtype" : "2436h",

"filename" : "图片名.png",

"minimum-system-version" : "11.0",

"orientation" : "portrait",

"scale" : "3x"

}

LaunchImage变化

方法二:

未勾选箭头指向Portraint 已勾选Portrait 图片拖进来效果 LaunchImage中的Contents.json文件 适配后启动图片占满整个屏幕

2.引导页iPhone X图片变形

适配前 适配后

由于iPhone X高度发生变化,图片铺满整个屏幕时候造成图片拉伸,现在需要UI切一个1125*2436的3x图片和以前做iPhone X机型判断1124*2001图片,并且对图片contentMode属性进行设置

if (IS_iPhoneX) {

coverImageNames = [NSArray arrayWithObjects:@"img_big_1_ipx.jpg", @"img_big_2_ipx.jpg",@"img_big_3_ipx.jpg", @"img_big_4_ipx.jpg",nil];

}else{

coverImageNames = [NSArray arrayWithObjects:@"img_big_1.jpg", @"img_big_2.jpg",@"img_big_3.jpg", @"img_big_4.jpg",nil];

}

imageView.clipsToBounds = YES;//超出区域裁剪

imageView.contentMode = UIViewContentModeScaleAspectFill;//图片等比例拉伸,会填充整个区域,但是会有一部分过大而超出整个区域

四:UITableview UICollectionView MJRefresh下拉刷新错乱

适配前首页

iOS11表格用MJRefresh框架下拉刷新的时候界面会闪,显示紊乱,

原因是iOS11弃用了automaticallyAdjustsScrollViewInsets属性,新增contentInsetAdjustmentBehavior来替代它

tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

解决方法:MJRefresh作者已经针对iOS 11和iPhone X做了适配,把MJRefresh更新最新的版本

//声明tableView的位置 添加下面代码

if (@available(iOS 11.0, *)) {

_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

_tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);

_tableView.scrollIndicatorInsets = _tableView.contentInset;

}

五.纯代码适配齐刘海

iPhone X导航栏由以前的固定64变成现在88,Statebar的高度由20变成44,增加24,项目中以前用导航栏64地方都进行是否iPhoneX判断,用到宏#define  kStatusBarAndNavigationBarHeight  (IS_iPhoneX ? 88.f : 64.f)

项目中导航栏自定义导航栏会遇到很多奇葩的问题如下图

导航栏

(1)在iPhone X中导航栏高度变成88,项目中自定义导航栏高度64,需要对导航栏高度进行判断

_navigationBar = [[MCCustomNavigationBar alloc]initWithFrame:CGRectMake(0, 0, SCREENW, 64) andType:CustomBarType_Home];

_navigationBar = [[MCCustomNavigationBar alloc]initWithFrame:CGRectMake(0, 0, SCREENW, kStatusBarAndNavigationBarHeight) andType:CustomBarType_Home];

(2)搜索框和左右两边按钮高度有问题,因为iPhone X中状态栏高度由20增加24变成44,所以搜索框和左右两边按钮高度在iPhone X上距顶部高度加上24高度,

#define itemTopOffset (IS_iPhoneX ? (26+24) : 26)

[self.leftBtn mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.offset(itemHorOffset);

make.height.equalTo(@(itemHeight));

make.width.equalTo(@(itemHeight));

make.top.offset(itemTopOffset);

}];

(3)iOS11上searchBar高度明显变大,

UITextField

UISearchBar改变搜索框的高度

系统的searchBar

UISearchBar的中子控件及其布局

UIView(直接子控件) frame 等于 searchBar的bounds,view的子控件及其布局

UISearchBarBackground(间接子控件) frame 等于searchBar的bounds

UISearchBarTextField(间接子控件) frame.origin等于(8.0, 6.0),即不等于searchBar的bounds

改变searchBar的frame只会影响其中搜索框的宽度,不会影响其高度,原因如下:

系统searchBar中的UISearchBarTextField的高度默认固定为28

左右边距固定为8,上下边距是父控件view的高度减去28除以2

改变UISearchBar的高度

方案

重写UISearchBar的子类(MCSearchBar),重新布局UISearchBar子控件的布局

增加成员属性contentInset,控制UISearchBarTextField距离父控件的边距

若用户没有设置contentInset,则计算出默认的contentInset

若用户设置了contentInset,则根据最新的contentInset布局UISearchBarTextField

新建UISearchBar的子类,增加成员属性contentInset,用来调整UISearchBarTextField距离父控件的边距。contentInset的setter方法

#pragma mark - setter method

- (void)setContentInset:(UIEdgeInsets)contentInset {

_contentInset.top = contentInset.top;

_contentInset.bottom = contentInset.bottom;

_contentInset.left = contentInset.left;

_contentInset.right = contentInset.right;

self.isChangeFrame = YES;

[self layoutSubviews];

}

- (void)layoutSubviews {

[super layoutSubviews];

for (UIView *subView in self.subviews[0].subviews) {

if ([subView isKindOfClass:[UIImageView class]]) {

//移除UISearchBarBackground

[subView removeFromSuperview];

}

if ([subView isKindOfClass:[UITextField class]]) {

CGFloat height = self.bounds.size.height;

CGFloat width = self.bounds.size.width;

if (_isChangeFrame) {

//说明contentInset已经被赋值

// 根据contentInset改变UISearchBarTextField的布局

subView.frame = CGRectMake(_contentInset.left, _contentInset.top, width - 2 * _contentInset.left, height - 2 * _contentInset.top);

} else {

// contentSet未被赋值

// 设置UISearchBar中UISearchBarTextField的默认边距

CGFloat top = (height - 28.0) / 2.0;

CGFloat bottom = top;

CGFloat left = 8.0;

CGFloat right = left;

_contentInset = UIEdgeInsetsMake(top, left, bottom, right);

subView.frame = CGRectMake(_contentInset.left, _contentInset.top, width - 2 * _contentInset.left, height - 2 * _contentInset.top);

}

}

}

}

在项目中使用自定义的MCSearchBar,SearchBar的高度可以改变

(4)iOS11中UISearchBar没有居中居左显示,并且icon和placeholder间距太窄

图标居左显示

现在实现居中显示

图标和文字居中

@property(nonatomic,assign)CGFloatwidth;

//判断版本

if(@available(iOS11.0, *)){

UITextField *textField = [self.searchBar valueForKey:@"searchField"];

[textField sizeToFit];

//记录一下这个时候的宽度

_width= textField.frame.size.width;

[_searchBar setPositionAdjustment:UIOffsetMake((_searchBar.width-_width)/2.0,0)forSearchBarIcon:UISearchBarIconSearch];

}

然后在代理方法 searchBarTextDidBeginEditing:(UISearchBar*)searchBar 调整位置

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{

if (@available(iOS 11.0, *)) {

if(!_searchBar.text.length) {

[_searchBar setPositionAdjustment:UIOffsetMake(0,0)forSearchBarIcon:UISearchBarIconSearch];

}

}

}

结束的方法  searchBarTextDidEndEditing:(UISearchBar*)searchBar 判断是否有内容

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{

if (@available(iOS 11.0, *)) {

if(!_searchBar.text.length) {

[_searchBar setPositionAdjustment:UIOffsetMake((_searchBar.width-self.width)/2.0,0) forSearchBarIcon:UISearchBarIconSearch];

}

}

}

如果有占位文字后台返的,UITextField在搜索框默认文字大小17,可以根据文字个数和大小算出占位文字宽度,然后算出搜索图标的偏移量.

(5)搜索页面导航栏中搜索框距离返回按钮太近

适配前

self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, testView.width - (SCREENW > 320 ? 90: 100)*SCREEN_Proportion, testView.height)];

由于搜索框距离左边距离导致的,现在需要定义一个宏做判断

#define marginLeft (IS_iPhoneX ? 10 : 0)

self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(marginLeft, 0, testView.width - (SCREENW > 320 ? 90: 100)*SCREEN_Proportion, testView.height)];

适配后效果

六.纯代码适配底部工具栏

在iPhone X中底部工具栏需要为home indicator留出34pt边距,iPhone X以前机型TarBar高度49,iPhone X中Tarbar高度加上34变成83.由于项目中Tabbar是用自定义的,需要对Tabbar的高度做适配,用到宏#define kTabbarHeight (IS_iPhoneX ? (49.f+34.f) : 49.f)

TarBar适配前

适配前代码

_customBarView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREENH - 49,SCREENW, 49)];

适配后的代码_customBarView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREENH - kTabbarHeight,SCREENW, kTabbarHeight)];

图标和文字居中

图标和文字和其他机型相比偏下,现在需要对图标和文字高度进行调整,做iPhone X和非iPhone X机型适配

图标高度适配 适配后的TarBar

七.底部view出现问题

(1)购物车View适配,涉及页面商品详情页,搜索页面,购物车页面

购物车页面适配前 搜索页面 购物车view #define kTabbarHeight (IS_iPhoneX ? (49.f+34.f) : 49.f) 适配后购物车View 其他页面点击购物车图标进入购物车页面 点击TarBar按钮进入购物车,购物车View被遮挡 适配前的代码

-(void)updateUIFrame

{

if (_fromType == ToShoppingTrolleyType_New_Other) {

[[MCNavigationLeftView shareManager] initWithTitle:nil andNavi:self andSEL:@selector(back)];

[[MCTabbarTool shareManager]hideTabbarView:NO];

self.view.frame = CGRectMake(0, 0, SCREENW, SCREENH-kStatusBarAndNavigationBarHeight-(IS_iPhoneX?34:0));

}else{

[[MCTabbarTool shareManager]showTabbarView:YES];

self.view.frame = CGRectMake(0, 0, SCREENW, SCREENH-kStatusBarAndNavigationBarHeight-kTabbarHeight);

}

self.cartBottomView.frame = CGRectMake(0, self.view.height-49, SCREENW, 49);

}

(2)自定义数字键盘适配

适配前TabBar图标进去购物车页面 适配后

适配底部用的一个宏#define  kTabbarSafeBottomMargin        (IS_iPhoneX ? 34.f : 0.f)用于计算距离屏幕顶部高度,如果iPhone X,留出距离屏幕底部34安全距离,控件不能显示34安全距离上

适配前代码 适配后代码

(3)筛选views适配

适配前 适配前collectionview 适配后collectionview

运行程序发现底部按钮高度偏高,如图所示,现在需要调整底部按钮距离屏幕顶部高度

底部按钮 适配后代码 适配后

(4)适配查看优惠券

适配前优惠券的详细信息 适配前 适配前代码 适配后代码 适配后优惠券详情

(5)适配填写订单

适配前 适配前底部view代码 适配后底部view代码 适配后

(6)Tabbar没有完全遮住

适配前遮罩部位没有遮住

为了遮住TabBar,在iPhone X上tabbar高度增加34,需要调整遮罩tabbar窗口的高度

适配前代码 适配后代码 适配后效果

八.继承自UIScrollView的视图偏移问题

我们可以发现collectionview在iOS11向下偏移64,什原因导致偏移?在iOS11之前,如果想要scrollView不偏移64p,则需设置automaticallyAdjustsScrollViewInsets=NO,但是这个属性在iOS11直接被遗弃了😳:使用scrollView的属性contentInsetAdjustmentBehavior来防止偏移。

UIScrollViewContentInsetAdjustmentAutomatic

UIScrollViewContentInsetAdjustmentScrollableAxes

UIScrollViewContentInsetAdjustmentNever

UIScrollViewContentInsetAdjustmentAlways

这里我们直接选Never就可以了

if (@available(iOS 11.0, *)) {

  _collectionView.contentInsetAdjustmentBehavior = UIApplicationBackgroundFetchIntervalNever;

     }

但是在iOS11以前系统编译崩溃,原来@available(iOS 11.0, *)是iOS 11新增加的,在iOS11以下系统找不到崩溃,为了解决这个问题需要用到条件编译指令解决这个问题

#ifdef __IPHONE_11_0

if (@available(iOS 11.0, *)) {

_collectionView.contentInsetAdjustmentBehavior = UIApplicationBackgroundFetchIntervalNever;

}

#endif

适配前我的页面 适配后我的页面

九.自定义分割线处理

1.iOS 11分割线颜色加深

iOS 11中有的自定义分割线颜色莫名奇妙变深,很难看,如下图所示,不符合设计规范,尝试其他方法没有解决这个问题,最后通过改变分割线的透明度来解决

适配前 适配前代码 适配后代码 适配后

2.没有文字显示分割线

适配前

// 这些界面以下使用代理方法来设置,发现并没有生效

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

// 这样的原理是因为之前只是实现了高度的代理方法,却没有实现View的代理方法,iOS10及以前这么写是没问题的,iOS11开启了行高估算机制引起的bug,因此有以下几种解决方法:

// 解决方法一:添加实现View的代理方法,只有实现下面两个方法,方法 (CGFloat)tableView: heightForFooterInSection: 才会生效

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {

return nil;

}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

return nil;

}

// 解决方法二:直接使用tableView属性进行设置,修复该UI错乱

self.tableView.sectionHeaderHeight = 0;

self.tableView.sectionFooterHeight = 5;

[_optionTableView setContentInset:UIEdgeInsetsMake(-35, 0, 0, 0)];

// 解决方法三:添加以下代码关闭估算行高

self.tableView.estimatedRowHeight = 0;

self.tableView.estimatedSectionHeaderHeight = 0;

self.tableView.estimatedSectionFooterHeight = 0;

适配后

十.顶部菜单上移,挡住文字适配

适配前顶部菜单被挡住 适配前代码 适配后代码 适配后常用清单页面

十一.适配xib页面

适配前注册页面

注册页面用xib写的,页面tableview距离顶部高度64,写死的,由于导航栏高度在iPhone X和非iPhone X高度不一致,如果都写成64出现下图问题,为了解决这个问题,用到系统自动布局NSLayoutConstraint视图上面,在storyboard 中,通过拖拽方式,将一个IBOutlet 拖拽到 .m 文件中如图所示

tableview距离顶部高度 适配后代码 适配后注册页面

十二:信号栏的字体颜色无法改变

适配前信号栏颜色 改变信号栏颜色方法

改变信号栏方法使用,如果某个页面状态栏颜色改变自己定义颜色用这个方法,针对iOS11以前使用

- (void)viewWillAppear:(BOOL)animated {

[super viewWillAppear:animated];

[MCHelpTool changeSignalFormatWithColor:[UIColor whiteColor]];

}

但是在iOS11上状态栏的颜色通过这个方法无法改变,状态栏机制发生变化导致,需要对该方法进行iOS11适配.

iOS 11(非iPhone X机型) iPhone X iOS11以前

/**

*  改变信号栏字体颜色

*

*  @param color 颜色参数

*/

+ (void)changeSignalFormatWithColor:(UIColor *)color{

UIApplication * app = [UIApplication sharedApplication];

id obj = [app valueForKeyPath:@"statusBar"];

if (@available(iOS 11.0, *)) {

if (IS_iPhoneX) {

id obc = [obj valueForKeyPath:@"statusBar"];

unsigned int propertyCount;

objc_property_t * properties = class_copyPropertyList([obc class], &propertyCount);

NSMutableArray * arr = [NSMutableArray arrayWithCapacity:1];

for (int i = 0; i < propertyCount; i++){

objc_property_t property = properties[i];

NSString * propertyStr = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];

if ([propertyStr isEqualToString:@"foregroundColor"]){

[obj setValue:color forKey:propertyStr];

}

[arr sui_addObj:propertyStr];

}

free(properties);

}else{

id ob = [obj valueForKeyPath:@"superclass"];

unsigned int propertyCount;

objc_property_t * properties = class_copyPropertyList([ob class], &propertyCount);

NSMutableArray * arr = [NSMutableArray arrayWithCapacity:1];

for (int i = 0; i < propertyCount; i++){

objc_property_t property = properties[i];

NSString * propertyStr = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];

if ([propertyStr isEqualToString:@"foregroundColor"]){

[obj setValue:color forKey:propertyStr];

}

[arr sui_addObj:propertyStr];

}

free(properties);

}

}else{

unsigned int propertyCount;

objc_property_t * properties = class_copyPropertyList([obj class], &propertyCount);

NSMutableArray * arr = [NSMutableArray arrayWithCapacity:1];

for (int i = 0; i < propertyCount; i++){

objc_property_t property = properties[i];

NSString * propertyStr = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];

if ([propertyStr isEqualToString:@"foregroundColor"]){

[obj setValue:color forKey:propertyStr];

}

[arr sui_addObj:propertyStr];

}

free(properties);

}

}

未完待续....

参考文章:

iOS11-UISearchBar居中placeholder和icon

ios 改变searchBar的高度

UIsearchBar iOS11 像之前的版本那样没有内容居中 有内容居左

iPhone X HIG

Adaptivity & Layout

Image size & Resolution

WWDC17: What's New in Location Technologies ?

Designing for iPhone X

Building Apps for iPhone X

关于iPhone X 的适配

iOS11 & iPhone X 适配指南

你可能需要为你的 APP 适配 iOS 11

适配iOS11,适配iPhoneX,适配安全区的几个文章和宏

为 iOS 11 适配工具栏(UIToolBar)

简书 App 适配 iOS 11

iOS 安全区域适配总结

Update Apps for iPhone X

手管 iPhone X 的适配总结

iOS11 以及iPhone X 适配记录

如何快速定位、分析、解决非Crash的BUG(iOS 11篇)

上一篇下一篇

猜你喜欢

热点阅读