zoukankan      html  css  js  c++  java
  • AutoLayout代码布局使用大全—一种全新的布局思想

     

    相信ios8出来之后,不少的ios程序员为了屏幕的适配而烦恼。相信不少的人都知道有AutoLayout

    这么个玩意可以做屏幕适配,事实上,AutoLayout不仅仅只是一个为了多屏幕适配的工具,

    它真正的意义所在是给了程序员一种全新的布局思想。

       本文主要依据真实项目实例从三个方向全方位讲解AutoLayout的使用大全。

       一。AutoLayout布局原理和语法

       二。约束冲突和AutoLayout动画处理

       三。AutoLayout布局思想,约束链的控制。

       本文讲解的内容和代码主要依赖于一个名为UIView+AutoLayout的分类。文章末尾将会附上下载链接。

       一。AutoLayout布局原理和语法

         笔者在写这篇文章之前,阅读过不少关于AutoLayout教程的文章。其中有一句话尤为深刻,

    学习AutoLayout之前,必须要完全抛弃传统的frame属性,先完成思想的扭转学习起来方能事半功倍。

          AutoLayout是苹果ios6出来的东西,与传统的Frame属性不同。每一个view对象都有一个frame属性,

    frame属于CGrect对象,通过苹果的Api可以得知,CGrect其实是一个结构体。

    struct CGRect {

     CGPoint origin;

     CGSize size;

    };

    typedef struct CGRect CGRect;一个是控制坐标的CGPoint,一个是控制大小的CGSize。

       而AutoLayout是通过约束来实现布局的。一个view一旦使用了AutoLayout约束,

    那么它的frame将永远都是0.

       所以在使用AutoLayout之前需要两个准备工作。

       1.设置

    translatesAutoresizingMaskIntoConstraints为NO。

       2.如果是viewControl则AutoLayout适配写在

    - (void)updateViewConstraints中。

     如果是view则AutoLayout适配写在

    - (void)updateConstraints中。实际上,这也正是AutoLayout好处之一,可以集中将一个controller和

    view的适配在一个方法中。

       AutoLayout语法主要分三类

        1.设置size。

        先来看看UIView+AutoLayout的实现。

    [ViewautoSetDimension:ALDimensionWidthtoSize:30];

        UIView+AutoLayout底层原生的实现

     NSLayoutConstraint *constraint = [NSLayoutConstraintconstraintWithItem:selfattribute:NSLayoutAttributeWidth

     relatedBy:NSLayoutRelationEqual 

    toItem:nilattribute:NSLayoutAttributeNotAnAttributemultiplier:0.0fconstant:size];

    [View addConstraint:constraint];

        任何一个AutoLayout语法都是通过创建一个NSLayoutConstraint约束对象添加到view的约束中去的。

    创建一个AutoLayout需要七个参数,他们分别是(1)WithItem:被约束对象  

    (2)第一个attribute:被约束对象的关系   (3)relatedBy:约束描述  (

    4)toItem:约束源   (5)第二个attribute:约束源的关系  (6)multiplier:约束系数 

     (7)constant:约束常数

        在官方的api中,对约束有一个计算公式

    /* Create constraints explicitly.  Constraints are of the form "view1.attr1 = view2.attr2 * multiplier + constant" 

       下面具体讲解参数在NSLayoutConstraint API中的对应属性。

       

    typedefNS_ENUM(NSInteger, NSLayoutAttribute) {

        NSLayoutAttributeLeft =1,

        NSLayoutAttributeRight,

        NSLayoutAttributeTop,

        NSLayoutAttributeBottom,

        NSLayoutAttributeLeading,

        NSLayoutAttributeTrailing,

        NSLayoutAttributeWidth,

        NSLayoutAttributeHeight,

        NSLayoutAttributeCenterX,

        NSLayoutAttributeCenterY,

        NSLayoutAttributeBaseline,

        NSLayoutAttributeLastBaseline =NSLayoutAttributeBaseline,

        NSLayoutAttributeFirstBaselineNS_ENUM_AVAILABLE_IOS(8_0),

        

        

        NSLayoutAttributeLeftMarginNS_ENUM_AVAILABLE_IOS(8_0),

        NSLayoutAttributeRightMarginNS_ENUM_AVAILABLE_IOS(8_0),

        NSLayoutAttributeTopMarginNS_ENUM_AVAILABLE_IOS(8_0),

        NSLayoutAttributeBottomMarginNS_ENUM_AVAILABLE_IOS(8_0),

        NSLayoutAttributeLeadingMarginNS_ENUM_AVAILABLE_IOS(8_0),

        NSLayoutAttributeTrailingMarginNS_ENUM_AVAILABLE_IOS(8_0),

        NSLayoutAttributeCenterXWithinMarginsNS_ENUM_AVAILABLE_IOS(8_0),

        NSLayoutAttributeCenterYWithinMarginsNS_ENUM_AVAILABLE_IOS(8_0),

        

        NSLayoutAttributeNotAnAttribute =0

    };

     
     
    以上是官方API对约束关系的描述,其中NSLayoutAttributeLeading,NSLayoutAttributeTrailing,实际上等同于left和right,据说是阿拉伯国家的使用习惯。
     可以根据以上枚举看出约束关系主要就是上下左右,宽度,高度,横坐标中心,纵坐标中心。
     
     

    typedefNS_ENUM(NSInteger, NSLayoutRelation) {

        NSLayoutRelationLessThanOrEqual = -1,

        NSLayoutRelationEqual =0,

        NSLayoutRelationGreaterThanOrEqual =1,

    };

      约束描述主要就是<= == >=  主要是用于不确定大小和坐标的约束,autolayout适配的灵活性和动态性主要来源于这个约束关系。
      约束系数multiplier和约束常数constant主要是计算约束关系最终结果的,遵循公式"view1.attr1 = view2.attr2 * multiplier + constant"
     
      以上就是所有布局的约束来源,可以看到使用起来非常的方便,由于要想准确的将一个View动态布局,
    有时候往往需要设置好几个约束来定位view的位置,所以这种代码写起来往往比设置frame更加的冗长,
    好在文文介绍的UIView+AutoLayout可以替你分担。
       
      回归主题,通过以上代码可以看到,由于只需要设置一个view的大小,所以不需要约束源,toItem
    设为nil,那么约束源的关系自然就是没有关系了,第二个Attribute设为NSLayoutAttributeNotAnAttribute。
       按照这种思维,其实我们就可以动态绑定一个view和另一个view的大小,实际上却很少这么用,
    为什么呢?之后会讲到。
     
       2.位置间的约束
       先来看看UIView+AutoLayout的实现。
       [View1autoPinEdge:ALEdgeLefttoEdge:ALEdgeLeftofView:View1withOffset:5];
       UIView+AutoLayout底层原生的实现

    NSLayoutConstraint *constraint = [NSLayoutConstraintconstraintWithItem:self

    attribute:NSLayoutAttributeLeftrelatedBy:NSLayoutRelationEqual
    toItem:View2attribute:NSLayoutAttributeLeftmultiplier:1.0fconstant:5];

    [View1 addConstraint:constraint];

    根据上文讲解的各参数的含义可知,以上方法的意思就是约束view1的最左边到view2的最左边的距离是5(因为约束系数是1).

    3.约束对齐

    先来看看UIView+AutoLayout的实现。

    [view1autoAlignAxisToSuperviewAxis:ALAxisVertical];

     UIView+AutoLayout底层原生的实现

       NSLayoutConstraint *constraint = [NSLayoutConstraintconstraintWithItem:selfattribute:NSLayoutAttributeCenterX 

    relatedBy:NSLayoutRelationEqua toItem:view1.superview

    attribute:NSLayoutAttributeCenterXmultiplier:1.0fconstant:0.0f];

    根据上文讲解的各参数的含义可知,以上方法的意思就是约束view1的横坐标中心在view1的父view中居中.


    因为前文说过,所有的约束都是创建一个相同的NSLayoutConstraint对象来实现。所以代码都是大通小易。

    以下主要讲解一下UIView+AutoLayout这个分类的使用方法。

    根据以上的约束三种用途,UIView+AutoLayout对应的方法主体上也分为三类。

    1.设置size类(以autosetdimension开头)


    以下是ALDimension枚举

    typedefNS_ENUM(NSInteger, ALDimension) {

        ALDimensionWidth =NSLayoutAttributeWidth,     // the width of the view

        ALDimensionHeight =NSLayoutAttributeHeight    // the height of the view

    };

      2.位置约束(以autopin开头)

    以下是ALEdge枚举

    typedefNS_ENUM(NSInteger, ALEdge) {

        ALEdgeLeft =NSLayoutAttributeLeft,            // the left edge of the view

        ALEdgeRight =NSLayoutAttributeRight,          // the right edge of the view

        ALEdgeTop =NSLayoutAttributeTop,              // the top edge of the view

        ALEdgeBottom = NSLayoutAttributeBottom,        // the bottom edge of the view

        ALEdgeLeading = NSLayoutAttributeLeading,      // the leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic)

        ALEdgeTrailing = NSLayoutAttributeTrailing     // the trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic)

    };

     

      3.约束对齐(autoAlign开头)

    以下是ALAxis枚举

    typedefNS_ENUM(NSInteger, ALAxis) {

        ALAxisVertical = NSLayoutAttributeCenterX,     // a vertical line through the center of the view

        ALAxisHorizontal = NSLayoutAttributeCenterY,   // a horizontal line through the center of the view

        ALAxisBaseline = NSLayoutAttributeBaseline     // a horizontal line at the text baseline (not applicable to all views)

    };

     

    第一节小结:主要讲解了一下AutoLayout底层实现原理和UIView+AutoLayout的封装原理。


     二。AutoLayout约束冲突和动画处理



     以上的这个页面就是完全用的AutoLayout布局,整体结构就是这样,顶部的label1和右上角按钮button1,

    中间的imageview1和label2,下方两个cellview1和cellview2,再下面一个button2,

    最下面的小提示忽略不计。

    cellview1和cellview2是自定义的view,里面的一些image view和label都是它的子view。

    重点:当一个父view1有了一个子view2,并且子view2有了子view3,那么在约束view3的时候,

    如果它的父view不是最高层的那个view,那么view3的约束会对它的父view产生约束影响。  

    这一个规则确实让人很难摸清头脑,笔者这里不再详细说明,希望读者在遇到约束冲突的时候

    逐渐摸清这个规则。

    AutoLayout的动画处理。

    假如一个view使用了AutoLayout约束布局之后,这个时候如果对这个view做一个动画处理,

    按照传统的做法是改变它的一些属性,在平移动画中主要是改变它的frame坐标,

    但是在AutoLayout中frame都是0应该如何处理呢。这里笔者由难到易提供三种解决方案。

    1.使用[self.viewlayoutIfNeeded]方法动态刷新约束,笔者认为这个对初学AutoLayout的人

    来说是最难的。

    2.改变view的bounds属性。这个网上有资料,在AutoLayout中bounds属性是有效的。

    这个可能相对好解决一点。

    3.改变view的transform属性,比如说网上平移10个距离,可以这样写self.transform = CGAffineTransformMakeTranslation(0, -10); 相信这个是最简单也是最好处理的了。

     三。AutoLayout布局思想,约束链的控制

      

     还是使用这个页面加上UIView+AutoLayout来详细讲解。

       比如说我要布局cellView1中最左边那个招商银行logo的imageview。

       使用UIView+AutoLayout可以这样写。

    [imageview autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self withOffset:5];

    [imageview autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:self withOffset:5];

    [imageview autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self withOffset:5];

    [imageview autoPinEdge:ALEdgeRight toEdge:ALEdgeLeft ofView:self withOffset:35];

       基本上任何的view都可以分别对它的上下左右使用四个位置约束来确定它的位置,

    这四行代码的意思本别就是

       imageview顶部距离父view顶部间距5,image view底部距离父view底部间距5,

    imageview左侧距离父view左侧间距5,imageview右侧距离父view左侧间距35,

        这样子的话,假如父view的高度是40的话,那么imageview的size不需要设置,

    自然而然的被这四个约束为(30,30).

        这看起来没什么不妥,实际上已经是约束过度了。当父view的高度发生变更的时候,

    imageview的高度就会因为顶部和底部的约束而动态计算,假如父view高50,

    那么imageview的size就是(30,40),这个时候假如是一张方形图片就会变形,

    实际上这并不是AutoLayout的精髓。

       

        再看下面这种约束方式

        

     [ImageViewautoSetDimensionsToSize:CGSizeMake(30,30)];

     [ImageViewautoPinEdge:ALEdgeLefttoEdge:ALEdgeLeftofView:selfwithOffset:5];

     [ImageViewautoAlignAxisToSuperviewAxis:ALAxisHorizontal];

        这三行代码的意思是,约束imageview的固定大小(30,30),

    约束imageview左侧距离父view左侧间距为5,约束imageview的纵坐标轴线与父view纵坐标轴线对齐。

    通过以上三个约束不难看出,无论父view如果改变大小和位置,

    image自身的形状和父view的相对位置都是固定的。

       

        总结:AutoLayout真正的语法只有一个方法,只要理解这个方法的七个参数分别所代表的含义就不难理解AutoLayout的实现原理。所以对于程 序员来说,重要的并不是这种布局方式用代码写起来有多么的冗长,因为有不少的三方库可以帮助你简写代码,实际上我们真正要掌握的是AutoLayout的 这种布局思想,心中对一个view布局的时候心中都应该要有一条约束链,只有这样,你的布局约束将会越来越精简,越来越准确,也越来越适配。

       因为笔者自己也是刚刚接触AutoLayout,以上只是粗略的讲解一下自身的学习心得,笔者极力推荐UIView+AutoLayout这个库来使用 AutoLayout,因为封装都比较形象,并且接近底层,对理解AutoLayout的原理和掌握内涵更加的有益。

  • 相关阅读:
    LeetCode Missing Number (简单题)
    LeetCode Valid Anagram (简单题)
    LeetCode Single Number III (xor)
    LeetCode Best Time to Buy and Sell Stock II (简单题)
    LeetCode Move Zeroes (简单题)
    LeetCode Add Digits (规律题)
    DependencyProperty深入浅出
    SQL Server存储机制二
    WPF自定义RoutedEvent事件示例代码
    ViewModel命令ICommand对象定义
  • 原文地址:https://www.cnblogs.com/bugismyalllife/p/4884277.html
Copyright © 2011-2022 走看看