iOS屏幕屏幕适配之_Auto Layout_1

版权声明:本文为博主原创文章,未经博主允许不得转载

关于视图的布局的权威参考文档,首当其中的肯定是apple的官方文档了。这里推荐apple的Auto Layout Guide,当然也可以参考我的一篇译文Auto Layout Guideps:译的很烂,凑合看吧!在该文的最后有几篇apple推荐阅读的文档,坚持看完必定会有很大的收获的。

在iphone4s及其之前的iphone,屏幕尺寸一直是固定的3.5英寸,硬件分辨率为320*480。那时候不存在屏幕适配的问题(当然排除同时兼容ipad和iphone),直接用比较粗暴的方式把一个view的位置写死,比如下面的

- (void)viewDidLoad {
    [super viewDidLoad];
    UIView *view = [[UIView alloc] init];
    view.backgroundColor = [UIColor orangeColor];
    view.frame = CGRectMake(50, 50, 100, 100);
    [self.view addSubview:view];
}

产生的效果如下:

从2012年9月iphone5的开始,把屏幕的尺寸从之前4s的3.5英寸升级为4英寸。iphone5上市初期,由于各大app公司还没有进行适配,iphone5的屏幕比4s的长(iphone5为320*568,4s为320*480。当时大家都开始调侃到:若干年后的iphone会变成一把上方宝剑,哈哈,足够长!),导致当时未适配的app的上面和下面出现了黑条,当然很快各大app都适配了iphone5。由于屏幕只是变长了,因此适配iphone5工作量不是很大(相对以后iphone6的适配来说)。2014年9月,apple发布了iphone6和6plus,这次屏幕继续变大,分辨率为375*667、414*736,因此如果继续采用frame的写法将会是一个很大的挑战......要是以后再出现其他分辨率的手机呢?苹果设备也出现了碎片化......这个时候是该用一种全新的方法来适配手机屏幕了。之前frame的写法可以认为是一种“绝对布局”的方法,而我们现在需要用一种称为“相对布局”的方法来解决这个问题,Auto Layout正是解决这个问题的一剂良药,而这一解决方案采用了一种称之为“约束”的布局思想。

创建布局约束

创建布局约束主要有3种方法:(这里暂时只讨论apple的方法,第三方的布局库我们以后再讨论,比如Masonry)

  • 在IB中使用Auto Layout。

  • 用可视化格式语言描述的约束。(+ constraintsWithVisualFormat:options:metrics:views:)

  • 为每一个组件提供一个基本关系,从而构建NSLayoutConstraint类的实例。(+ constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:)

尽管很多iOS的入门书籍中绝大多数都是采用IB来介绍iOS开发的,但是绝大多数企业都是采用纯代码的方法来构建app,因此我们这里主要来讨论采用上面的后两种方式,即采用纯代码的方式进行UI创建和适配。关于使用IB还是纯代码方式进行iOS开发,可以参考一篇博文“iOS开发中的争议二”

第二种方法和第三种方法其实都是使用纯代码创建NSLayoutConstraint的实例(第二种方法一次创建多个实例组成的数组),可以参考apple的官方文档NSLayoutConstraint类官方文档,从中可以看到,创建NSLayoutConstraint一共有两个类方法:

+ constraintsWithVisualFormat:options:metrics:views:

+ constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:

在本博文中,我们把上面3种方法中的第二种方法称为“创建可视化语言描述的约束”,第三种方法称为“创建一般的约束”。下面我们分别讨论这两种方法。

创建一般的约束

从NSLayoutConstraint.h中我们可以看到创建一般约束对象的类方法声明:

+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;

该类方法中一共有7个参数,参数这么多........还能不能愉快的编程了???不过仔细看一下,其实没有那么复杂了。

参数 参数的作用 参数类型
参数1:view1 需要添加约束的视图 一个UIView及其子类
参数2:attr1 指定参数1需要做什么样的约束 枚举量NSLayoutAttribute
参数3:relation 与参照视图属性之间的关系,比如等于、小于、大于等 枚举量NSLayoutRelation
参数4:view2 参照的视图 NSLayoutRelation
参数5:attr2 指定参数2需要做什么样的约束 枚举量NSLayoutAttribute
参数6:multiplier 倍数 CGFloat类型
参数7:c 加数 CGFloat

上述关系中view1.attr1 = view2.attr2 *multiplier + c (假如这里relation为相等关系)

其中参数2和参数3的枚举量定义如下:

typedef NS_ENUM(NSInteger, NSLayoutRelation) {
    NSLayoutRelationLessThanOrEqual = -1,                // 小于等于关系
    NSLayoutRelationEqual = 0,                                     // 等于关系
    NSLayoutRelationGreaterThanOrEqual = 1,            // 大于等于关系
};

typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
    NSLayoutAttributeLeft = 1,                                       // 左边
    NSLayoutAttributeRight,                                           // 右边
    NSLayoutAttributeTop,                                              // 顶部
    NSLayoutAttributeBottom,                                        // 底部
    NSLayoutAttributeLeading,                                       // 首部
    NSLayoutAttributeTrailing,                                        // 尾部
    NSLayoutAttributeWidth,                                           // 宽度
    NSLayoutAttributeHeight,                                          // 高度
    NSLayoutAttributeCenterX,                                        // 水平居中
    NSLayoutAttributeCenterY,                                        // 垂直居中
    NSLayoutAttributeLastBaseline,                                 // 基线
    NSLayoutAttributeBaseline NS_SWIFT_UNAVAILABLE("Use 'lastBaseline' instead") = NSLayoutAttributeLastBaseline,
    NSLayoutAttributeFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0),
    
    NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    
    NSLayoutAttributeNotAnAttribute = 0
};

说了那么多啰嗦的理论,现在我们进入实战。假如我们有这样的需要:需要产生一个宽度和高度都为100点的正方形方块,且它位于屏幕中心。入下图所示。

- (void)createOneView {
    // 创建视图
    UIView *view = [[UIView alloc] init];
    view.backgroundColor = [UIColor orangeColor];
    // 关闭视图的autoresizing属性!!!!
    view.translatesAutoresizingMaskIntoConstraints = NO;
    // 把视图添加到self.view视图上
    [self.view addSubview:view];
    
    // 创建一个宽度的约束,宽度指定为100
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:view
                                                                       attribute:NSLayoutAttributeWidth
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:nil
                                                                       attribute:NSLayoutAttributeNotAnAttribute
                                                                      multiplier:1
                                                                        constant:100];
    // 创建一个高度约束,高度指定为100
    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:view
                                                                        attribute:NSLayoutAttributeHeight
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:nil
                                                                        attribute:NSLayoutAttributeNotAnAttribute
                                                                       multiplier:1
                                                                         constant:100];
    // 创建一个view的水平居中方向的约束,使view的水平中心等于self.view的水平中心
    NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:view
                                                                         attribute:NSLayoutAttributeCenterX
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:self.view
                                                                         attribute:NSLayoutAttributeCenterX
                                                                        multiplier:1
                                                                          constant:0];
    // 创建一个view的竖直居中方向的约束,使view的竖直中心等于self.view的水平中心
    NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:view
                                                                         attribute:NSLayoutAttributeCenterY
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:self.view
                                                                         attribute:NSLayoutAttributeCenterY
                                                                        multiplier:1
                                                                          constant:0];
    // 添加约束。创建后一定要添加约束才有效,并且约束一定要添加到该视图的最近父视图上。当然也能单独添加。
    [self.view addConstraints:@[widthConstraint, heightConstraint, centerXConstraint, centerYConstraint]];
}

下面我们再来实现一个这样的需求:创建一个包含3个矩形块的界面,其中矩形块与屏幕周边的距离都为20点,矩形块的边与边也相距20点,三个矩形块一样高,上面两个宽度一样。具体的样子入下图所示:

实现代码如下:

- (void)createThreeViews {
    // 创建3个view对象
    UIView *leftView = [[UIView alloc] init];
    UIView *rightView = [[UIView alloc] init];
    UIView *bottomView = [[UIView alloc] init];
    
    // 设置背景颜色
    leftView.backgroundColor = [UIColor greenColor];
    rightView.backgroundColor = [UIColor purpleColor];
    bottomView.backgroundColor = [UIColor orangeColor];
    
    // 添加到视图上面显示
    [self.view addSubview:leftView];
    [self.view addSubview:rightView];
    [self.view addSubview:bottomView];
    
    // 关闭系统的自定义布局
    leftView.translatesAutoresizingMaskIntoConstraints = NO;
    rightView.translatesAutoresizingMaskIntoConstraints = NO;
    bottomView.translatesAutoresizingMaskIntoConstraints = NO;
    
    // leftView.top = self.view.top + 20
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:leftView
                                                          attribute:NSLayoutAttributeTop
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeTop
                                                         multiplier:1
                                                           constant:20]];
    // leftView.Left = self.view.left + 20
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:leftView
                                                          attribute:NSLayoutAttributeLeft
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeLeft
                                                         multiplier:1
                                                           constant:20]];
    // rightView.top = leftView.top
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:rightView
                                                          attribute:NSLayoutAttributeTop
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:leftView
                                                          attribute:NSLayoutAttributeTop
                                                         multiplier:1
                                                           constant:0]];
    // rightView.Left = leftView.right + 20
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:rightView
                                                          attribute:NSLayoutAttributeLeft
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:leftView
                                                          attribute:NSLayoutAttributeRight
                                                         multiplier:1
                                                           constant:20]];
    // rightView.Right = self.view.Right - 20
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:rightView
                                                          attribute:NSLayoutAttributeRight
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeRight
                                                         multiplier:1
                                                           constant:-20]];
    // rightView.Height = leftView.Height
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:rightView
                                                          attribute:NSLayoutAttributeHeight
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:leftView
                                                          attribute:NSLayoutAttributeHeight
                                                         multiplier:1
                                                           constant:0]];
    // rightView.Width = leftView.Width
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:rightView
                                                          attribute:NSLayoutAttributeWidth
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:leftView
                                                          attribute:NSLayoutAttributeWidth
                                                         multiplier:1
                                                           constant:0]];
    // bottomView.Left = self.view.Left + 20
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:bottomView
                                                          attribute:NSLayoutAttributeLeft
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeLeft
                                                         multiplier:1
                                                           constant:20]];
    // bottomView.Right = self.view.Right - 20
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:bottomView
                                                          attribute:NSLayoutAttributeRight
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeRight
                                                         multiplier:1
                                                           constant:-20]];
    // bottomView.Top = leftView.Bottom + 20
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:bottomView
                                                          attribute:NSLayoutAttributeTop
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:leftView
                                                          attribute:NSLayoutAttributeBottom
                                                         multiplier:1
                                                           constant:20]];
    // bottomView.Height = leftView.Height
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:bottomView
                                                          attribute:NSLayoutAttributeHeight
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:leftView
                                                          attribute:NSLayoutAttributeHeight
                                                         multiplier:1
                                                           constant:0]];
    // bottomView.Bottom = self.view.bottom - 20
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:bottomView
                                                          attribute:NSLayoutAttributeBottom
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeBottom
                                                         multiplier:1
                                                           constant:-20]];
}

创建可视化语言描述的约束

待续...

原文地址:https://www.cnblogs.com/weixiaochao/p/6739696.html