界面库下载地址:
https://github.com/youngsoft/MyLinearLayout
前面的几篇文章里我分别介绍了线性布局(MyLinearLayout),相对布局(MyRelativeLayout),框架布局(MyFrameLayout)这三种布局。这三种布局中 :
线性布局主要应用于容器视图里面的所有子视图依次从上往下排列或者从左往右排列的场景。
子视图1 |
子视图2 |
子视图3 |
子视图4 |
子视图1 | 子视图2 | 子视图3 | 子视图4 |
当然我们也可以用线性布局嵌套线性布局的方法来实现一些复杂的界面布局,比如(这个例子如果用MyTableLayout实现将更加简单):
|
|||
|
|||
|
相对布局主要用于容器视图中的各个子视图之间的位置和高宽以及子视图和容器视图之间具有一定的依赖和约束关系的场景。比如说子视图1的位置在子视图2的右下角,并且宽度等于子视图3的宽度,而子视图3的底部又在容器视图的底部。
子视图1(等宽3) | ||
子视图2 | ||
子视图3(等宽1) |
相对布局因为需要指定各子视图之间的依赖关系,因此如果设置不当就会产生递归死循环的情况,而且在某种程度上不利于子视图之间的位置的更新和变化等等,其中IOS自带的AutoLayout其实就是一套相对布局的实现,相对布局功能很强大也可以很容易布局复杂的界面,缺点是使用不当的话就容易造成约束死循环的情况。
框架布局主要用于容器视图中的个子视图在容器视图的上,中,下,左,中,右,拉升填充,居中显示等11种情况。
左上 | 中上 | 右上 |
左中 | 居中 | 右中 |
左下 | 中下 | 右下 |
框架布局中的子视图只跟容器视图之间产生关系,子视图之间没有任何关联关系。
一、表格布局的介绍
在一些实际的应用界面中,我们希望我们的子视图以表格的形式展示出来,这些表格展示可以是正规的几行几列并且固定高宽的形式,也可能是每一行的列数都不同,也可能是每行的高度不一样,也可能是一行内的各列的宽度也不一样,
水平表格布局
垂直表格布局
要实现上面的两种界面风格,我们可以借助MyTableLayout来实现。
MyTableLayout是从MyLinearLayout中继承而来,因此表格布局也分为垂直表格布局和水平表格布局,样式请参考上面的图例的展示风格。而表格的风格样式同样通过
orientation属性来设置。不管是垂直表格布局还是水平表格布局。我们在建立了表格布局视图并指定了表格风格后,我们首先的步骤是要为表格添加行(如果是水平表格其实就是添加列,下面如果为说明都是如此概念),那这个步骤可以通过MyTableLayout的方法:
-(void)addRow:(CGFloat)rowSize colSize:(CGFloat)colSize;
-(void)insertRow:(CGFloat)rowSize colSize:(CGFloat)colSize atIndex:(NSInteger)rowIndex;
rowSize为MTLSIZE_WRAPCONTENT时表示由最高的单元格视图决定本行高度,每个单元格视图需要自己设置高度;为MTLSIZE_AVERAGE表示均分高度,单元格视图不需要设置高度;大于0表示固定高度,单元格视图不需要设置高度.
colSize 为MTLSIZE_MATCHPARENT时表示每个单元格视图需要自己指定宽度,整体行宽和表格布局一致;为MTLSIZE_WRAPCONTENT表示每个单元格视图需要自己指定宽度,整个行宽包裹所有子视图;为MTLSIZE_AVERAGE表示均分宽度,这时候单元格视图不必设置宽度;大于0表示单元格视图固定宽度,这时候单元格视图可以不必设置宽度。
同时我们也提供了对行操作的其他方法:
//删除指定的行
-(void)removeRowAt:(NSInteger)rowIndex;
//交行两个行的内容
-(void)exchangeRowAt:(NSInteger)rowIndex1 withRow:(NSInteger)rowIndex2;
//得到行视图,从返回我们可以看出,我们调用插入行操作时,系统内部会自动建立一个MyLinearLayout线性布局视图作为行视图,如果是垂直表格则默认是水平线性布局,而如果是水平表格则默认是垂直线性布局,因此我们可以通过这个方法来设置行的其他的各种属性,比如说行间距。
-(MyLinearLayout*)viewAtRowIndex:(NSInteger)rowIndex;
//返回当前有多少行
-(NSUInteger)countOfRow;
-(void)addCol:(UIView*)colView atRow:(NSInteger)rowIndex;
-(void)insertCol:(UIView*)colView atIndexPath:(NSIndexPath*)indexPath;
-(void)removeColAt:(NSIndexPath*)indexPath;
-(void)exchangeColAt:(NSIndexPath*)indexPath1 withCol:(NSIndexPath*)indexPath2;
@interface NSIndexPath(MyTableLayoutEx)
+(instancetype)indexPathForCol:(NSInteger)col inRow:(NSInteger)row;
@property(nonatomic,assign,readonly)NSInteger col;
@end
同时我们也方便的提供了单元格列视图的获取和数量的获取的方法
//返回列视图
-(UIView*)viewAtIndexPath:(NSIndexPath*)indexPath;
//返回指定行的列的数量。
-(NSUInteger)countOfColInRow:(NSInteger)rowIndex;
-(void)loadView
{
[super loadView];
/*
有的时候我们希望让一个布局视图放入到非布局视图中去,但又希望布局视图的宽高和非布局父视图宽高一致。
这时候我们可以设置myHeight,myWidth来指定自身的高宽,我们也可以通过myLeft = 0,myRight = 0来让其跟父视图保持一样的宽度,但如果是这样的话还需要设置wrapContentWidth = NO. 设置高度同理。
*/
MyTableLayout *tbll = [MyTableLayout tableLayoutWithOrientation:MyLayoutViewOrientation_Vert];
tbll.myLeft = tbll.myRight = 0; //宽度和非布局父视图一样宽
tbll.myTop = tbll.myBottom = 0; //高度和非布局父视图一样高
[self.view addSubview:tbll];
//第一行固定高度固定宽度
[tbll addRow:30 colSize:70];
[tbll viewAtRowIndex:0].backgroundColor = [UIColor colorWithWhite:0.1 alpha:1];
UILabel *colView = [UILabel new];
colView.text = @"Cell00";
colView.textAlignment = NSTextAlignmentCenter;
colView.myLeft = 10; //可以使用myLeft,myTop,myRight,myBottom来调整间隔
colView.myTop = 5;
colView.myBottom = 5;
colView.myRight = 40;
colView.backgroundColor = [UIColor redColor];
[tbll addCol:colView atRow:0];
colView = [UILabel new];
colView.text = @"Cell01";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor greenColor];
colView.myLeft = 20;
[tbll addCol:colView atRow:0];
colView = [UILabel new];
colView.text = @"Cell02";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor blueColor];
[tbll addCol:colView atRow:0];
//第二行固定高度,均分宽度
[tbll addRow:40 colSize:MTLSIZE_AVERAGE];
[tbll viewAtRowIndex:1].backgroundColor = [UIColor colorWithWhite:0.2 alpha:1];
colView = [UILabel new];
colView.text = @"Cell10";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor redColor];
[tbll addCol:colView atRow:1];
colView = [UILabel new];
colView.text = @"Cell11";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor greenColor];
[tbll addCol:colView atRow:1];
colView = [UILabel new];
colView.text = @"Cell12";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor blueColor];
[tbll addCol:colView atRow:1];
colView = [UILabel new];
colView.text = @"Cell13";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor yellowColor];
[tbll addCol:colView atRow:1];
//第三行固定高度,子视图自己决定宽度。
[tbll addRow:30 colSize:MTLSIZE_WRAPCONTENT];
[tbll viewAtRowIndex:2].backgroundColor = [UIColor colorWithWhite:0.3 alpha:1];
colView = [UILabel new];
colView.text = @"Cell20";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor redColor];
colView.myWidth = 100;
[tbll addCol:colView atRow:2];
colView = [UILabel new];
colView.text = @"Cell21";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor greenColor];
colView.myWidth = 200;
[tbll addCol:colView atRow:2];
//第四行固定高度,子视图自己决定宽度。
[tbll addRow:30 colSize:MTLSIZE_MATCHPARENT];
[tbll viewAtRowIndex:3].backgroundColor = [UIColor colorWithWhite:0.4 alpha:1];
colView = [UILabel new];
colView.text = @"Cell30";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor redColor];
colView.myWidth = 80;
[tbll addCol:colView atRow:3];
colView = [UILabel new];
colView.text = @"Cell31";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor greenColor];
colView.myWidth = 200;
[tbll addCol:colView atRow:3];
//第五行高度均分.这里设置为0表示剩余高度再均分。宽度均分,
[tbll addRow:MTLSIZE_AVERAGE colSize:MTLSIZE_AVERAGE];
MyLinearLayout *row4 = [tbll viewAtRowIndex:4];
//可以设置行的属性.比如padding, 线条颜色,
row4.padding = UIEdgeInsetsMake(3, 3, 3, 3);
row4.topBorderline = [[MyBorderline alloc] initWithColor:[UIColor blackColor]];
row4.topBorderline.thick = 2;
row4.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1];
colView = [UILabel new];
colView.text = @"Cell40";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor redColor];
[tbll addCol:colView atRow:4];
colView = [UILabel new];
colView.text = @"Cell41";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor greenColor];
[tbll addCol:colView atRow:4];
//第六行高度由子视图决定,均分宽度
[tbll addRow:MTLSIZE_WRAPCONTENT colSize:MTLSIZE_AVERAGE];
[tbll viewAtRowIndex:5].backgroundColor = [UIColor colorWithWhite:0.6 alpha:1];
colView = [UILabel new];
colView.text = @"Cell50";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor redColor];
colView.myHeight = 80;
[tbll addCol:colView atRow:5];
colView = [UILabel new];
colView.text = @"Cell51";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor greenColor];
colView.myHeight = 120;
[tbll addCol:colView atRow:5];
colView = [UILabel new];
colView.text = @"Cell52";
colView.textAlignment = NSTextAlignmentCenter;
colView.backgroundColor = [UIColor blueColor];
colView.myHeight = 70;
[tbll addCol:colView atRow:5];
}
orientation =MyLayoutViewOrientation_Horz 水平表格也就是一个瀑布流风格的表格,我们可以通过将表格放入到UIScrollView中进行从上到下的滚动以便展示所有内容。先看界面布局效果:
-(void)loadView
{
[super loadView];
self.view.backgroundColor = [UIColor blackColor];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:scrollView];
/*
创建一个水平的表格布局,水平表格布局主要用于建立瀑布流视图。需要注意的是水平表格中row也就是行是从左到右排列的,而每行中的col也就是列是从上到下排列的。
*/
_rootLayout = [MyTableLayout tableLayoutWithOrientation:MyLayoutViewOrientation_Horz];
_rootLayout.wrapContentWidth = NO;
_rootLayout.rowSpacing = 5;
_rootLayout.colSpacing = 10;
_rootLayout.padding = UIEdgeInsetsMake(5, 5, 5, 5); //分别设置表格布局里面的行间距、列间距、内部padding边距。
_rootLayout.widthSize.equalTo(scrollView.widthSize);
_rootLayout.wrapContentHeight = YES; //布局宽度和父视图一致,高度则由内容包裹。这是实现将布局视图加入滚动条视图并垂直滚动的标准方法。
[scrollView addSubview:_rootLayout];
//为瀑布流建立3个平均分配的行,每行的列的尺寸由内容决定。
[_rootLayout addRow:MTLSIZE_AVERAGE colSize:MTLSIZE_WRAPCONTENT];
[_rootLayout addRow:MTLSIZE_AVERAGE colSize:MTLSIZE_WRAPCONTENT];
[_rootLayout addRow:MTLSIZE_AVERAGE colSize:MTLSIZE_WRAPCONTENT];
}
-(void)handleAddColLayout:(id)sender
{
//获取表格布局中的每行的高度,找到高度最小的一行,如果高度都相等则选择索引号小的行。
CGFloat minHeight = CGFLOAT_MAX;
NSInteger rowIndex = 0;
for (NSInteger i = 0; i < self.rootLayout.countOfRow; i++)
{
UIView *rowView = [self.rootLayout viewAtRowIndex:i];
if (CGRectGetMaxY(rowView.frame) < minHeight)
{
minHeight = CGRectGetMaxY(rowView.frame);
rowIndex = i;
}
}
NSArray *images = @[@"p1-11",
@"p1-12",
@"p1-21",
@"p1-31",
@"p1-32",
@"p1-33",
@"p1-34",
@"p1-35",
@"p1-36",
@"image1",
@"image2",
@"image3"
];
static NSInteger sTag = 1000;
UIView *colLayout = [self createColLayout:images[arc4random_uniform((uint32_t)images.count)]
title:[NSString stringWithFormat:@"单元格标题:%03ld", (long)sTag]];
colLayout.tag = sTag++;
[self.rootLayout addCol:colLayout atRow:rowIndex];
}
下面代码是用来创建单元格视图的代码:
-(UIView*)createColLayout:(NSString*)image title:(NSString*)title
{
MyLinearLayout *colLayout = [MyLinearLayout linearLayoutWithOrientation:MyLayoutViewOrientation_Vert];
colLayout.gravity = MyGravity_Horz_Fill; //里面所有子视图的宽度都跟父视图保持一致,这样子视图就不需要设置宽度了。
colLayout.wrapContentHeight = YES;
colLayout.subviewSpace = 5; //设置布局视图里面子视图之间的间距为5个点。
colLayout.backgroundColor = [UIColor whiteColor];
[colLayout setTarget:self action:@selector(handleColLayoutTap:)];
colLayout.highlightedOpacity = 0.3; //设置触摸事件按下时的不透明度,来响应按下状态。
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:image]];
imageView.wrapContentHeight = YES; //这个属性重点注意!! 对于UIImageView来说,如果我们设置了这个属性为YES的话,表示视图的高度会根据视图的宽度进行等比例的缩放来确定,从而防止图片显示时出现变形的情况。
[colLayout addSubview:imageView];
UILabel *titleLabel = [UILabel new];
titleLabel.text = title;
titleLabel.font = [UIFont systemFontOfSize:13];
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.adjustsFontSizeToFitWidth = YES;
titleLabel.myBottom = 2;
[titleLabel sizeToFit];
[colLayout addSubview:titleLabel];
return colLayout;
}
可以看出我们通过一个水平表格就可以很轻松的实现瀑布流的效果。
四、总结
好了,表格布局的内容就介绍到这里了,表格布局的内部实现其实就是一个线性布局套线性布局的封装,但是他简化了我们插入视图的方法,从而很容易的布局出各种风格的布局,我们可以从上往下依次布局,也可以从左往右依次布局。如果您觉得这篇文章能够帮助到您,或者能成为您界面布局的解决方案,那么请到我的github:
https://github.com/youngsoft/MyLinearLayout 中下载这套界面解决框架库,如果您觉得好用就记得给我点赞哦,如果有什么不明确的可以加我QQ:156355113联系我。