zoukankan      html  css  js  c++  java
  • 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]];
    }
    
    

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

    待续...

  • 相关阅读:
    布局(layout)文件图形界面不能显示:An error has occurred. See error log for more details. java.lang.NullPointe
    Mac下无法推出硬盘
    Excel导入导出数据库(MVC)
    json导入数据库
    XML导入数据库
    Excel表格导入数据库
    Lambda高级查询
    Linq高级查询
    多线程
    反射
  • 原文地址:https://www.cnblogs.com/weixiaochao/p/6739696.html
Copyright © 2011-2022 走看看