探究IOS中UI控件的位置(一):Frame、Bounds和Center

1.三个属性的基本介绍:

    (1)frame:描述当前视图在其父视图中的位置和大小。

    (2)bounds:描述当前视图在其自身坐标系统中的位置和大小。

    (3)center:描述当前视图的中心点在其父视图中的位置。

2.必须明确的几个逻辑原点:

      1.位置是相对的,想要表示一个物体的位置必须有参照系。(不同的参照系对相同位置的表示有什么不同?)

      2.控件的原始坐标系:默认控件的左上角为原点,值{0,0},原点出发水平向右是x轴正方向,递增;原点出发垂直向下是y轴正方向,递增。

      3.控件的bounds.origin(最初值都是{0,0})和frame.origin代表的都是控件左上角点的坐标。可以修改。(如何修改,会有什么影响?)

      4.bounds.size和frame.size都表示控件的大小,永远一样。(size的改变是如何影响bounds和frame的?)

      5.bounds代表本地(控件自己的)坐标系,frame代表父控件坐标系。坐标必须在同一个坐标系中才能比较。

3.探索bounds和frame的区别和联系

      一般大家对frame的改变和影响比较熟悉,但是对bounds改变比较陌生。所以,下面就对父控件、子控件的bounds.origin和bounds.size分为四种情况进行组合变换来探究。通过setBounds方法来改变bounds值。

- (void)viewDidLoad {

[super viewDidLoad];

//添加父控件orangeView

UIView * orangeView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 200, 200)];

orangeView.backgroundColor = [UIColor orangeColor];

[self.view addSubview:orangeView];

//添加子控件yellowView

UIView * yellowView = [[UIView alloc]initWithFrame:CGRectMake(20, 20, 100, 100)];

yellowView.backgroundColor = [UIColor yellowColor];

[orangeView addSubview:yellowView];

}

输出bounds和frame值:

orangeView: bounds:{{0, 0}, {200, 200}}--frame:{{100, 100}, {200, 200}};

yellowView: bounds:{{0, 0}, {100, 100}}--frame:{{20, 20}, {100, 100}}。

图 3.0  添加两个控件

3.1 保持bounds.size不变,只改变bounds.origin

 3.1.1 父控件:

[orangeView setBounds:CGRectMake(-30, -30, 200, 200)];

    输出值:

orangeView: bounds:{{-30, -30}, {200, 200}}--frame:{{100, 100}, {200, 200}};

yellowView: bounds:{{0, 0}, {100, 100}}--frame:{{20, 20}, {100, 100}}。

      从输出结果可以得出:父控件的bounds值变为修改后的值,frame不变;子控件bounds值不变(意料之中),值得注意的是,虽然子控件的位置移动了(相对于屏幕,示例程序是向右下方移动;相对于父控件的话,其实子控件位置不变,因为frame不变),但是子控件的frame不变。(父控件通过改变自身的bounds.origin值(自身坐标体系)抵消了子控件位移造成的frame.origin的改变(子控件的frame和父控件的bounds在同一个坐标体系中,因此可以互相抵消))

图 3.1  只改变父控件的bounds.origin

  3.1.2 子控件:

[yellowView setBounds:CGRectMake(-30, -30, 100, 100)];

    输出值:

orangeView: bounds:{{0, 0}, {200, 200}}--frame:{{100, 100}, {200, 200}};

yellowView: bounds:{{-30, -30}, {100, 100}}--frame:{{20, 20}, {100, 100}}。

      从输出结果可以得出:父控件的frame和bounds值都不变,子控件只有bounds变为修改后的值,frame值不变,子控件位置也不变。

      小结:从3.1.1和3.1.2的情况可以分析出:只要bounds值的origin被修改,size值不变,此时无论父控件还是子控件,只有被修改的bounds值会变为修改值,其他的值不变。但要注意:修改父控件的bounds值的origin值会导致子控件的位置改变(相对于屏幕)。

3.2 保持bounds.origin不变,只改变bounds.size

3.2.1 父控件

[orangeView setBounds:CGRectMake(0, 0, 250, 250)];

    输出值:

orangeView: bounds:{{0, 0}, {250, 250}}--frame:{{75, 75}, {250, 250}};

yellowView: bounds:{{0, 0}, {100, 100}}--frame:{{20, 20}, {100, 100}}。

      从输出结果可以得出:父控件的bounds值变为修改值,frame值发生改变;子控件的bounds和frame不变。父控件的图形变换规律是:以变换前的center为中心,左右、上下等距离扩大或缩小。因此,假设原子父控件的frame = {{x, y}, {w, h}},修改后的父控件bounds = {{0, 0}, {w1, h1}},那么变换后的frame = {{x-(w1-w)/2, y-(h1-h)/2}, {w1, h1}};子控件的位置(相对于父控件)不变,因为frame没变。(图中的绿色控件是父控件原来的位置,作为对照)

图 3.2  只改变父控件的bounds.size

3.2.2 子控件

[yellowView setBounds:CGRectMake(0, 0, 250, 250)];

    输出值:

bounds:{{0, 0}, {200, 200}}--frame:{{100, 100}, {200, 200}};

yellowView: bounds:{{0, 0}, {250, 250}}--frame:{{-55, -55}, {250, 250}}

      从输出结果可以得出:子控件的bounds值变为修改值,frame值发生改变;父控件的bounds和frame不变。子控件的图形变换规律和3.2.1中子控件一样;子控件位置(相对于父控件)改变,因为frame变了。

      小结:从3.2.1和3.2.2的情况可以分析出::只要bounds值的size被修改,origin值不变,此时无论父控件还是子控件,被修改控件的bounds值变为修改值,frame值也会改变(计算公式如上),其他的值不变。  

3.3 同时改变bounds.origin和bounds.size

      由3.2和3.3分析可以推测出结果(已验证):

      1.父控件bounds和frame改变,子控件位置改变(相对于屏幕)。

图3.3  改变父控件的bounds.size和bounds.origin

      2.和3.2.2的到的结果相同。

      小结:bounds.size的改变要优先于bounds.origin改变进行处理。

综述:

    1.bounds.size改变时,当前控件的frame值改变,bounds值变为改变后的值,但不影响其他控件两个参数值。

    2.bounds.origin改变时,当前控件的frame值不变,bounds值变为改变后的值,但不影响其他控件两个参数值。

    3.bounds.size的改变要优先于bounds.origin改变进行处理。

    4.控件的bounds.size或bounds.origin的改变,只要改变了坐标系,在同一个坐标系中的其他的控件的位置(相对于屏幕)也会受到影响。

   5.以上规律对于控件是子控件或是父控件无需考虑。

4 应用场景

     苹果官方控件UITableView和UICollectionView就有很好的利用综述中第4点的特性来改变cell的移动的。UITableView或UICollectionView相当于父控件,cell相当于子控件,当滑动屏幕的时候,不断地改变tableview或collectionview的bounds.origin,从而使所有的cell相对于屏幕的位置发生变化,产生向上或向下滚动的效果,而cell的frame并没有发生改变,这样就不用在滑动过程中重新计算cell的frame值。

参考文章:

    1.深入探究frame和bounds的区别以及setbounds使用 - CocoaChina_让移动开发更简单

    2.详解UIView的frame、bounds和center属性 - 移动开发 - ITeye技术网站

推荐阅读更多精彩内容