这是很久以前写的一篇文章,现在把它搬到这儿,统一管理~~~
1 .传统布局的纠结
自己简单封装了个布局框架。以此来分享一下,与大家一起来探讨一下iOS开发。此框架主要有两方面的重要作用:
1. 通过本框架布局,能够清晰的看到iOS控件元素的相互关系,不必要每次都要计算控件的位置,减少脑细胞死亡量。
2. 通过本框架,只需要改动一行代码,就能够轻松实现手机横竖屏完美展现。
3. 其他还有很多好处,自己在使用的过程种可以慢慢体会,可以把你使用的经验分享在下面的评论里。
刚接触ios开发时,看看我们页面布局代码是怎么写的:
[objc]view plaincopy
```
- (void)viewDidLoad {
[superviewDidLoad];
self.view.backgroundColor= [UIColorclearColor];
UIView*view1= [[UIViewalloc]initWithFrame:CGRectMake(5,20, kDeviceWidth/2, kDeviceWidth/3)];
view1.backgroundColor= [UIColorwhiteColor];
[self.viewaddSubview:view1];
UIImageView*imageView1= [[UIImageViewalloc]initWithFrame:CGRectMake(kDeviceWidth/4-22, kDeviceWidth/6-22,44,44)];
[view1addSubview:imageView1];
imageView1.image= [UIImageimageNamed:@"my_04@2x.png"];
UILabel*viewllable = [[UILabelalloc]initWithFrame:CGRectMake(kDeviceWidth/4-60, kDeviceWidth/6-22+44,120,20)];
[view1addSubview:viewllable];
viewllable.text=@"我是:View1";
viewllable.textAlignment= NSTextAlignmentCenter;
}
```
运行的结果如下图所示:
(图1)
让我一起来简单的分析一下上面的代码:
[objc]view plaincopy
```UIView*view1= [[UIViewalloc]initWithFrame:CGRectMake(5,20, kDeviceWidth/2, kDeviceWidth/3)];```
[objc]view plaincopy
```UIImageView*imageView1= [[UIImageViewalloc]initWithFrame:CGRectMake(kDeviceWidth/4-22, kDeviceWidth/6-22,44,44)];```
[objc]view plaincopy
```UILabel*viewllable = [[UILabelalloc]initWithFrame:CGRectMake(kDeviceWidth/4-60, kDeviceWidth/6-22+44,120,20)];```
我们总共添加了三个控件view1(白色的长方形) imageView1(立方体图片) viewllable(显示文字的控件),每个控件我都是通过CGRectMake( , , , );里面的四个参数搞定,这里面的四个参数后面两个参数搞定了控件的大小,前面的两个参数搞定了控件的位置。使用起来确实很方便。可是用着用着我就开始纠结了,在说出我的苦恼之前,我们再看一个图:
(图2)
我们回头在分析一下上面那三行代码
看 CGRectMake里面的参数。里面的参数都是根据屏幕大小,或者根据它的父控件,或者是它相邻控件的位置计算的,就拿imageView1 CGRectMake里面的四个参数来说:CGRectMake(kDeviceWidth/4-22, kDeviceWidth/6-22, 44, 44)
第一个参数:kDeviceWith/2 是view1的宽度,那么kDeviceWidth/4 就是view1宽度的一半 22 其实是44/2 就是imageView1宽度的一半,kDeviceWidth/4-22 就是相当于把imageView1水平方向上居中显示再view1里面,
第二个参数就是显示垂直显示在view1中。
那么我的纠结问题来了:
1 如果我不告诉你, 你知道KDeviceWidth/4-22 ,kDeviceWith/6-22 是什么意思么?纠结的问题:不知道的外人很难理解参数含义。估计时间长了,我自己都忘了是啥意思了。
2 纠结问题二 :如果实现图二的界面,还这样写?光算控件所在位置我得算到猴年马月啊,而且一不留神就容易写错。面对复杂页面:计算量大,易出错。
3 问题三:写过之后,就不想再回头看了,太乱太复杂了。代码后期不易维护。
其实以前,我就是这么天天算,算了天昏地暗啊,脑细胞死的实在太多了,最后就烦了。俗话说:叫什么水复疑无路,柳岸花明又一村(
不好意思:语文老师死的早。。。)
,正在山穷水尽之时,突然脑洞大开。于是就憋出了下面这个框架。
2 纠结之后憋出的新框架
嘿嘿 ,其实很简单,几行代码就搞定了,你可能觉得这太简单了啊,呵呵 ,我就愿意写简单而又别人不愿意写的东西。好了,我们来看一些整个框架的主要方法如下:
[objc]view plaincopy
```
#import
@interfaceUIView (UIViewCategory)
-(void)layout_width:(float)width;//视图高度
-(void)layout_heigth:(float)heigth;//视图宽度
-(void)layout_verticalCenter;//相对于父视图垂直居中
-(void)layout_horizontalCenter;//相对于父视图水平居中
//相对父视图的位置关系
-(void)margin_top:(float)toppix;//距离父视图的上边距
-(void)margin_left:(float)leftpix;//距离父视图的左边距
-(void)margin_bottom:(float)bottompix;//距离父视图的下边距
-(void)margin_rigth:(float)rigthpix;//距离父视图的右边距
//同级相对位置关系
-(void)toleftView:(UIView*)viewofPix:(float)sizepix;//距离某视图的左部边缘距离
-(void)totopView:(UIView*)viewofPix:(float)sizepix;//距离某视图的上部边缘距离
-(void)torigthView:(UIView*)viewofPix:(float)sizepix;//距离某视图的右部边缘距离
-(void)tobottomView:(UIView*)viewofPix:(float)sizepix;//距离某视图的下部边缘距离
//同级对齐方式
-(void)aligntopwithview:(UIView*)view;//与某视图的上部边缘对齐
-(void)aligbottomnwithview:(UIView*)view;//与某视图的下部边缘对齐
-(void)alignleftwithview:(UIView*)view;//与某视图的左部边缘对齐
-(void)alignrigthwithview:(UIView*)view;//与某视图的右部边缘对齐
@end
```
解释具体作用就不用了吧,注释已经很详细了。实现文件我就不贴了,文章最后我会给出源代码下载路径。下面让我们一起来看看用此框架去实现图二的界面吧,代码如下:
[objc]view plaincopy
```
#import "ViewController.h"
#import "UIView+UIViewCategory.h"
#define kDeviceWidth [UIScreen mainScreen].bounds.size.width
#define KDeviceHeight [UIScreen mainScreen].bounds.size.height
@interfaceViewController ()
@end
@implementationViewController
- (void)viewDidLoad {
[superviewDidLoad];
self.view.backgroundColor= [UIColorclearColor];
UIView*view1= [[UIViewalloc]init];
[view1layout_width:kDeviceWidth/2];//view1的宽度
[view1layout_heigth:KDeviceHeight/3];//view1的高度
[view1margin_top:20.0f];//距离父边距上部20像素
[view1margin_left:5.0f];//距离父边距左边5像素
view1.backgroundColor= [UIColorwhiteColor];
[self.viewaddSubview:view1];
UIImageView*imageView1= [[UIImageViewalloc]init];
[view1addSubview:imageView1];
[imageView1layout_width:44];
[imageView1layout_heigth:44];
[imageView1layout_horizontalCenter];//在其父视图中水平居中 相对于CGRectMake(kDeviceWidth/4-22, kDeviceWidth/6-22, 44, 44) 是不是好理解的多啊
[imageView1layout_verticalCenter];//在其父视图中垂直居中
imageView1.image= [UIImageimageNamed:@"my_04@2x.png"];
UILabel*viewllable = [[UILabelalloc]init];
[view1addSubview:viewllable];
[viewllablelayout_heigth:20];
[viewllablelayout_width:120];
[viewllablelayout_horizontalCenter];//在父视图中水平居中 相对于CGRectMake(kDeviceWidth/4-60, kDeviceWidth/6-22+44, 120, 20) 是不是更直观啊
[viewllabletobottomView:imageView1ofPix:5.0];//左边距离imageView1 5像素, 如果用CGRectMake()你又该怎么去实现??
viewllable.text=@"我是:View1";
viewllable.textAlignment= NSTextAlignmentCenter;
UILabel*lableview1= [[UILabelalloc]init];
[self.viewaddSubview:lableview1];
[lableview1layout_width:kDeviceWidth/2-15];
[lableview1layout_heigth:KDeviceHeight/6-5];
[lableview1aligntopwithview:view1];//上边缘与view1的上边缘对齐
[lableview1torigthView:view1ofPix:5.0];//距离view1右边5像素 那么跟上面合起来就是:与view1水平对齐并且在view1的右边5像素处
lableview1.text=@"我是lable1 我与View1顶部对齐,并距离View1右边距5个像素";
lableview1.font= [UIFontboldSystemFontOfSize:15.0];
lableview1.numberOfLines=0;
lableview1.textAlignment= NSTextAlignmentCenter;
lableview1.backgroundColor= [UIColoryellowColor];
UILabel*lableview2= [[UILabelalloc]init];
[self.viewaddSubview:lableview2];
[lableview2layout_width:kDeviceWidth/2-15];
[lableview2layout_heigth:KDeviceHeight/6];
[lableview2alignleftwithview:lableview1];
[lableview2tobottomView:lableview1ofPix:5.0];
lableview2.text=@"我是lable2 我左边与lable1对齐,并距离lable1下边缘5个像素";
lableview2.font= [UIFontboldSystemFontOfSize:15.0];
lableview2.numberOfLines=0;
lableview2.textAlignment= NSTextAlignmentCenter;
lableview2.backgroundColor= [UIColoryellowColor];
UILabel*lableview3= [[UILabelalloc]init];
[self.viewaddSubview:lableview3];
[lableview3layout_heigth:KDeviceHeight/3*2];
[lableview3layout_width:kDeviceWidth-10];
[lableview3tobottomView:view1ofPix:5.0];
[lableview3margin_left:5.0];
lableview3.text=@"我是lableview3 ,他妹的.就这一行代码:[lableview3 tobottomView:view ofPix:5.0] 就把我准确的放在了View1的下面5像素的位置";
lableview3.font= [UIFontsystemFontOfSize:15.0];
lableview3.textAlignment= NSTextAlignmentCenter;
lableview3.numberOfLines=0;
lableview3.backgroundColor= [UIColororangeColor];
}
@end
```
注意看上面有两个最长的注释,我进行了对比,下面我们再尝试一下:改一下view1的上边距和左边距也就是下面两行代码,你会看到什么?:整个页面其他元素的位置都会跟着移动了。不知道这是不是改变了你曾经遇到到:改变一个控件,其他控件根本不动的情况。
[view1margin_top:20.0f];//距离父边距上部20像素
[view1margin_left:5.0f];//距离父边距左边5像素
下面让我们再看一下手机横屏下的展示效果
3 横竖屏转换下的展示效果
代码不变让我们看一下横屏显示的效果图:
( 图3 )
我擦,怎么回事,这显示的是什么东西,不对啊,页面没变啊,这是怎么回事。别着急,小小的杠杆就能撬动大大的地球,请看第三节。
3 小杠杆撬动大地球
上面我们看到那个问题了,那么该如何找到这个小杠杆呢。其实我们只要将
[objc]view plaincopy
```
#define kDeviceWidth [UIScreen mainScreen].bounds.size.width
#define KDeviceHeight [UIScreen mainScreen].bounds.size.height
```
这两个宏定义调换一下位置就行了如下:
[objc]view plaincopy
```
#define kDeviceHeight [UIScreen mainScreen].bounds.size.width
#define KDeviceWidth [UIScreen mainScreen].bounds.size.height
```
注意:此处在UIView+UIViewCategory.m(该文件在源代码里面)的两个定义也需要调换一下。具体原因,自己慢慢思考吧。下面再看一下运行结果如下图:
(图4 横屏显示)
4 总结
框架总体思想:其实总体的框架,就是相对布局思想。
总共有两种情况下的相对布局:
1 :父视图与子视图之间的相对布局 ,主要有以下函数:
[objc]view plaincopy
```
-(void)layout_verticalCenter;//相对于父视图垂直居中
-(void)layout_horizontalCenter;//相对于父视图水平居中
//相对父视图的位置关系
-(void)margin_top:(float)toppix;//距离父视图的上边距
-(void)margin_left:(float)leftpix;//距离父视图的左边距
-(void)margin_bottom:(float)bottompix;//距离父视图的下边距
-(void)margin_rigth:(float)rigthpix;//距离父视图的右边距
```
注意:1 在布局子视图相对于父视图的位置时,要尽量用上面的方法,并且有一点要注意,要先调用 addSubView: 把子视图添加到父视图中,然后才调用上面的方法。不然的话,鬼知道你的父类视图是谁呀。
2 :同级关系的相对布局,主要有以下函数:
[objc]view plaincopy
```
//同级相对位置关系
-(void)toleftView:(UIView*)viewofPix:(float)sizepix;//距离某视图的左部边缘距离
-(void)totopView:(UIView*)viewofPix:(float)sizepix;//距离某视图的上部边缘距离
-(void)torigthView:(UIView*)viewofPix:(float)sizepix;//距离某视图的右部边缘距离
-(void)tobottomView:(UIView*)viewofPix:(float)sizepix;//距离某视图的下部边缘距离
//同级对齐方式
-(void)aligntopwithview:(UIView*)view;//与某视图的上部边缘对齐
-(void)aligbottomnwithview:(UIView*)view;//与某视图的下部边缘对齐
-(void)alignleftwithview:(UIView*)view;//与某视图的左部边缘对齐
-(void)alignrigthwithview:(UIView*)view;//与某视图的右部边缘对齐
```
注意:1 上面4个函数,分别定义了上 下 左 右 相对于同级视图的边距,其中view是同级视图,sizepix是距离同级视图的边距数。
2 下面4个函数,定义了上 下 左 右 与同级视图的对齐方式,上对齐:就是本视图的上边框,与同级视图的上边框对齐,其它的以此类推。
3 一般来说,使用上面八个函数,每两个组合就能轻松实现视图的精确定位。视图是由水平和垂直两个方向决定的,一般使用一个水平也就是左右的函数 和一个垂直的也就是上下的函数组合就能实现视图定位。
4 一个视图要么基与父视图定位,要么基于同级视图定位,不要交叉使用,不要一个视图又基于父视图定位,又基于统计视图定位,及这八个函数不要与上面那个父视图关系的四个函数同时在同一个视图上混合使用。
项目已经托管在github上了。
项目源代码地址 github:https://github.com/lerpo/ios_EasyLayout