//
//  MyBaseLayout.h
//  MyLayout
//
//  Created by oybq on 15/6/14.
//  Copyright (c) 2015年 YoungSoft. All rights reserved.
//

#import "MyBorderline.h"
#import "MyLayoutTraits.h"

/*
 几种视图类型的定义：
1.布局视图：    就是从MyBaseLayout派生而出的视图，目前MyLayout中一共有：线性布局、框架布局、相对布局、表格布局、流式布局、浮动布局、路径布局、栅格布局、弹性布局9种布局。 布局视图也是一个视图。
2.非布局视图：  除上面说的7种布局视图外的所有视图和控件。
3.布局父视图：  如果某个视图的父视图是一个布局视图，那么这个父视图就是布局父视图。
4.非布局父视图：如果某个视图的父视图不是一个布局视图，那么这个父视图就是非布局父视图。
5.布局子视图：  如果某个视图的子视图是一个布局视图，那么这个子视图就是布局子视图。
6.非布局子视图：如果某个视图的子视图不是一个布局视图，那么这个子视图就是非布局子视图。
*/

@interface UIView (MyLayoutExt)<MyViewTraits>

/*
   视图的布局位置对象属性，用来指定视图水平布局位置和垂直布局位置。对于一个视图来说我们可以使用frame属性中的origin部分来确定一个视图的左上方位在父视图的位置。这种方法的缺点是需要明确的指定一个常数值，以及需要进行位置的计算，缺乏可扩展性以及可维护性。因此对于布局视图里面的子视图来说我们将不再通过设置frame属性中的origin部分来确定位置，而是通过视图扩展的布局位置对象属性来设置视图的布局位置。子视图的布局位置对象在不同类型的布局视图里和不同的场景下所表达的意义以及能设置的值类型将会有一定的差异性。下面的表格将列出这些差异性：
 
 +--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------+
 |                    |Scene1            | Scene2               |Scene3         |Scene4     |Scene5              |Scene6 |Scene7 |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |Vert MyLinearLayout |   L,R,CX         | T,B                  | L,R,CX,T,B    |    -      |    -               | L,R   | -     |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |Horz MyLinearLayout |   T,B,CY         | L,R                  | L,R,T,B,CY    |    -      |    -               |  -    |T,B    |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |Vert MyTableLayout  |   T,B,CY         | L,R                  | L,R,T,B,CY    |    -      |    -               |  -    |T,B    |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |Horz MyTableLayout  |   L,R,CX         | T,B                  | L,R,CX,T,B    |    -      |    -               | L,R   |  -    |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |MyFrameLayout       |   ALL            |  -                   | L,R,T,B,CX,CY |    -      |    -               |  -    | -     |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |MyRelativeLayout    |   ALL            |  -                   |  -            |   ALL     |   CX,CY            | L,R   |T,B    |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |Vert MyFlowLayout   |   -              | T,B,R,L              |  -            |   -       |   -                | -     | -     |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |Horz MyFlowLayout   |   -              | T,B,R,L              |  -            |   -       |    -               | -     | -     |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |Vert MyFloatLayout  |   -              | T,B,R,L              |  -            |   -       |    -               | -     | -     |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |Horz MyFloatLayout  |   -              | T,B,R,L              |  -            |   -       |    -               | -     | -     |
 |--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------|
 |MyPathLayout        |   -              | T,L                  |  -            |   -       |    -               | -     | -     |
 +--------------------+------------------+----------------------+---------------+-----------+--------------------+-------+-------+

 *上面表格中L=leftPos, R=rightPos, T=topPos, B=bottomPos,CX=centerXPos,CY=centerYPos,ALL是所有布局位置对象,-表示不支持。
 *Scene表示在这种场景下支持的布局位置对象的种类，以及设置的值所表达的意义。
    比如上表中的行Vert MyLinearLayout,列Scene1中的值 L,R,CX 的意思是垂直线性布局下的子视图的leftPos,rightPos,centerXPos的位置值设置为数值时表示的是子视图的左右边距以及水平中心点在父布局下的中心点边距。
 
 Scene1:布局位置对象的值设置为数值,且表示他离父视图的边距。所谓边距就是指子视图跟父视图之间的距离。
     比如A.leftPos.equalTo(10)表示A的左边距是10，也就是A视图的左边和父视图的左边距离10个点。
 
 Scene2:布局位置对象的值设置为数值,且表示的是视图之间的间距。所谓间距就是指视图和其他视图之间的距离。这里要注意边距和间距的区别，边距是子视图和父视图之间的距离，间距是子视图和兄弟视图之间的距离。
     比如垂直线性布局视图L分别添加了A,B两个子视图则设置A.topPos.equalTo(10),A.bottomPos.equalTo(10),B.topPos.equalTo(10)的意思是A的顶部间距是10，底部间距也是10。视图B的顶部间距10。这样视图B和视图A之间的间距就是20
 Scene3:布局位置对象的值设置为大于0且小于1的数值,表示视图之间的相对间距值或者边距值。
      视图的相对间距的最终距离 = (布局视图尺寸 - 所有固定尺寸和固定间距之和) * 当前视图的相对间距值 /(所有子视图相对间距的总和)
      视图的相对边距的最终距离 = 布局视图尺寸 * 当前视图的相对边距值

 
 Scene4:布局位置对象的值设置为MyLayoutPos对象，表示某个位置依赖于另外一个位置。只有在相对布局中的子视图的布局位置对象的位置值才能设置为MyLayoutPos对象。
    比如： A.leftPos.equalTo(B.rightPos)表示视图A的左边等于视图B的右边。
 
 Scene5:布局位置对象的值设置为NSArray<MyLayoutPos>数组对象，表示一组视图整体居中。只有在相对布局中的子视图的centerXPos或者centerYPos中的位置值才可以被设置为这种值。
    比如：A.centerXPos.equalTo(@[B.centerXPos,C.centerXPos])表示A,B,C三个子视图在相对布局中整体水平居中。
 
 Scene6:当同时设置了leftPos和rightPos左右边距后就能确定出视图的布局宽度了，这样就不需要为子视图指定布局宽度值了。需要注意的是只有同时设置了左右边距才能确定视图的宽度，而设置左右间距时则不能。
    比如：某个布局布局视图的宽度是100，而某个子视图的leftPos.equalTo(@10),rightPos.equalTo(@20).则这个子视图的宽度=70(100-10-20)
 
 Scene7:当同时设置了topPos和bottomPos上下边距后就能确定出视图的布局高度了，这样就不需要为子视图指定布局高度值了。需要注意的是只有同时设置了上下边距才能确定视图的高度，而设置上下间距是则不能。
    比如：某个布局布局视图高度是100，而某个子视图的topPos.equalTo(@10),bottomPos.equalTo(@20).则这个子视图的高度=70(100-10-20)

 另外如果某个布局视图是视图控制器的根视图，那么你可以将布局视图里面的第一个子视图的topPos设置为： topPos.equalTo(@(MyLayoutPos.safeAreaMargin)) 或者最后一个子视图的bottomPos设置为bottomPos.equalTo(@(MyLayoutPos.safeAreaMargin)） 这样不管视图控制器所在的导航条是否半透明，总是会显示在导航条下面的位置。。
 
*/

/**
 *视图的上边布局位置对象。(top layout position of the view.)
 */
@property (nonatomic, readonly) MyLayoutPos *topPos;

/**
 *视图的头部布局位置对象,对于非阿拉伯国家就是左边，对于阿拉伯国家就是右边(leading layout position of the view.)
 */
@property (nonatomic, readonly) MyLayoutPos *leadingPos;

/**
 *视图的下边布局位置对象。(bottom layout position of the view.)
 */
@property (nonatomic, readonly) MyLayoutPos *bottomPos;

/**
 *视图的尾部布局位置对象,对于非阿拉伯国家就是右边，对于阿拉伯国家就是左边。(trailing layout position of the view.)
 */
@property (nonatomic, readonly) MyLayoutPos *trailingPos;

/**
 *视图的水平中心布局位置对象。(horizontal center layout position of the view.)
 */
@property (nonatomic, readonly) MyLayoutPos *centerXPos;

/**
 *视图的垂直中心布局位置对象。(vertical center layout position of the view.)
 */
@property (nonatomic, readonly) MyLayoutPos *centerYPos;

/**
 *视图的左边布局位置对象。如果您不考虑国际化布局就用这个属性，如果考虑国际化则请用leadingPos(left layout position of the view.)
 */
@property (nonatomic, readonly) MyLayoutPos *leftPos;

/**
 *视图的右边布局位置对象。如果您不考虑国际化布局就用这个属性，如果考虑国际化则请用trailingPos(right layout position of the view.)
 */
@property (nonatomic, readonly) MyLayoutPos *rightPos;

/**
 *视图的基线位置对象。目前只支持相对布局里面的视图的设置并且调用视图或者被调用视图都只能是UILabel和UITextField和UITextView三个只支持单行文本的视图。
 */
@property (nonatomic, readonly) MyLayoutPos *baselinePos;

/*
 下面定义的八个属性是上面定义的leftPos,topPos,rightPos,bottomPos,centerXPos,centerYPos的equalTo设置NSNumber类型的值时的简化版本。
 比如：
 v.myLeft = 10    <==>   v.leftPos.equalTo(@10)
 v.myRight = 20   <==>   v.rightPos.equalTo(@20)
 v.myCenterX = 0  <==>   v.centerXPos.equalTo(@0)


 这八个属性的值最好别用于读取，而只是单纯用于设置
 
 这要再次区分一下边距和间距和概念，所谓边距是指子视图距离父视图的距离；而间距则是指子视图距离兄弟视图的距离。myLeft,myRight,myTop,myBottom这几个子视图的扩展属性即可用来表示边距也可以用来表示间距，这个要根据子视图所归属的父布局视图的类型而确定：
 
 1.垂直线性布局MyLinearLayout中的子视图： myLeft,myRight表示边距，而myTop,myBottom则表示间距。
 2.水平线性布局MyLinearLayout中的子视图： myLeft,myRight表示间距，而myTop,myBottom则表示边距。
 3.表格布局中的子视图：                  myLeft,myRight,myTop,myBottom的定义和线性布局是一致的。
 4.框架布局MyFrameLayout中的子视图：     myLeft,myRight,myTop,myBottom都表示边距。
 5.相对布局MyRelativeLayout中的子视图：  myLeft,myRight,myTop,myBottom都表示边距。
 6.流式布局MyFlowLayout中的子视图：      myLeft,myRight,myTop,myBottom都表示间距。
 7.浮动布局MyFloatLayout中的子视图：     myLeft,myRight,myTop,myBottom都表示间距。
 8.路径布局MyPathLayout中的子视图：      myLeft,myRight,myTop,myBottom即不表示间距也不表示边距，它表示自己中心位置的偏移量。
 9.非布局父视图中的布局子视图：           myLeft,myRight,myTop,myBottom都表示边距。
 10.非布局父视图中的非布局子视图：         myLeft,myRight,myTop,myBottom的设置不会起任何作用，因为MyLayout已经无法控制了。
 
 再次强调的是：
 1. 如果同时设置了左右边距就能决定自己的宽度，同时设置左右间距不能决定自己的宽度！
 2. 如果同时设置了上下边距就能决定自己的高度，同时设置上下间距不能决定自己的高度！
*/

/**
 *视图上边的布局位置, 是topPos.equalTo方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Top layout position of the view. Equivalent to topPos.equalTo(NSNumber). Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myTop;

/**
 *视图头部的布局位置, 是leadingPos.equalTo方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Leading layout position of the view. Equivalent to leadingPos.equalTo(NSNumber).Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myLeading;

/**
 *视图下边的布局位置, 是bottomPos.equalTo方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Bottom layout position of the view. Equivalent to bottomPos.equalTo(NSNumber).Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myBottom;

/**
 *视图尾部的布局位置, 是trailingPos.equalTo方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Trailing layout position of the view. Equivalent to trailingPos.equalTo(NSNumber).Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myTrailing;

/**
 *视图水平中心布局位置, 是centerXPos.equalTo方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Horizontal center layout position of the view. Equivalent to centerXPos.equalTo(NSNumber).Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myCenterX;

/**
 *视图垂直中心布局位置, 是centerYPos.equalTo方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Vertical center layout position of the view. Equivalent to centerYPos.equalTo(NSNumber).Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myCenterY;

/**
 *视图中心布局位置, 是myCenterX,myCenterY方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Center layout position of the view. Equivalent to set myCenterX and myCenterY .Only for setting, not for getting.
 */
@property (nonatomic, assign) CGPoint myCenter;

/**
 *视图左边的布局位置, 是leftPos.equalTo方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Left layout position of the view. Equivalent to leftPos.equalTo(NSNumber).Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myLeft;

/**
 *视图右边的布局位置, 是rightPos.equalTo方法的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Right layout position of the view. Equivalent to rightPos.equalTo(NSNumber).Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myRight;

/**
 *视图四边的布局位置, 是myLeading,myTop,myTrailing,myBottom的简化版本。此属性只用于赋值不用于读取！
 */
/**
 *Boundary layout position of the view. Equivalent to myLeading,myTop,myTrailing,myBottom set to the same number.Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myMargin;

/**
 *leading and trailing margin of the view to the superview. Equivalent to myLeading,myTrailing set to the same number.Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myHorzMargin;

/**
 *top and bottom margin of the view to the superview. Equivalent to myTop,myBottom set to the same number.Only for setting, not for getting.
 */
@property (nonatomic, assign) CGFloat myVertMargin;

/*
 视图的布局尺寸对象MyLayoutSize,用于设置视图的宽度和高度尺寸。视图可以通过设置frame值来设置自身的尺寸，也可以通过设置widthSize和heightSize来
 设置布局尺寸，通过frame设置的结果会立即生效，而通过widthSize和heightSize设置则会在布局后才生效，如果同时设置了frame值和MyLayoutSize值则MyLayoutSize的设置值优先。
 
 其中的equalTo方法可用于设置布局尺寸的具体值：
 1.如果设置为NSNumber则表示布局尺寸是一个具体的数值。比如widthSize.equalTo(@20)表示视图的宽度设置为20个点。
 2.如果设置为MyLayoutSize则表示布局尺寸依赖于另外一个视图的布局尺寸。比如A.widthSize.equalTo(B.widthSize)表示A的宽度和B的宽度相等
 3.如果设置为NSArray<MyLayoutSize*>则表示视图和数组里面的视图均分布局视图的宽度或者高度。比如A.widthSize.equalTo(@[B.widthSize,C.widthSize])表示视图A,B,C三个视图均分父视图的宽度。
 4.如果设置为nil则表示取消布局尺寸的值的设置。
 
 其中的add方法可以用于设置布局尺寸的增加值，一般只和equalTo设置为MyLayoutSize和NSArray时配合使用。比如A.widthSize.equalTo(B.widthSize).add(20)表示视图A的宽度等于视图B的宽度再加上20个点。
 
 其中的multiply方法可用于设置布局尺寸放大的倍数值。比如A.widthSize.equalTo(B.widthSize).multiply(2)表示视图A的宽度是视图B的宽度的2倍。
 
 其中的min,max表示用来设置布局尺寸的最大最小值。比如A.widthSize.min(10).max(40)表示宽度的最小是10最大是40。
 
 下面的表格描述了在各种布局下的子视图的布局尺寸对象的equalTo方法可以设置的值。
 为了表示方便我们把：
     线性布局简写为L、垂直线性布局简写为L-V、水平线性布局简写为L-H 相对布局简写为R、表格布局简写为T、框架布局简写为FR、
     流式布局简写为FL、垂直流式布局简写为FL-V，水平流式布局简写为FL-H、浮动布局简写为FO、左右浮动布局简写为FO-V、上下浮动布局简写为FO-H、
     路径布局简写为P、全部简写为ALL，不支持为-，
 
 定义A为操作的视图本身，B为A的兄弟视图，P为A的父视图。
 +-------------+----------+--------------+---------------+------------+--------------+---------------+--------------+----------------------+
 | 对象 \ 值    | NSNumber |A.widthSize   |A.heightSize   |B.widthSize | B.heightSize |  P.widthSize  |P.heightSize  |NSArray<MyLayoutSize*>|
 +-------------+----------+--------------+---------------+------------+--------------+---------------+--------------+----------------------+
 |A.widthSize  | ALL      |ALL           |ALL            |ALL         | ALL          |ALL            |ALL           |R                     |
 +-------------+----------+--------------+---------------+------------+--------------+---------------+--------------+----------------------+
 |A.heightSize | ALL      |ALL           |ALL            |ALL         |ALL           |ALL            |ALL           |R                     |
 +-------------+----------+--------------+---------------+------------+--------------+---------------+--------------+----------------------+

  上表中所有的布局尺寸的值都支持设置为数值，而且所有布局下的子视图的宽度和高度尺寸都可以设置为等于自身的宽度和高度尺寸，布局库这里做了特殊处理，是不会造成循环引用的。比如：
    A.widthSize.equalTo(A.widthSize)，支持这种设置的原因是有时候比如希望某个UILabel的宽度是在其本身内容宽度的基础上再添加一个增加值，这时候就可以设置如下：
    A.widthSize.equalTo(A.widthSize).add(30);
    表示视图A的宽度总是视图内容的宽度+30，这样即使视图调用了sizeToFit方法来计算出包裹内容的宽度，但是最终的布局宽度还是会再增加30个点。
 
 */
/**
 the MyLayoutSize is layout dimension object object of the UIView. used to set the width and height of the View which is in Layout View
 */

/**
 *视图的宽度布局尺寸对象，可以通过其中的euqalTo方法来设置NSNumber,MyLayoutSize,NSArray<MyLayoutSize*>,MyLayoutMostSize,UIView,nil这六种值
 */
@property (nonatomic, readonly) MyLayoutSize *widthSize;

/**
 *视图的高度布局尺寸对象，可以通过其中的euqalTo方法来设置NSNumber,MyLayoutSize,NSArray<MyLayoutSize*>,MyLayoutMostSize,UIView,nil这六种值
 */
@property (nonatomic, readonly) MyLayoutSize *heightSize;

/*
 下面三个属性是上面widthSize,heightSize的equalTo设置NSNumber类型值的简化版本,表示设置视图的高度和宽度的布局尺寸。
 需要注意的是设置这三个值并不是直接设置frame里面的size的宽度和高度，而是设置的是布局尺寸的数值
 
 v.myWidth = 10    <=>   v.widthSize.equalTo(@10)
 v.myHeight = 20   <=>   v.heightSize.equalTo(@10)
 
 这三个属性的值最好别用于读取，而只是单纯用于设置
 */

/**
 *视图的宽度布局尺寸,是widthSize.equalTo方法的简化版本。此属性只用于赋值不用于读取！除了设置常规的数字外您还可以设置一些特殊的值：
 MyLayoutSize.wrap  表示宽度自适应
 MyLayoutSize.fill  表明宽度填充父视图剩余宽度
 MyLayoutSize.empty 表明清除宽度约束。
 */
@property (nonatomic, assign) CGFloat myWidth;

/**
 *视图的高度布局尺寸,是heightSize.equalTo方法的简化版本。此属性只用于赋值不用于读取！除了设置常规的数字外您还可以设置一些特殊的值：
 MyLayoutSize.wrap  表示高度自适应
 MyLayoutSize.fill  表明高度填充父视图剩余高度
 MyLayoutSize.empty 表明清除高度约束。
 */
@property (nonatomic, assign) CGFloat myHeight;

/**
 *视图的宽度高度布局尺寸,是myWidth,myHeight方法的简化版本。此属性只用于赋值不用于读取！
 */
@property (nonatomic, assign) CGSize mySize;

/**
 设置子视图的相对比重尺寸。也就是子视图的尺寸并不是一个绝对值而是一个相对值，在最终布局时系统会根据布局视图的剩余尺寸来将这个相对的值转化为绝对的值。通过对子视图设置相对的尺寸可以很方便的适配各种屏幕尺寸的设备，以便达到完美的布局效果。这个属性默认值是0表示不使用相对尺寸。weight属性的引入是参考android中的weight的概念而来的。
 
 目前只有在线性布局、表格布局、流式布局、浮动布局下的子视图设置weight才有效，相对布局、框架布局、路径布局里面的子视图不支持weight属性的设置。
 在不同的布局下的子视图的weight属性所表达的意义也有所差异：
 
 @note
 1.在线性布局和表格布局下：
 
 1.1. 当线性布局是垂直线性布局时这个属性用来设置子视图高度占用父线性布局剩余高度的比重，这样子视图就不需要明确的设定高度值。
 
 1.2. 当线性布局是水平线性布局时这个属性用来设置子视图宽度占用父线性布局剩余宽度的比重，这样子视图就不需要明确的设定宽度值。
 
 @code
 视图的真实尺寸值 = 布局视图剩余尺寸 * 当前视图的weight比重/(布局视图内所有设置了weight比重值的子视图比重之和)。
 @endcode
 
 对一个垂直线性布局举例来说：假设布局视图的高度是100，A子视图占据了20的固定高度，B子视图的weight设置为0.4，C子视图的weight设置为0.6 那么:
 @code
 A子视图的高度 = 20
 B子视图的高度 = (100-20)*0.4/(0.4+0.6) = 32
 C子视图的高度 = (100-20)*0.6/(0.4+0.6) = 48
 @endcode
 
 子视图设置weight属性时要注意如下几点：
 
 - 垂直线性布局必须指定明确的高度，而高度不能设置为自适应；水平线性布局必须指定明确的宽度，而不能使用wrapContentWidth属性。
 
 - 如果比重属性设置为0的话则表示视图的尺寸必须要明确的被指定，这也是默认值。
 
 - 线性布局里面的所有子视图的比重值的和不一定要求是1，比如线性布局里面两个视图的比重都设置为1和都设置为0.5以及都设置为0.1的意义是一样的，都是占用50%。
 
 @note
 2.在流式布局下：
 
 2.1. 当流式布局是垂直流式布局时这个属性用来设置子视图宽度占用父流式布局当前行的剩余宽度的比重，这样子视图就不需要明确的设定宽度值。
 
 2.2. 当流式布局是水平流式布局时这个属性用来设置子视图高度占用父流式布局当前列的剩余高度的比重，这样子视图就不需要明确的设定高度值。
 
 同时在数量约束和内容约束两种布局中视图设置的比重值在最终计算出真实尺寸时也是有差异的：
 
 @code
 数量约束流式布局内的视图的真实尺寸值 = 布局视图剩余尺寸 * 当前视图的weight比重/(视图所在行的所有设置了weight比重值的视图比重之和)。
 
 内容约束流式布局内的视图的真实尺寸值 = 布局视图剩余尺寸 * 当前视图的weight比重。
 
 对一个垂直数量约束流式布局举例来说：假设布局视图的宽度是100，A子视图占据了20的固定宽度，B子视图的weight设置为0.4，C子视图的weight设置为0.6 那么:
 A子视图的宽度 = 20
 B子视图的宽度 = (100-20)*0.4/(0.4+0.6) = 32
 C子视图的宽度 = (100-20)*0.6/(0.4+0.6) = 48
 
 对一个垂直内容约束流式布局举例来说：假设布局视图的宽度是100，A子视图占据了20的固定宽度，B子视图的weight设置为0.4，C子视图的weight设置为0.6 那么：
 A子视图的宽度 = 20
 B子视图的宽度 = (100-20)*0.4 = 32
 C子视图的宽度 = (100-20-32)*0.6 = 28.8
 @endcode
 
 
 @note
 3. 在浮动布局下：
 
 3.1. 当浮动布局的方向是垂直布局时，这个属性用来设置视图宽度占用当前浮动布局父视图剩余宽度的比重，这样视图就不需要明确的设定宽度值。
 
 3.2. 当浮动布局的方向是水平布局时，这个属性用来设置视图高度占用当前浮动布局父视图剩余高度的比重，这样子视图就不需要明确的设定高度值。
 
 @code
 视图的真实尺寸 = 布局父视图的剩余尺寸 * 视图的weight比重值。
 @endcode
 
 举例来说：假设一个垂直浮动布局视图的宽度是100，A子视图占据了20的固定宽度，B子视图的weight设置为0.4，C子视图的weight设置为0.6 那么：
 
 @code
 A子视图的宽度 = 20
 B子视图的宽度 = (100-20)*0.4 = 32
 C子视图的宽度 = (100-20-32)*0.6 = 28.8
 @endcode
 
 */
@property (nonatomic, assign) CGFloat weight;

/**
 设置视图不受布局父视图的布局约束控制和不再参与视图的布局，所有设置的其他扩展属性都将失效而必须用frame来设置视图的位置和尺寸，默认值是NO。这个属性主要用于某些视图希望在布局视图中进行特殊处理和进行自定义的设置的场景。比如一个垂直线性布局下有A,B,C三个子视图设置如下：

 @code
 A.mySize = CGSizeMake(100,100);
 B.mySize = CGSizeMake(100,50);
 C.mySize = CGSizeMake(100,200);
 B.frame = CGRectMake(20,20,200,100);
 
 正常情况下当布局完成后:
 A.frame == {0,0,100,100}
 B.frame == {0,100,100,50}  //可以看出即使B设置了frame值，但是因为布局约束属性优先级高所以对B设置的frame值是无效的。
 C.frame == {0,150,100,200}
 
 而当我们设置如下时：
 A.mySize = CGSizeMake(100,100);
 B.mySize = CGSizeMake(100,50);
 C.mySize = CGSizeMake(100,200);
 B.frame = CGRectMake(20,20,200,100);
 B.useFrame = YES;

 那么在布局完成后：
 A.frame == {0, 0, 100, 100}
 B.frame == {20,20,200,100}   //可以看出B并没有受到约束的限制，结果就是B设置的frame值。
 C.frame == {0, 100,100,200}  //因为B不再参与布局了，所以C就往上移动了，由原来的150变为了100.
 
 @endcode 
 
 @note
 useFrame的应用场景是某个视图虽然是布局视图的子视图但不想受到父布局视图的约束，而是可以通过frame进行自由位置和尺寸调整的场景。

 */
@property (nonatomic, assign) BOOL useFrame;

/**
 设置视图在进行布局时只会参与布局但不会真实的调整位置和尺寸，默认值是NO。当设置为YES时会在布局时保留出视图的布局位置和布局尺寸的空间，但不会更新视图的位置和尺寸，也就是说只会占位但不会更新。因此你可以通过frame值来进行位置和尺寸的任意设置，而不会受到你的布局视图的影响。这个属性主要用于某些视图希望在布局视图中进行特殊处理和进行自定义的设置的场景。比如一个垂直线性布局下有A,B,C三个子视图设置如下：

 @code
 A.mySize = CGSizeMake(100,100);
 B.mySize = CGSizeMake(100,50);
 C.mySize = CGSizeMake(100,200);
 B.frame = CGRectMake(20,20,200,100);
 
 正常情况下当布局完成后:
 A.frame == {0,0,100,100}
 B.frame == {0,100,100,50}  //可以看出即使B设置了frame值，但是因为布局约束属性优先级高所以对B设置的frame值是无效的。
 C.frame == {0,150,100,200}
 
 而当我们设置如下时：
 A.mySize = CGSizeMake(100,100);
 B.mySize = CGSizeMake(100,50);
 C.mySize = CGSizeMake(100,200);
 B.frame = CGRectMake(20,20,200,100);
 B.noLayout = YES;
 
 那么在布局完成后：
 A.frame == {0,0,100,100}
 B.frame == {20,20,200,100}  //可以看出虽然B参与了布局，但是并没有更新B的frame值，而是保持为通过frame设置的原始值。
 C.frame == {0,150,100,200}  //因为B参与了布局，占用了50的高度，所以这里C的位置还是150，而不是100.
@endcode

 @note
 useFrame和noLayout的区别是：
  
 1.前者不会参与布局而必须要通过frame值进行设置，而后者则会参与布局但是不会将布局的结果更新到frame中。
 
 2.当前者设置为YES时后者的设置将无效，而后者的设置并不会影响前者的设置。
 
 
 @note
 noLayout的应用场景是那些想在运行时动态调整某个视图的位置和尺寸，但是又不想破坏布局视图中其他子视图的布局结构的场景，也就是调整了视图的位置和尺寸，但是不会调整其他的兄弟子视图的位置和尺寸。
 
*/
@property (nonatomic, assign) BOOL noLayout;

/**
 指定视图的可见性，默认是visible。这个属性是对视图hidden属性的扩展，布局系统对视图的hidden属性设置后，视图将不再参与布局。但在实际中有些场景我们希望视图隐藏后
 仍然会占用空间仍然会参与布局。因此我们可以用这个属性来设置当视图隐藏后是否继续参与布局。
 如果您使用了这个属性来对视图进行隐藏和取消隐藏操作则请不要再去操作hidden属性，否则可能出现二者效果不一致的情况。因此建议视图的隐藏和显示用这个属性进行设置。
 
 属性可以设置的值如下：
 
  1. MyVisibility_Visible     视图可见，等价于hidden = NO
 
  2. MyVisibility_Invisible   视图不可见，等价于hidden = YES, 但是会在父布局视图中占位空白区域
 
  3. MyVisibility_Gone        视图不可见，等价于hidden = YES, 但是不会在父视图中占位空白区域
 
 
 @note
   建议您用这个属性设置视图的隐藏的显示而不用系统默认的hidden来进行设置。
 
 */
@property (nonatomic, assign) MyVisibility visibility;

/**
 指定子在布局视图上的对齐方式，默认是None表示未指定，这个属性目前只支持框架布局，线性布局，流式布局，浮动布局下的属性设置。
 
 1. 在框架布局中支持上、中、下、垂直拉伸和左、中、右、水平拉伸8个设置
 
 2. 在垂直线性布局中只支持左、中、右、水平拉伸对齐。(如果父布局视图设置了gravity，子视图设置了这个属性则这个属性优先级最高)
 
 3. 在水平线性布局中只支持上、中、下、垂直拉伸、基线对齐。(如果父布局视图设置了gravity，子视图设置了这个属性则这个属性优先级最高)
 
 4. 在垂直流式布局和垂直浮动布局中用来设置一行内的上、中、下、垂直拉伸、基线对齐。(如果流式父布局视图设置了arrangedGravity，子视图设置了这个属性则这个属性优先级最高)
 
 5. 在水平流式布局和水平浮动布局中用来设置一列内的左、中、右、水平拉伸对齐。(如果流式父布局视图设置了arrangedGravity，子视图时设置了这个属性则这个属性优先级最高)
 */
@property (nonatomic, assign) MyGravity alignment;

/**
 下面两个属性：reverseFloat和clearFloat 仅用在浮动布局MyFloatLayout下面的子视图中使用。
 */

/**
 是否反方向浮动，默认是NO表示正向浮动。正向浮动和反向浮动的意义根据所在的父浮动布局视图的方向的不同而不同：
 
    1. 如果父视图是垂直浮动布局则默认正向浮动是向左浮动的，而反向浮动则是向右浮动。
 
 @code
 下面是垂直浮动布局中的正向浮动和反向浮动的效果图(正向浮动:A,B,D; 反向浮动:C,E,F)：
 
 |<--A-- <---B---    -C->|
 |<-----D---- -F-> --E-->|
 @endcode
 
    2. 如果父视图是水平浮动布局则默认正向浮动是向上浮动的，而反向浮动则是向下浮动。
 
 @code
 下面是水平浮动布局中的正向浮动和反向浮动的效果图(正向浮动:A,B,D; 反向浮动:C,E,F):
 
  -----------
   ↑   ↑
   |   |
   A   |
   |   D
       |
   ↑   |
   B
   |   F
       ↓
   |   |
   C   E
   ↓   ↓
  ------------
 @endcode
 
 @note 这个属性的定义是完全参考CSS样式表中float属性的定义
 */
@property (nonatomic, assign, getter=isReverseFloat) BOOL reverseFloat;

/**
 清除浮动，默认是NO。这个属性的意义也跟父浮动布局视图的方向相关。如果设置为了清除浮动属性则表示本子视图不会在浮动方向上紧跟在前一个浮动子视图的后面，而是会另外新起一行或者一列来重新排列。
 
 @code
 垂直浮动布局下的浮动和清除浮动
 
 |<--A-- <---B--- <-C--|
 |<----D---            |
 |<--E-- <---F--       |
 |<-----G----          |
 |      ---I---> --H-->|
 |                -J-> |
 
 A(正向浮动);B(正向浮动);C(正向浮动);D(正向浮动);E(正向浮动);F(正向浮动);G(正向浮动，清除浮动);H(反向浮动);I(反向浮动);J(反向浮动，清除浮动)
 @endcode
 
 @note 这个属性的定义是完全参考CSS样式表中clear属性的定义。
 
 */
@property (nonatomic, assign) BOOL clearFloat;


/**
 视图在父布局视图中布局完成后也就是视图的frame更新完成后执行的block，执行完block后会被重置为nil。通过在viewLayoutCompleteBlock中我们可以得到这个视图真实的frame值,当然您也可以在里面进行其他业务逻辑的操作和属性的获取和更新。block方法中layout参数就是父布局视图，而v就是视图本身，block中这两个参数目的是为了防止循环引用的问题。
 
 不再建议使用这个block进行获取子视图最终frame值，因为这个block只会执行一次，所以得到的frame值可能不准确。
 建议通过KVO来观察布局视图的isMyLayouting属性来获取布局完成后子视图的frame值。
 
 */
@property (nonatomic, copy) void (^viewLayoutCompleteBlock)(MyBaseLayout *layout, UIView *v);

/**
 视图的在父布局视图调用完评估尺寸的方法后，可以通过这个方法来获取评估的CGRect值。评估的CGRect值是在布局前评估计算的值，而frame则是视图真正完成布局后的真实的CGRect值。在调用这个方法前请先调用父布局视图的-(CGSize)sizeThatFits:方法进行布局视图的尺寸评估，否则此方法返回的值未可知。这个方法主要用于在视图布局前而想得到其在父布局视图中的位置和尺寸的场景。
 
 @return 返回被子视图的评估的CGRect值。
 */
- (CGRect)estimatedRect;

/**
 *清除视图所有为布局而设置的布局特性值。如果是布局视图调用这个方法则同时会清除布局视图中所有关于布局设置的属性值。
 */
- (void)clearLayoutTraits;
- (void)clearLayoutTraitsInSizeClass:(MySizeClass)sizeClass;

/**
  获取视图在某个SizeClass下的布局特性对象。视图可以通过得到的布局特性对象来设置视图在对应SizeClass下的各种布局约束属性。如果指定的sizeClass之前不存在则会从默认sizeClass下拷贝一份。
 
 @param sizeClass 指定获取某种SizeClass
 @return 返回指定的布局特性对象
 */
- (__kindof id<MyViewTraits>)fetchLayoutTraitsInSizeClass:(MySizeClass)sizeClass;

/**
  获取视图在某个SizeClass下的布局特性对象，如果对象不存在则会新建立一个新的特性对象，并且其布局约束属性都拷贝自srcSizeClass中的属性，如果对象已经存在则srcSizeClass不起作用，如果srcSizeClass本来就不存在则也不会起作用。
 @param sizeClass 指定获取某个SizeClass
 @param srcSizeClass 指定从哪种SizeClass中拷贝
 @return 返回指定的布局特性对象
 */
- (__kindof id<MyViewTraits>)fetchLayoutTraitsInSizeClass:(MySizeClass)sizeClass copyFrom:(MySizeClass)srcSizeClass;


/// 为某个sizeClass设置新的布局特性对象，新的布局特性对象一般来源于其他视图或者其他sizeClass，从而实现布局特性属性的拷贝功能。
/// @param value 新的值，这个值必须是上述两个fetchLayoutTraits方法返回值的copy结果。
/// @param sizeClass 具体的sizeClass类型
- (void)setLayoutTraits:(__kindof id<MyViewTraits>)value inSizeClass:(MySizeClass)sizeClass;


@end

/**
 布局视图基类，基类不支持实例化对象。在编程时我们经常会用到一些视图，这种视图只是负责将里面的子视图按照某种规则进行排列和布局，而别无其他的作用。因此我们称这种视图为容器视图或者称为布局视图。
 布局视图通过重载layoutSubviews方法来完成子视图的布局和排列的工作。对于每个加入到布局视图中的子视图，都会在加入时通过KVO机制监控子视图的center和bounds以及frame值的变化，每当子视图的这些属性一变化时就又会重新引发布局视图的布局动作。同时对每个视图的布局扩展属性的设置以及对布局视图的布局属性的设置都会引发布局视图的布局动作。布局视图在添加到非布局父视图时也会通过KVO机制来监控非布局父视图的frame值和bounds值，这样每当非布局父视图的尺寸变更时也会引发布局视图的布局动作。前面说的引起变动的方法就是会在KVO处理逻辑以及布局扩展属性和布局属性设置完毕后通过调用setNeedLayout来实现的，当布局视图收到setNeedLayout的请求后，会在下一个runloop中对布局视图进行重新布局而这就是通过调用layoutSubviews方法来实现的。布局视图基类只提供了更新所有子视图的位置和尺寸以及一些基础的设置，而至于如何排列和布局这些子视图则要根据应用的场景和需求来确定，因此布局基类视图提供了一个：
   -(CGSize)calcLayoutSize:(CGSize)size subviewEngines:(NSMutableArray<MyLayoutEngine *> *)subviewEngines context:(MyLayoutContext *)context
     的方法，要求派生类去重载这个方法，这样不同的派生类就可以实现不同的应用场景，这就是布局视图的核心实现机制。
 
 MyLayout布局库根据实际中常见的场景实现了8种不同的布局视图派生类他们分别是：线性布局、表格布局、相对布局、框架布局、流式布局、浮动布局、路径布局、栅格布局。
 */
@interface MyBaseLayout < __covariant MyLayoutTraitsT> : UIView< MyLayoutTraits >

/**
  用于实现对阿拉伯国家的布局适配。对于非阿拉伯国家来说，界面布局都是默认从左到右排列。而对于阿拉伯国家来说界面布局则默认是从右往左排列。默认这个属性是NO，您可以将这个属性设置为YES，这样布局里面的所有视图都将从右到左进行排列布局。如果您需要考虑国际化布局的问题，那么您应该用leadingPos来表示头部的位置，而用trailingPos来表示尾部的位置，这样当布局方向是LTR时那么leadingPos就表示的是左边而trailingPos则表示的是右边；而当布局方向是RTL时那么leadingPos表示的是右边而trailingPos则表示的是左边。如果您的界面布局不会考虑到国际化以及不需要考虑RTL时那么您可以用leftPos和rightPos来表示左右而不需要用leadingPos和trailingPos。
 */
@property (class, nonatomic, assign) BOOL isRTL;


/**
 直接更新window下所有布局视图的RTL特性。
 */
+ (void)updateRTL:(BOOL)isRTL inWindow:(UIWindow *)window;
//+ (void)myUpArabicUI:(BOOL)isArabicUI inWindow:(UIWindow *)window MYDEPRECATED("use updateRTL:inWindow: instead");

/*
 布局视图里面的padding属性用来设置布局视图的内边距。内边距是指布局视图里面的子视图离自己距离。外边距则是视图与父视图之间的距离。
 内边距是在自己的尺寸内离子视图的距离，而外边距则不是自己尺寸内离其他视图的距离。下面是内边距和外边距的效果图：
 
                    ^
                    | margin-top
                    |           width
                +------------------------------+
                |                              |------------>
                |  p                       p   | margin-right
                |  a      padding-top      a   |
                |  d                       d   |
                |  d   +---------------+   d   |
     <----------|  i   |               |   i   |
     margin-left|  n   |               |   n   |
                |  g   |   subview's   |   g   |  height
                |  |   |    content    |   |   |
                |  l   |               |   r   |
                |  e   |               |   i   |
                |  f   +---------------+   g   |
                |  t                       h   |
                |       padding-bottom     t   |
                +------------------------------+
                    |margin-bottom
                    |
                    V
 
 
 如果一个布局视图中的每个子视图都离自己有一定的距离就可以通过设置布局视图的内边距来实现，而不需要为每个子视图都设置外边距。
 
 */

/**
 * 设置布局视图四周的内边距值。所谓内边距是指布局视图内的所有子视图离布局视图四周的边距。通过为布局视图设置内边距可以减少为所有子视图设置外边距的工作，而外边距则是指视图离父视图四周的距离。
 */
@property (nonatomic, assign) UIEdgeInsets padding;

/**
 * 顶部内边距，用来设置子视图离自身顶部的边距值。
 */
@property (nonatomic, assign) CGFloat paddingTop;
/**
 *头部内边距，用来设置子视图离自身头部的边距值。对于LTR方向的布局来说就是指的左边内边距，而对于RTL方向的布局来说就是指的右边内边距
 */
@property (nonatomic, assign) CGFloat paddingLeading;
/**
 *底部内边距，用来设置子视图离自身底部的边距值。
 */
@property (nonatomic, assign) CGFloat paddingBottom;
/**
 *尾部内边距，用来设置子视图离自身尾部的边距值。对于LTR方向的布局来说就是指的右边内边距，而对于RTL方向的布局来说就是指的左边内边距
 */
@property (nonatomic, assign) CGFloat paddingTrailing;

/**
 *左边内边距，用来设置子视图离自身左边的边距值。如果您不需要考虑布局的方向，那么请用这个属性来设置左边的内部边距，如果您需要考虑国际化则请用paddingLeading
 */
@property (nonatomic, assign) CGFloat paddingLeft;

/**
 *右边内边距，用来设置子视图离自身右边的边距值。如果您不需要考虑布局的方向，那么请用这个属性来设置右边的内部边距，如果您需要考虑国际化则请用paddingTrailing
 */
@property (nonatomic, assign) CGFloat paddingRight;

/**
 * 设置当布局的尺寸由子视图决定并且在没有子视图加入的情况下padding的设置值是否会加入到布局的尺寸值里面。默认是YES，表示当布局视图没有子视图时padding值也会加入到尺寸里面。
 * 举例来说假设某个布局视图的高度是自适应,并且设置了paddingTop为10，paddingBottom为20。那么默认情况下当没有任何子视图时布局视图的高度是30；而当我们将这个属性设置为NO时，那么在没有任何子视图时布局视图的高度就是0，也就是说paddingTop和paddingBottom不会参与高度的计算了。
 */
@property (nonatomic, assign) BOOL zeroPadding;

/**
 指定padding内边距的缩进是在SafeArea基础之上进行的。默认是UIRectEdgeLeft|UIRectEdgeRight 表示缩进SafeArea所指定的水平区域。你也可以设置只缩进某一个或则几个方向，或者不缩进任何一个方向。这个属性是为了支持iPoneX而设置的。为了支持iPhoneX的全屏幕适配。我们只需要对根布局视图设置这个扩展属性，默认情况下是不需要进行特殊设置的，MyLayout自动会对iPhoneX进行适配。我们知道iOS11中引入了安全区域的概念，MyLayout中的根布局视图会自动将安全区域叠加到设置的padding中去。默认情况下四周的安全区域都会叠加到padding中去，因此您可以根据特殊情况来设置只需要叠加哪一个方向的安全区域。
 */
@property (nonatomic, assign) UIRectEdge insetsPaddingFromSafeArea;

/**
 *当insetsPaddingFromSafeArea同时设置有左右方向同时缩进并且在横屏时是否只缩进有刘海方向的内边距。默认是NO，表示两边都会缩进。如果你想让没有刘海的那一边延伸到屏幕的安全区外，请将这个属性设置为YES。iPhoneX设备中具有一个尺寸为44的刘海区域。当您横屏时为了对齐，左右两边的安全缩进区域都是44。但是有些时候我们希望没有刘海的那一边不需要缩进对齐而是延伸到安全区域以外。这时候您可以通过给根布局视图设置这个属性来达到效果。注意这个属性只有insetsPaddingFromSafeArea设置了左右都缩进时才有效。
 */
@property (nonatomic, assign) BOOL insetLandscapeFringePadding;

/**
 *设置布局视图里面子视图之间的垂直间距。如果布局内每个子视图的垂直间距都相等则可以用这个属性来设置。这个属性不支持框架布局、相对布局、路径布局。
 */
@property (nonatomic, assign) CGFloat subviewVSpacing;
/**
 *设置布局视图里面子视图之间的水平间距。如果布局内每个子视图的水平间距都相等则可以用这个属性来设置。这个属性不支持框架布局、相对布局、路径布局。
 */
@property (nonatomic, assign) CGFloat subviewHSpacing;
/**
 *设置布局视图里面子视图之间的间距。如果布局内每个子视图的间距都相等则可以用这个属性来设置。这个属性不支持框架布局、相对布局、路径布局。
 */
@property (nonatomic, assign) CGFloat subviewSpacing;

/**
 布局里面的所有子视图的整体停靠方向以及填充，所谓停靠是指布局视图里面的所有子视图整体在布局视图中的位置，系统默认的停靠是在布局视图的左上角。
 
 @note
 只有框架布局、线性布局、表格布局、流式布局、浮动布局、栅格布局支持gravity属性，相对布局和路径布局不支持。
 
 1. MyGravity_Vert_Top,MyGravity_Vert_Center,MyGravity_Vert_Bottom 表示整体垂直居上，居中，居下 (支持：框架布局,线性布局,表格布局,流式布局,垂直浮动布局)
 
 2. MyGravity_Horz_Left,MyGravity_Horz_Center,MyGravity_Horz_Right 表示整体水平居左，居中，居右 (支持：框架布局,线性布局,表格布局,流式布局,水平浮动布局)
 
 3. MyGravity_Vert_Between 表示每行之间的行间距都被拉伸，以便使里面的子视图垂直方向填充满整个布局视图。 (支持：垂直线性布局,垂直表格布局，流式布局)
 
 4. MyGravity_Horz_Between 表示每列之间的列间距都被拉伸，以便使里面的子视图水平方向填充满整个布局视图。 (支持：水平线性布局,水平表格布局，流式布局)
 
 5. MyGravity_Vert_Around 表示每行之间的行间距都被拉伸，以便使里面的子视图垂直方向填充满整个布局视图，首尾子视图和父视图的间距是子视图兄弟之间的一半。 (支持：垂直线性布局,垂直表格布局，流式布局)
 
 6. MyGravity_Horz_Around 表示每列之间的列间距都被拉伸，以便使里面的子视图水平方向填充满整个布局视图，首尾子视图和父视图的间距是子视图兄弟之间的一半。 (支持：水平线性布局,水平表格布局，流式布局)
 
 7. MyGravity_Vert_Among 表示每行之间的行间距都被拉伸，以便使里面的子视图垂直方向填充满整个布局视图，首尾子视图和父视图的间距和子视图兄弟之间的间距相等。 (支持：垂直线性布局,垂直表格布局，流式布局)
 
 8. MyGravity_Horz_Among 表示每列之间的列间距都被拉伸，以便使里面的子视图水平方向填充满整个布局视图，首尾子视图和父视图的间距和子视图兄弟之间的间距相等。 (支持：水平线性布局,水平表格布局，流式布局)
 
 9. MyGravity_Vert_Fill 表示布局会拉伸子视图的高度，以便使里面的子视图垂直方向填充满整个布局视图的高度或者子视图平分布局视图的高度。(支持：框架布局，水平线性布局，水平表格布局，流式布局)
 
 10. MyGravity_Horz_Fill 表示布局会拉伸子视图的宽度，以便使里面的子视图水平方向填充满整个布局视图的宽度或者子视图平分布局视图的宽度。 (支持：框架布局，垂直线性布局，垂直表格布局，流式布局)
 11. MyGravity_Vert_Baseline 表示布局里面的子视图都基线对齐，目前只支持水平线性布局。
 12.MyGravity_Vert_Stretch 表示当布局中的子视图没有设置高度约束时或者非布局子视图高度自适应时，会拉伸子视图的高度。(支持：线性布局、流式布局)
 13.MyGravity_Horz_Stretch 表示当布局中的子视图没有设置宽度约束或者非布局子视图宽度自适应时，会拉伸子视图的宽度。(支持：线性布局、流式布局)
 */
@property (nonatomic, assign) MyGravity gravity;

/**
 *设置是否布局里面的所有子视图按添加的顺序逆序进行布局。默认是NO，表示按子视图添加的顺序排列。比如一个垂直线性布局依次添加A,B,C三个子视图，那么在正常布局时A,B,C从上到下依次排列，而当这个属性设置为YES时，则布局时就会变成按C,B,A依次从上到下排列。这个属性的设置对框架布局和相对布局无效。
 */
@property (nonatomic, assign) BOOL reverseLayout;

/**
 设置布局内所有子视图的位置的坐标变换，这个坐标变换不会影响到子视图的尺寸。默认值为CGAffineTransformIdentity，表示对子视图不进行任何位置变换。
  这个属性会对布局视图内所有的子视图进行单独的位置变换，而不是进行整体的变换。在对子视图进行变换时的坐标原点是布局视图的中心点，并且是以子视图自身的中心点作为坐标变换计算的依据。
 
 @note
 我们可以设置如下的值进行一些常见的位置变化：
 1.CGAffineTransformIdentity 表示恢复正常，不进行任何位置变换。
 2.CGAffineTransformMakeTranslation(tx, ty) 表示布局视图内所有子视图的水平位置都将偏移tx, 垂直位置都将偏移ty。
 3.CGAffineTransformMakeScale(sx,sy)  表示布局视图内所有子视图的水平位置都将缩放sx倍，所有子视图的垂直位置都将缩放sy倍。
 4.CGAffineTransformMake(-1,0,0,1,0,0) 表示布局视图内所有子视图的位置都将水平翻转，形成水平镜像效果。
 5.CGAffineTransformMake(1,0,0,-1,0,0) 表示布局视图内所有子视图的位置都将垂直翻转，形成垂直镜像效果。
 6.CGAffineTransformMake(-1,0,0,-1,0,0) 表示布局视图内所有子视图的位置都将旋转180度。
 7. 当然我们还可以进行任意的坐标变换，只要您熟悉CGAffineTransform的使用和设置方法。
 */
@property (nonatomic, assign) CGAffineTransform layoutTransform;

/**
 *把一个布局视图放入到UIScrollView(UITableView和UICollectionView除外)内时是否自动调整UIScrollView的contentSize值。默认是MyAdjustScrollViewContentSizeModeAuto表示布局视图会自动接管UIScrollView的contentSize的值。 你可以将这个属性设置MyAdjustScrollViewContentSizeModeNo而不调整和控制contentSize的值，设置为MyAdjustScrollViewContentSizeModeYes则一定会调整contentSize.
 */
@property (nonatomic, assign) MyAdjustScrollViewContentSizeMode adjustScrollViewContentSizeMode;

/**
 *在布局视图进行布局时是否调用基类的layoutSubviews方法，默认设置为NO。
 */
@property (nonatomic, assign) BOOL priorAutoresizingMask;

/**
 *设置是否选中状态。您可以用这个状态来记录布局的扩展属性。
 */
@property (nonatomic, getter=isSelected) BOOL selected; // default is NO may be used by some subclasses or by application

/**
 *设置布局视图在布局开始之前的处理块。系统会在每次布局完成前调用对应的处理块后将处理块清空为nil。系统会在调用layoutSubviews方法前执行beginLayoutBlock。
 */
@property (nonatomic, copy) void (^beginLayoutBlock)(void);
/**
 *设置布局视图在布局完成之后的处理块。系统会在每次布局完成后调用对应的处理块后将处理块清空为nil。您也可以在endLayoutBlock块内取到所有子视图真实布局后的frame值。系统会在调用layoutSubviews方法后执行endLayoutBlock。
 */
@property (nonatomic, copy) void (^endLayoutBlock)(void);

/**
 *设置布局时的动画。并指定时间,选项,和完成时的处理，这个动画只会在调用后的下次布局时执行一次。
 @param duration 指定动画的时间间隔
 */
- (void)layoutAnimationWithDuration:(NSTimeInterval)duration;
- (void)layoutAnimationWithDuration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion;

/**
 设置布局视图在第一次布局完成之后或者有横竖屏切换时进行处理的block。这个block不像beginLayoutBlock以及endLayoutBlock那样只会执行一次,而是会一直存在
 因此需要注意代码块里面的循环引用的问题。这个block调用的时机是第一次布局完成或者每次横竖屏切换时布局完成被调用。
 这个方法会在endLayoutBlock后调用。
 
 layout 参数就是布局视图本身。
 
 isFirst 表明当前是否是第一次布局时调用。
 
 isPortrait 表明当前是横屏还是竖屏。
 */
@property (nonatomic, copy) void (^rotationToDeviceOrientationBlock)(MyBaseLayout *layout, BOOL isFirst, BOOL isPortrait);

/**
 删除所有子视图的方便方法
 */
- (void)removeAllSubviews;

/**
 *判断当前是否正在布局中,如果正在布局中则返回YES,否则返回NO。 我们可以通过KVO的方式来监听这个属性的变化，以便获取布局完成后的真实frame值。
 */
@property (nonatomic, assign, readonly) BOOL isMyLayouting;

/**
 *设置布局视图的四周的边界线对象。boundBorderLine是同时设置四周的边界线。您也可以单独设置布局视图某些边的边界线。边界线对象默认是nil，您必须通过建立边界线类MyBorderline的对象实例并赋值给下面的属性来实现边界线的指定。
 */

/**顶部边界线*/
@property (nonatomic, strong) MyBorderline *topBorderline;
/**头部边界线*/
@property (nonatomic, strong) MyBorderline *leadingBorderline;
/**底部边界线*/
@property (nonatomic, strong) MyBorderline *bottomBorderline;
/**尾部边界线*/
@property (nonatomic, strong) MyBorderline *trailingBorderline;
/**四周边界线*/
@property (nonatomic, strong) MyBorderline *boundBorderline;

/**
 *如果您不需要考虑国际化的问题则请用这个属性设置左边边界线，否则用leadingBorderline
 */
@property (nonatomic, strong) MyBorderline *leftBorderline;
/**
 *如果您不需要考虑国际化的问题则请用这个属性设置右边边界线，否则用trailingBorderline
 */
@property (nonatomic, strong) MyBorderline *rightBorderline;

/**
 *智能边界线，智能边界线不是设置布局自身的边界线而是对添加到布局视图里面的子布局视图根据子视图之间的关系智能的生成边界线，对于布局视图里面的非布局子视图则不会生成边界线。目前的版本只支持线性布局，表格布局，流式布局和浮动布局这四种布局。
 *举例来说如果为某个垂直线性布局设置了智能边界线，那么当这垂直线性布局里面添加了A和B两个子布局视图时，系统会智能的在A和B之间绘制一条边界线。
 */
@property (nonatomic, strong) MyBorderline *intelligentBorderline;

/**
 *不使用父布局视图提供的智能边界线功能。当某个布局视图的父布局视图设置了intelligentBorderline时但是这个布局视图又想自己定义边界线或者不想要边界线时则将这个属性设置为YES即可。
 */
@property (nonatomic, assign) BOOL notUseIntelligentBorderline;

/**
 *在有布局触摸事件时布局按下时背景的高亮的颜色。只有设置了setTarget:action方法此属性才生效。
 */
@property (nonatomic, strong) UIColor *highlightedBackgroundColor;

/**
 *在有布局触摸事件时布局按下时的高亮不透明度。值的范围是[0,1]，默认是0表示完全不透明，为1表示完全透明。只有设置了setTarget:action方法此属性才生效。
 */
@property (nonatomic, assign) CGFloat highlightedOpacity;

/**
 *设置布局的背景图片。这个属性的设置就是设置了布局的layer.contents的值，因此如果要实现背景图的局部拉伸请用layer的其他contentsXXX属性进行调整和处理
 */
@property (nonatomic, strong) UIImage *backgroundImage;

/**
 *在有布局触摸事件时布局按下时的高亮背景图片。只有设置了setTarget:action方法此属性才生效。
 */
@property (nonatomic, strong) UIImage *highlightedBackgroundImage;

/**
  设置布局的touch up 、touch down、touch cancel事件的处理动作,后两个事件的处理必须依赖于第一个事件的处理。请不要在这些处理动作中修改背景色，不透明度，以及背景图片。如果您只想要高亮效果但是不想处理事件则将action设置为nil即可了。
 @param target 事件的处理对象，如果设置为nil则表示取消事件。
 @param action 事件的处理动作，格式为：-(void)handleAction:(MyBaseLayout*)sender。
 */
- (void)setTarget:(id)target action:(SEL)action;
- (void)setTouchDownTarget:(id)target action:(SEL)action;
- (void)setTouchCancelTarget:(id)target action:(SEL)action;

/**
评估布局视图的尺寸。这个方法并不会让布局视图进行真正的布局，只是对布局的尺寸进行评估，主要用于在布局完成前想预先知道布局尺寸的场景。通过对布局进行尺寸的评估，可以在不进行布局的情况下动态的计算出布局的位置和大小，但需要注意的是这个评估值有可能不是真实显示的实际位置和尺寸。
 @param size 指定期望的宽度或者高度，如果size中对应的值设置为0则根据布局自身的高度和宽度来进行评估，而设置为非0则固定指定的高度或者宽度来进行评估。比如下面的例子：
  1.sizeThatFits:CGSizeMake(0,0) 表示按布局的位置和尺寸根据布局的子视图来进行动态评估。
  2.sizeThatFits:CGSizeMake(320,0) 表示布局的宽度固定为320,而高度则根据布局的子视图来进行动态评估。这个情况非常适用于UITableViewCell的动态高度的计算评估。
  3.sizeThatFits:CGSizeMake(0,100) 表示布局的高度固定为100,而宽度则根据布局的子视图来进行动态评估。
 @return 返回评估的尺寸。
 */
- (CGSize)sizeThatFits:(CGSize)size;
- (CGSize)sizeThatFits:(CGSize)size inSizeClass:(MySizeClass)sizeClass;

/**
  是否缓存经过sizeThatFits方法评估后的所有子视图的位置和尺寸一次!，默认设置为NO不缓存。当我们用sizeThatFits方法评估布局视图的尺寸后，所有子视图都会生成评估的位置和尺寸，因为此时并没有执行布局所以子视图并没有真实的更新frame值。而当布局视图要进行真实布局时又会重新计算所有子视图的位置和尺寸，因此为了优化性能当我们对布局进行评估后在下次真实布局时我们可以不再重新计算子视图的位置和尺寸而是用前面评估的值来设置位置和尺寸。这个属性设置为YES时则每次评估后到下一次布局时不会再重新计算子视图的布局了，而是用评估值来布局子视图的位置和尺寸。而当这个属性设置为NO时则每次布局都会重新计算子视图的位置和布局。
   这个属性一般用在那些动态高度UITableviewCell中进行配合使用，我们一般将布局视图作为UITableviewCell的contentView的子视图:
 
 @code
 MyXXXLayout *rootLayout= [MyXXXLayout new];
 rootLayout.cacheEstimatedRect = YES;   //设置缓存评估的rect,如果您的cell是高度自适应的话，强烈建立打开这个属性，这会大大的增强您的tableview的性能！！
 rootLayout.myHorzMargin = 0;           //宽度和父视图相等
 rootLayout.myHeight = MyLayoutSize.wrap;    //高度动态包裹。
 [self.contentView addSubview:rootLayout];
 self.rootLayout = rootLayout;
  
 //在rootLayout添加子视图。。。
 
 *************************************
 
 然后我们在heightForRowAtIndexPath中按如下格式进行高度的评估的计算。
 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
     UITableViewCellXXX *cell = (UITableViewCellXXX*)[self tableView:tableView cellForRowAtIndexPath:indexPath];
     CGSize size = [cell.rootLayout sizeThatFits:CGSizeMake(tableView.frame.size.width, 0)];
     return size.height;
 }
 
 @endcode
 
 @note
   这个属性有可能会造成动态高度计算不正确，请只在UITableviewCell的高度为自适应时使用，其他地方不建议设置这个属性！！。如果出现高度计算异常也请勿设置这个属性为YES。
 */
@property (nonatomic, assign) BOOL cacheEstimatedRect;

/**
 评估计算一个未加入到布局视图中的子视图subview在加入后的frame值。在实践中我们希望得到某个未加入的子视图在添加到布局视图后的应该具有的frame值，这时候就可以用这个方法来获取。比如我们希望把一个子视图从一个布局视图里面移到另外一个布局视图的末尾时希望能够提供动画效果,这时候就可以通过这个方法来得到加入后的子视图的位置和尺寸。
     这个方法只有针对那些通过添加顺序进行约束的布局视图才有意义，相对布局和框架布局则没有意义。
 
 @note 使用示例：假设存在两个布局视图L1,L2他们的父视图是S，现在要实现将L1中的任意一个子视图A移动到L2的末尾中去，而且要带动画效果，那么代码如下：
 @code
   //得到A在S中的frame，这里需要进行坐标转换为S在中的frame
   CGRect rectOld =  [L1 convertRect:A.frame toView:S];
   //得到将A加入到L2后的评估的frame值，注意这时候A还没有加入到L2。
   CGRect rectNew = [L2 subview:A estimatedRectInLayoutSize:CGSizeZero];
   //将新位置的评估的frame值，这里需要进行坐标转换为S在中的frame。
   rectNew = [L2 convertRect:rectNew toView:S];
 
   //动画的过程是先将A作为S的子视图进行位置的调整后再加入到L2中去
   [A removeFromSuperview];
   //因为A要使用frame进行位置的调整，所以这里要记得将useFrame设置为YES。
   A.useFrame = YES;
   A.frame = rectOld;
   [S addSubview:A];
   [UIView animateWithDuration:0.3 animations:^{
 
     A.frame = rectNew;
 
   } completion:^(BOOL finished) {
 
     //动画结束后再将A移植到L2中。
     [A removeFromSuperview];
     //将useFrame设置为NO表示，视图A重新受到布局视图的约束控制
     A.useFrame = NO;
     [L2 addSubview:A];
   }];
 @endcode
 
 @param subview 一个未加入布局视图的子视图，如果子视图已经加入则直接返回子视图的frame值。
 @param size 指定布局视图期望的宽度或者高度，一般请将这个值设置为CGSizeZero。 具体请参考sizeThatFits方法中的size的说明。
 @return 子视图在布局视图最后一个位置(假如加入后)的frame值。
 */
- (CGRect)subview:(UIView *)subview estimatedRectInLayoutSize:(CGSize)size;


- (MyLayoutTraitsT)fetchLayoutTraitsInSizeClass:(MySizeClass)sizeClass;
- (MyLayoutTraitsT)fetchLayoutTraitsInSizeClass:(MySizeClass)sizeClass copyFrom:(MySizeClass)srcSizeClass;

- (void)setLayoutTraits:(MyLayoutTraitsT)value inSizeClass:(MySizeClass)sizeClass;


@end

#pragma mark-- MyLayoutDragger
@class MyLayoutDragger;


@protocol MyLayoutDraggerDelegate <NSObject>

@optional

/// 拖动的视图开始悬停在某个视图之上通知
/// - Parameters:
///   - dragger: 拖动管理器
///   - draggingView: 拖动的视图
///   - hoveringView: 悬停的视图
- (void)myLayoutDragger:(MyLayoutDragger *)dragger draggingView:(UIView *)draggingView enterInHoveringView:(UIView *)hoveringView;

/// 拖动的视图从悬停的视图上离开通知
/// - Parameters:
///   - dragger: 拖动管理器
///   - draggingView: 拖动的视图
///   - hoveringView: 悬停的视图
- (void)myLayoutDragger:(MyLayoutDragger *)dragger draggingView:(UIView *)draggingView leaveFromHoveringView:(UIView *)hoveringView;

/// 开始拖动通知
/// - Parameters:
///   - dragger: 推动管理器
///   - dragView: 开始拖动的视图
- (void)myLayoutDragger:(MyLayoutDragger *)dragger startDragView:(UIView *)dragView;

/// 结束拖动通知
/// - Parameters:
///   - dragger: 拖动管理器
///   - dropView: 结束拖动的视图
- (void)myLayoutDragger:(MyLayoutDragger *)dragger endDropView:(UIView *)dropView;

@end


/**
 布局视图拖动管理器类，用来实现布局内的视图的拖动封装。用于实现布局子视图的拖放处理。
布局视图的拖动管理器类，只支持那些按顺序添加的布局视图，不支持相对布局、框架布局、栅格布局、路径布局。
 一般情况下我们要实现布局内子视图的：
  1.UIControlEventTouchDown 事件来处理拖动开始
  2.UIControlEventTouchDragInside UIControlEventTouchDragOutside 事件来处理拖动进行中
  3. UIControlEventTouchUpInside UIControlEventTouchCancel 事件来处理拖动结束。
 
 如果您添加到布局下的子视图不是UIControl类的派生类的话，请分别重载如下事件：
 
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event    在这个方法内部调用dragView:withEvent:方法
 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;   在这个方法内部调用dragginView:withEvent方法
 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event  在上述两个方法内部调用dropView:withEvent方法
 
 */
@interface MyLayoutDragger : NSObject

//当拖动的视图和其他视图区域重叠时拖动视图否可以悬停在其他视图上。默认为NO，表明当拖动的视图与其他视图重叠后其他视图会移动，如果为YES则重叠时其他视图会保持不动。
@property (nonatomic, assign) BOOL canHover;

//设置拖动时不会移动位置的子视图列表。也就是说数组中指定的子视图在和拖动的视图重叠时总是固定在原有的位置不会变动。
@property (nonatomic, strong) NSArray<UIView *> *exclusiveViews;

//设定在拖动时拖动视图进入目标视图尺寸的比例就会触发目标视图移开或者触发悬停回调通知，取值为[0,1] 默认值为0.25.
@property (nonatomic, assign) CGFloat overlapRatio;

//设置拖动时位置调整的动画时长，默认是0秒，设置为0时拖动不产生动画效果。设置为0.2效果较好。
@property (nonatomic, assign) NSTimeInterval animateDuration;

@property (nonatomic, weak) id<MyLayoutDraggerDelegate> delegate;


//拖动管理器所属的布局视图
@property (nonatomic, weak, readonly) MyBaseLayout *layoutView;
//正在执行拖动的视图，可能为空
@property (nonatomic, weak, readonly) UIView *draggingView;
//拖动时,拖动视图所悬停的视图，可能为空。注意悬停的视图也有可能是exclusiveViews中指定的视图。
@property (nonatomic, weak, readonly) UIView *hoveringView;





//下列方法请在子视图的相应事件处理中调用。

//开始拖动,请在子视图view的拖动开始事件处调用这个方法，其中view指定要开始拖动的视图。
- (void)dragView:(UIView *)view withEvent:(UIEvent *)event;
//拖动中,请在子视图view的拖动过程事件中调用这个方法，其中的view指定拖动中的视图。
- (void)dragginView:(UIView *)view withEvent:(UIEvent *)event;
//结束拖动，请在子视图view的结束或者终止拖动事件中调用这个方法，其中的view指定要结束拖动的视图。
- (void)dropView:(UIView *)view withEvent:(UIEvent *)event;

@end

@interface MyBaseLayout (MyLayoutDragger)

//创建一个布局视图拖动器。要求拖动的视图必须是布局视图中的子视图。
- (MyLayoutDragger *)createLayoutDragger;

@end

#pragma mark-- Deprecated

@interface UIView (MyDeprecated)

/**
 *！！！不建议使用这个属性了，而是直接设置视图的宽度为MyLayoutSize.wrap。 比如:myWidth = MyLayoutSize.wrap 或者 widthSize.equalTo(@(MyLayoutSize.wrap))。
 *获取和判断的时候可以通过 myWidth == MyLayoutSize.wrap 或者 widthSize.isWrap 来比较判断
 *视图的宽度包裹属性，表示视图的宽度由所有子视图的整体宽度来确定或者根据视图内容来宽度自适应。默认值是NO(水平线性布局默认这个属性是YES)，表示必须要明确指定视图的宽度，而当设置为YES时则不需要明确的指定视图的宽度了。这个属性不能和widthSize(或者设置了左右边距)同时设置否则可能会产生约束冲突，因为前者表明宽度由子视图或者内容来决定而后者则表示宽度是一个明确的值。如果同时设置了宽度包裹属性又同时设置了明确的宽度则系统会出现约束冲突告警，虽然如此，系统在布局时做了一些优化，如果同时设置了明确的宽度和宽度包裹则会在布局前将宽度包裹属性置为NO。
 */
@property (nonatomic, assign) BOOL wrapContentWidth;

/**
 *！！！不建议使用这个属性了，而是直接设置视图的高度为MyLayoutSize.wrap。 比如:myHeight = MyLayoutSize.wrap 或者 heightSize.equalTo(@(MyLayoutSize.wrap))。
 *获取和判断的时候可以通过 myHeight == MyLayoutSize.wrap 或者 heightSize.isWrap 来比较判断

 *视图的高度包裹属性，表示视图的高度由所有子视图的整体高度来确定或者根据视图内容来高度自适应。默认值是NO(垂直线性布局默认这个属性是YES)，表示必须要明确指定布局的高度，而当设置为YES时则不需要明确的指定视图的高度了。这个属性不能和heightSize(或者设置了上下边距)同时设置否则可能会产生约束冲突，因为前者表明高度由子视图或者内容来决定而后者则表示高度是一个明确的值。如果同时设置了高度包裹属性又同时设置了明确的高度则系统会出现约束冲突告警，虽然如此，系统在布局时做了一些优化，如果同时设置了明确的高度和高度包裹则会在布局前将高度包裹属性置为NO。如果某个非布局视图指定了明确的宽度，而又将这个属性设置为了YES的话就能实现在固定宽度的情况下视图的高度根据内容自适应的效果，这个特性主要用于UILabel,UITextView以及实现了sizeThatFits方法的视图来实现高度根据内容自适应的场景。UILabel在使用这个属性时会自动设置numberOfLines为0，因此如果您要修改numberOfLines则需要在设置这个属性后进行；UITextView可以用这个属性以及heightSize中的max方法来实现到达指定的高度后若继续输入则产生滚动的效果；UIImageView可以用这个属性来在实现在确定宽度的情况下高度根据宽度的缩放情况进行等比例的缩放。
 */
@property (nonatomic, assign) BOOL wrapContentHeight;

/**
 *不建议使用这个属性了！直接设置尺寸为MyLayoutSize.wrap即可。
 *视图的尺寸根据内容来决定，也就是视图的尺寸由内容包裹。这个属性是: A.wrapContentWidth = YES; A.wrapContentHeight = YES;的简化版本。
 *在历史版本中对UILabel进行text赋值后总要手动调用sizeToFit来重新更新布局，在1.3.6以后的新版本中，如果你希望视图的尺寸根据内容而确定则请将这个属性
 *设置为YES。这样就可以在设置完毕text后系统会自动激发布局处理。
 */
@property (nonatomic, assign) BOOL wrapContentSize;


- (void)resetMyLayoutSetting MYDEPRECATED("use clearLayoutTraits instead");
- (void)resetMyLayoutSettingInSizeClass:(MySizeClass)sizeClass MYDEPRECATED("use clearLayoutTraitsInSizeClass: instead");

- (instancetype)fetchLayoutSizeClass:(MySizeClass)sizeClass MYDEPRECATED("use fetchLayoutTraitsInSizeClass: instead");

- (instancetype)fetchLayoutSizeClass:(MySizeClass)sizeClass copyFrom:(MySizeClass)srcSizeClass MYDEPRECATED("use fetchLayoutTraitsInSizeClass:copyFrom: instead");


- (void)setLayoutSizeClass:(MySizeClass)sizeClass withValue:(id)value MYDEPRECATED("use setLayoutTraits:inSizeClass: instead");


@property (nonatomic, assign) CGFloat subviewVSpace MYDEPRECATED("use subviewVSpacing instead");
@property (nonatomic, assign) CGFloat subviewHSpace MYDEPRECATED("use subviewHSpacing instead");
@property (nonatomic, assign) CGFloat subviewSpace MYDEPRECATED("use subviewSpacing instead");

@end

