iOS开发适配总结

前言

•本文为iOS开发AutoLayout的总结记录和一些适配的经验,主要讲述当前使用比较多的系统自适应的方式,特别是tableView的cell的高度自适应(能用tableview完成的界面,都不用其它UI)。适应方式包括:

1.NSLayoutConstraint

2.Masonry

3.XIB

4.计算Frame

5.数据LayoutModel概念

其中,前三种都是一样的,只是不同的方式,Masonry封装了NSLayoutConstraint,点语法更加简便易用。

内容

首先备注一下,自动适配重点设置属性!!!

View自适应,需要把View的translatesAutoresizingMaskIntoConstraints设置为NO,XIB会自动设置,可以考虑在基类设置。

1.NSLayoutConstraint

NSLayoutConstraint是系统类,用于添加约束,在添加约束前,必须要先把view添加到父view上再进行约束。约束一般为4个约束,最基本的是原点+宽高,后面衍生出相对距离,居中,齐平等条件,再后来就是约束的优先级设置,优先级有 至少,最多,约束冲突优先级等设置,基本上满足了所有的UI设计!开发过程中需要想象约束条件。以下举个例子

图中有5个约束(比4个多),这个cell如果设置了自适应高度,那么图片的4个边距是一定,并且图片的高度是一定比某个值大。

那么按照上面图,我们对应NSLayoutConstraint的代码如下:

[self.contenView addConstraint:[NSLayoutConstraint constraintWithItem:self.content attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:170]];
    [self.contenView addConstraint:[NSLayoutConstraint constraintWithItem:self.content attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:5]];
    [self.contenView addConstraint:[NSLayoutConstraint constraintWithItem:self.content attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeRight multiplier:1.0f constant:-5]];
    [self.contenView addConstraint:[NSLayoutConstraint constraintWithItem:self.content attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-5]];
    [self.content addConstraint:[NSLayoutConstraint constraintWithItem:self.content attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1.0f constant:90]];

5个NSLayoutConstraint对应5图内5条线,代码看似很多,其实内容很少,仔细会发现有很多重复的代码!

为了将复杂的东西简单化,直观化,Masonry就这样出现了。

2.Masonry

Masonry是链式编程标志性库,链式编程把一个个方法调用使用了”点”方法来调用,理解是,将代码区块化并且区块代码返回当前操作对象用于调用下一个区块代码!

利用了2个知识点:1.block的代码块封装,2. Get方法(“点”方法)!

最简单的block封装结构如下:

//第一种方式,直接声明block,看着比较复杂
- (Person *(^)(void))sleep{
    Person * (^sleepBlock)(void) = ^(void){
        NSLog(@"-----我在睡觉----");
        return self;
    };
    return sleepBlock;
}

//第二种方式,先定义block,再来设置方法内容,比较清晰
typedef Person *_Nullable(^noDataBlock)(void);
- (noDataBlock)wakeup{
    noDataBlock block = ^{
        NSLog(@"-----我起床了----");
        return self;
    };
    return block;
}

有兴趣的小伙伴可以自行百度,链式编程代码比较美观,跟JAVA和Python的语法有点像,挺好!

Masonry核心代码实际是封装了NSLayoutConstraint,所以,如果我们觉得苹果的繁琐&&啰嗦,不妨使用Masonry,思想和想象的方式是一样的,例如针对上图的约束,我们用Masonry做一遍,代码如下:

[self.content mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(weakSelf.view.mas_left).mas_offset(170);
        make.top.mas_equalTo(weakSelf.view.mas_top).mas_offset(5);
        make.bottom.mas_equalTo(weakSelf.view.mas_bottom).mas_offset(-5);
        make.right.mas_equalTo(weakSelf.view.mas_right).mas_offset(-5);
        make.height.mas_greaterThanOrEqualTo(90);
        
    }];

对比下效果是不是觉得很简洁!

当然,Masonry还有一些优先级的设置,例如上面的大于等于90高度的设置,如果要设置优先级,如下

make.height.mas_greaterThanOrEqualTo(90).priorityMedium();

Masonry能满足你想要的约束

以上方式为纯代码方式,内容多了编写起来也是挺费劲,从动态加载数据和继承方面来说,代码编写比较习惯的理解!

当界面是静态界面并且没有继承(普通业务界面一般不被继承),苹果给我们一个很直观,很渐变的方式编写UI,并且约束直观,效率高! 这就是XIB。

3.XIB

XIB的关联这里不描写步骤,思想与上面描述的也是一样,一行代码描写了一条线!

喜欢它快和直观,跟Android的UI配置文件XML很相似!

自适应高度或宽度的时候不要限制高度或宽度等于某个常数并且是最高优先级即可!

XIB是静态页面适配首选!

总结:以上是3种约束的方式,归根到底是一种方法,3种设置方法,设置的约束比较固定,难免会出现大小屏间距,高宽一模一样的问题! 这主要原因是我们设置约束都是一些常识!

针对以上的问题,有的人会做一个Frame管理类来计算对应屏幕对应的数值,原理是根据屏幕宽高和设计稿使用的屏幕宽高计算出一个比例来实现获取对应的值,简单公式如下

resultWidth =  designWidth *  [UIScreen mainScreen].bounds.size.width/designFrameWidth(例如:375)

以上只是例子,有很多种计算!

4.计算Frame

实际的开发过程中,设计的大牛们通常会提供一份375*667或414*896的标注图给我们(sketch),在追求完美的设计师眼里,组件的宽高比经常会被强制地要求完全符合他们的设计稿,执行单位的我们,就想出了转换每一个尺寸的想法!因此,一个转换Frame的管理单例就诞生了!

管理思想是很直接的!简单公式为: 需求横向尺寸*当前屏幕宽/设计稿屏幕宽,而纵向也一样。当然字体也可以同步设置。

如下图

根据标注文件设计一个单例管理所有尺寸的比例,从而满足设计师的请求

Demo链接:https://github.com/WuChuming/CMFrameManager/tree/master

Demo中的CMFrameManager可以直接导入项目使用,如果项目没有SecneDelegate文件,可以直接删除CMSenceContainer类使用

值的注意的是由于导航栏和Tabbar的高度是不能按屏幕比例缩放的,所以我们在计算比率的时候,先将导航栏和Tabbar的高度减去,使用有效区域来计算比率!iPX的设计图一样地计算

整个管理模块的层别如下:

计算应该搭配自适应设置使用,以尽量满足设计师的像素差别!

5.数据LayoutModel概念

普通的数据获取和展示如下图

普通的设计模式直观,数据对应不同的View,展示直接!

但是,有2个问题:

1.ViewController要处理模型和视图关系,约束,业务状态的时候,往往就会出现大量代码,后期阅读和维护困难,关联性强,比较容易埋坑

2.视图自定义性很高,代码冗余,不好拓展,后期增加相似View需要重新定义视图,并且View控制器重新增加逻辑适配,控制器代码量和View的视图数量会渐渐增加!

监于以上两个问题,我们需要一个减轻视图控制器并且能规范视图展示的对象!

这个对象的方法包括:

1.整理原始数据,从原始数据中处理数据展示逻辑(如没有数据转换展示,没有数据View显示其它类型等),约束状态(如高度计算,图片尺寸等) 和 其它相关的状态属性(如背景图样式等)

2.归纳数据,整理出TableView熟悉的Title,Section,Row数据源数据。

总结以上描述,流程图如下

从图上可以看出,VC的视图状态,约束处理代码和复用对应View的微调代码由LayoutModel来实现,LayoutModel是数据整理层的对象,将项目数据搬运的过程中层次分离就更加明显!

请看下面的例子

发表评论

邮箱地址不会被公开。 必填项已用*标注