美文网首页
iOS-屏幕适配

iOS-屏幕适配

作者: Imkata | 来源:发表于2020-08-10 11:26 被阅读0次

    一. 屏幕适配历史

    1. iphone3gs-4s
      frame直接写死。
    2. ipad:autoresizing
      根据父控件的frame发生改变,子控件跟着一起改变。
    3. iphone5-iPhone5s:autolayout
      自动布局(是针对xib进行使用的)。
    4. iPhone6和iphone6p:sizeClass
      发现屏幕变得太多样,界面大统一了(是针对storyboard进行使用的)。

    更多关于屏幕适配可参考:
    一篇文章详解iOS之AutoResizing、AutoLayout、sizeClass来龙去脉
    iOS8中SizeClass的使用

    二. AutoLayout

    1. AutoLayout简介

    在以前的iOS程序中,是如何设置布局UI界面的?

    • 经常编写大量的坐标计算代码
    • 为了保证在3.5 inch和4.0 inch屏幕上都能有完美的UI界面效果,有时还需要分别为两种屏幕编写不同的坐标计算代码(即传说中的“屏幕适配”)。

    什么是Autolayout?

    • Autolayout是一种“自动布局”技术,专门用来布局UI界面的
    • Autolayout自iOS 6开始引入,由于Xcode 4的不给力,当时并没有得到很大推广
    • 自iOS 7(Xcode 5)开始,Autolayout的开发效率得到很大的提升
    • 苹果官方也推荐开发者尽量使用Autolayout来布局UI界面
    • Autolayout能很轻松地解决屏幕适配的问题

    关于Autoresizing:

    • 在Autolayout之前,有Autoresizing可以作屏幕适配,但局限性较大,有些任务根本无法完成
    • 相比之下,Autolayout的功能比Autoresizing强大很多

    Autolayout的2个核心概念:

    • 参照
    • 约束

    2. Autolayout的警告和错误

    1. 警告:黄色向右的箭头
      控件的frame不匹配所添加的约束,比如约束控件的宽度为100,而控件现在的宽度是110。
    2. 错误:红色向右的箭头
      缺乏必要的约束,比如只约束了宽度和高度,没有约束具体的位置。
    3. 两个约束冲突黄色警告
      比如,1个约束控件的宽度为100,1个约束控件的宽度为110。

    3. 约束添加的原则

    在创建约束之后,需要将其添加到作用的view上,在添加时要注意目标view需要遵循以下规则:

    1. 对于两个同层级view之间的约束关系,添加到它们的父view上
    原则1.png
    1. 对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上
    原则2.png
    1. 对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上
    原则3.png

    三. VFL语言

    什么是VFL语言?

    • VFL全称是Visual Format Language,翻译过来是“可视化格式语言”
    • VFL是苹果公司为了简化Autolayout的编码而推出的抽象语言

    1. 代码实现Autolayout的步骤

    1. 利用NSLayoutConstraint类创建具体的约束对象
    2. 添加约束对象到相应的view上
    - (void)addConstraint:(NSLayoutConstraint*)constraint;
    - (void)addConstraints:(NSArray*)constraints;
    
    1. 代码实现Autolayout的注意点
      ① 要先禁止autoresizing功能,设置view的下面属性为NO。
      view.translatesAutoresizingMaskIntoConstraints=NO;
      ② 添加约束之前,一定要保证相关控件都已经在各自的父控件上。
    2. 不用再给view设置frame

    2. NSLayoutConstraint类

    一个NSLayoutConstraint对象就代表一个约束。

    创建约束对象的常用方法:

    // view1:要约束的控件
    // attr1:约束的类型(做怎样的约束)
    // relation:与参照控件之间的关系
    // view2:参照的控件
    // attr2:约束的类型(做怎样的约束)
    // multiplier:乘数
    // c:常量 
    +(id)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
    

    3. VFL的使用

    使用VFL来创建约束数组

    // format:VFL语句
    // opts:约束类型
    // metrics:VFL语句中用到的具体数值
    // views:VFL语句中用到的控件
    + (NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
    

    创建一个字典(内部包含VFL语句中用到的控件)的快捷宏定义NSDictionaryOfVariableBindings(...)

    VFL示例:

    // canelButton宽72,acceptButton宽50,它们之间间距12
    H:[cancelButton(72)]-12-[acceptButton(50)]
    
    // wideView宽度大于等于60point,该约束条件优先级为700(优先级最大值为1000,优先级越高的约束越先被满足)
    H:[wideView(>=60@700)]
    
    // 竖直方向上,先有一个redBox,其下方紧接一个高度等于redBox高度的yellowBox
    V:[redBox]-[yellowBox(==redBox)]
    
    // 水平方向上,Find距离父view左边缘默认间隔宽度,之后是FindNext距离Find间隔默认宽度;再之后是宽度不小于20的FindField,它和FindNext以及父view右边缘的间距都是默认宽度。(竖线“|”表示superview的边缘) 
    H:|-10-[Find]-[FindNext]-[FindField(>=20)]-|
    

    4. VFL练习

    练习①

    //添加两个view蓝色在上.红色在下,红色的宽度是蓝色的一半
    - (void)test1
    {
        // 1.添加控件
        UIView *blueView = [[UIView alloc] init];
        blueView.backgroundColor = [UIColor blueColor];
        blueView.translatesAutoresizingMaskIntoConstraints = NO;
        [self.view addSubview:blueView];
        
        UIView *redView = [[UIView alloc] init];
        redView.backgroundColor = [UIColor redColor];
        redView.translatesAutoresizingMaskIntoConstraints = NO;
        [self.view addSubview:redView];
        
        // 2.VFL生成约束
        NSArray *conts = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[blueView]-20-|" options:0 metrics:nil views:@{@"blueView" : blueView}];
        [self.view addConstraints:conts];
        
        //右对齐
        NSArray *conts2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[blueView(40)]-20-[redView(==blueView)]" options:NSLayoutFormatAlignAllRight metrics:nil views:@{@"blueView" : blueView, @"redView" : redView}];
        [self.view addConstraints:conts2];
        //设置红色的宽度是蓝色的一半,(设置一个view是另外一个view的多少倍的时候必须要用下面的方法)
        NSLayoutConstraint *redWidth = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0.0];
        [self.view addConstraint:redWidth];
    }
    

    效果图如下:

    练习1.png

    练习②

    //添加两个按钮,左边,右边,下边距离相等都是20
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        // 1.添加控件
        UIView *blueView = [[UIView alloc] init];
        blueView.backgroundColor = [UIColor blueColor];
        blueView.translatesAutoresizingMaskIntoConstraints = NO;
        [self.view addSubview:blueView];
        
        UIView *redView = [[UIView alloc] init];
        redView.backgroundColor = [UIColor redColor];
        redView.translatesAutoresizingMaskIntoConstraints = NO;
        [self.view addSubview:redView];
        
        // 2.VFL生成约束
        NSDictionary *mertrics = @{@"margin" : @20}; // 参数\数值
        NSDictionary *views = NSDictionaryOfVariableBindings(blueView, redView);//view
        NSArray *conts = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-margin-[blueView]-margin-[redView(==blueView)]-margin-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:mertrics views:views];
        //NSLayoutFormatAlignAllTop上对齐
        NSArray *conts2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[blueView(==blueHeight)]-margin-|" options:0 metrics:@{@"blueHeight" : @40, @"margin" : @20} views:views];
        //竖直方向高度相等
        [self.view addConstraints:conts];
        [self.view addConstraints:conts2];
    }
    

    效果图如下:

    练习2.png

    四. 补充

    1. 自动包住文字内容

    给label添加Autolayout之后,label的尺寸会根据里面的内容自动包裹文字,不会有空白,以前要算,现在不用算了

    在没有Autolayout之前,UILabel的文字内容总是居中显示,导致顶部和底部会有一大片空白区域

    没有Autolayout.png

    有了Autolayout之后,UILabel的bounds默认会自动包住所有的文字内容,顶部和底部不再有空缺区域

    有了Autolayout.png

    2. 通过约束添加动画

    storyboard里面的控件如下:

    添加动画.png

    代码如下:

    //  MJViewController.m
     
    #import "MJViewController.h"
     
    @interface MJViewController ()
    @property (weak, nonatomic) IBOutlet UILabel *textLabel;
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftMargin;
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *width;
    @property (weak, nonatomic) IBOutlet UIView *redView;
     
    @end
     
    @implementation MJViewController
     
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    }
     
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        self.leftMargin.constant = 100;
        self.width.constant = 200;
        
        [UIView animateWithDuration:2.0 animations:^{
            [self.view layoutIfNeeded];
            [self.redView layoutIfNeeded];
        }];
        
        self.textLabel.text = @"sdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlfsdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlfsdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlfsdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlfsdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlf";
    }
    @end
    

    相关文章

      网友评论

          本文标题:iOS-屏幕适配

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