随着约束布局的越来越流行,很多项目正在逐步由frame布局转移到约束布局。最近就有几个朋友说道,新项目要求用约束来布局,而用约束来进行布局,Masonry作为一个强大的三方库,就不得不提了。此篇文章,就是简单的使用Masonry来进行布局,以tableView为实例,进行讲解,在demo里会有相应的注释。这个demo,感觉能满足基本的需求,若有哪里不足或不正确,欢迎指出。
注意:如果你的项目,父视图是ScrollView,那么我建议你,还是不要用Masonry。scrollView自身就是有约束设置的,再用Masonry进行子视图的约束,子视图的约束将会失效,当然如果你有很长的时间来研究scrollView自身约束和Masonry库约束的冲突的话(这里姑且让我用冲突这个词语吧),那你可以肆无忌惮的使用Masonry库了。
效果图在结尾处
下面直接贴代码:
ViewController.m文件
#import "ViewController.h"
#import "TableViewCell.h"
#import "TableViewModel.h"
#import "TableHeaderView.h"
#import "Masonry.h"
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
@property (nonatomic,strong)TableHeaderView *headerView;
@property (nonatomic,strong)UITableView *tableView;
@property (nonatomic,strong)NSMutableArray *dataSource;
@end
static NSString *const cellIdentifier =@"cellIdentifier";
@implementation ViewController
- (void)viewDidLoad
{
[superviewDidLoad];
[self loadData];
}
- (void)loadData
{
self.dataSource = [NSMutableArrayarrayWithCapacity:0];
for (int i =0; i <20; i++)
{
TableViewModel *model = [[TableViewModelalloc]init];
if (i %2 ==0)
{
model.isLeft = @"1";
model.title = @"这是左侧的title";
model.headerTitle =@"这是imageView在左侧的组头上的title";
}
else
{
model.isLeft = @"0";
model.title =@"这是右侧的title这是右侧的title";
model.headerTitle =@"这是imageView在右侧的组头上的title";
}
[self.dataSourceaddObject:model];
}
[self.tableViewreloadData];
}
- (UITableView *)tableView
{
if (_tableView ==nil)
{
//使用约束布局,将frame置为CGRectZero
self.tableView = [[UITableViewalloc]initWithFrame:CGRectZerostyle:UITableViewStyleGrouped];
self.tableView.delegate =self;
self.tableView.dataSource =self;
self.tableView.rowHeight =86.0f;
[self.tableViewregisterClass:[TableViewCellclass]forCellReuseIdentifier:cellIdentifier];
[self.viewaddSubview:self.tableView];
//此处约束设置,必须保证此对象已经添加到父视图上
[self.tableViewmas_makeConstraints:^(MASConstraintMaker *make) {
//头部相对于父视图10个像素
make.top.equalTo(self.view.mas_top).offset(20);
//相对父视图做约束(此处表示:左,右部,均相对于父视图0个像素。此处代码不唯一,cell中另有其他写法)
make.left.and.right.equalTo(self.view);
//底部相对于父视图10个像素(注意:设置底部和右侧约束时,要使用负数)
make.bottom.equalTo(self.view).offset(-10);
//mas_equalTo方法,设置绝对距离
// make.height.mas_equalTo([UIScreen mainScreen].bounds.size.height - 10);
}];
}
return_tableView;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.dataSource.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:cellIdentifierforIndexPath:indexPath];
if (self.dataSource.count >0)
{
TableViewModel *model = self.dataSource[indexPath.section];
[cell configCellWithModel:model];
}
return cell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
/**
此处为tableView的组头view,注意,此处组头view要使用frame来进行布局,不能使用Masonry约束布局。
原因:组头view本身所属于tableView,并没有兄弟/父子视图关系,使用Masonry进行约束布局,只能作用于父子/兄弟视图间。
我是这么理解的,可能理解有误,在这里我只是提醒一下,不能使用Masonry对组头视图布局,组尾视图是一样的道理。
*/
TableHeaderView *headerView = [[TableHeaderViewalloc]initWithFrame:CGRectMake(0,0,self.view.frame.size.width,50)];
TableViewModel *model = self.dataSource[section];
[headerView configHeaderViewWithModel:model];
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 0.01;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 50.0f;
}
- (void)didReceiveMemoryWarning
{
[superdidReceiveMemoryWarning];
}
@end
Cell类
TableViewCell.h 文件
#import <UIKit/UIKit.h>
@class TableViewModel;
@interface TableViewCell : UITableViewCell
@property (nonatomic,strong)UIImageView *imgView;
@property (nonatomic,strong)UILabel *titleLabel;
- (void)configCellWithModel:(TableViewModel *)model;
@end
TableViewCell.m 文件
#import "TableViewCell.h"
#import "TableViewModel.h"
#import "Masonry.h"
static CGFloat width =220;
@implementation TableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [superinitWithStyle:stylereuseIdentifier:reuseIdentifier];
if (self)
{
self.selectionStyle =UITableViewCellSelectionStyleNone;
[self configUI];
}
return self;
}
- (void)configUI
{
if (!self.imgView)
{
self.imgView = [UIImageViewnew];
[self.contentViewaddSubview:self.imgView];
//初始化设置约束
[self.imgViewmas_makeConstraints:^(MASConstraintMaker *make) {
//设置左侧相对于父视图20个像素
make.left.equalTo(self.contentView.mas_left).offset(20);
//设置y坐标中心点
make.centerY.equalTo(self.contentView.mas_centerY);
//设置宽和高的绝对距离
make.width.mas_equalTo(100);
make.height.mas_equalTo(66);
}];
}
if (!self.titleLabel)
{
self.titleLabel = [UILabelnew];
self.titleLabel.font = [UIFontsystemFontOfSize:15];
self.titleLabel.backgroundColor = [UIColorlightGrayColor];
self.titleLabel.textColor = [UIColorwhiteColor];
[self.contentViewaddSubview:self.titleLabel];
[self.titleLabelmas_makeConstraints:^(MASConstraintMaker *make) {
//此对象的左侧,相对于兄弟视图的右侧做约束
make.left.equalTo(self.imgView.mas_right).offset(10);
make.centerY.equalTo(self.contentView.mas_centerY);
make.height.mas_equalTo(30);
//若不给对象设置宽度,则此对象的宽度以展示的文字长度为宽度,但此时其他兄弟视图不能以此对象的右侧作为约束对象,
//若类似于此demo这种场景,兄弟视图在模型赋值时改变位置,而此时此对象并未主动更新约束位置。当兄弟视图改变位置后,此对象也会根据兄弟视图进行位置变换,不过此对象相对于兄弟视图的位置不会改变
}];
}
}
- (void)configCellWithModel:(TableViewModel *)model
{
if ([model.isLeftintegerValue] ==1)
{
self.titleLabel.text = model.title;
[self.imgViewsetImage:[UIImageimageNamed:@"1.jpg"]];
//当已经初始化了约束,而此时此对象的位置需要改变,则使用mas_updateConstraints方法,更新约束位置
[self.imgViewmas_updateConstraints:^(MASConstraintMaker *make) {
//设置对象相对于父视图约束还可以这样写
make.left.equalTo(@20);
make.right.equalTo(self.contentView).offset(- ([UIScreenmainScreen].bounds.size.width -120));
}];
}
else
{
self.titleLabel.text = model.title;
[self.imgViewsetImage:[UIImageimageNamed:@"2.jpg"]];
[self.imgViewmas_updateConstraints:^(MASConstraintMaker *make) {
//设置对象相对于父视图约束也可以这样写
make.left.offset([UIScreenmainScreen].bounds.size.width -100 - width);
make.right.offset(-width);
}];
}
}
@end
模型类
#import <Foundation/Foundation.h>
@interface TableViewModel : NSObject
@property (nonatomic,copy)NSString *isLeft;
@property (nonatomic,copy)NSString *title;
@property (nonatomic,copy)NSString *headerTitle;
@end
组头类
TableHeaderView.h 文件
#import <UIKit/UIKit.h>
@class TableViewModel;
@interface TableHeaderView : UIView
@property (nonatomic,strong)UILabel *headerTitleLabel;
- (void)configHeaderViewWithModel:(TableViewModel *)model;
@end
TableHeaderView.m 文件
#import"TableHeaderView.h"
#import "TableViewModel.h"
#import "Masonry.h"
@implementation TableHeaderView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [superinitWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColorgrayColor];
[self configUI];
}
return self;
}
- (void)configUI
{
if (!self.headerTitleLabel)
{
self.headerTitleLabel = [UILabelnew];
self.headerTitleLabel.font = [UIFontsystemFontOfSize:15];
self.headerTitleLabel.textAlignment = NSTextAlignmentCenter;
self.headerTitleLabel.textColor = [UIColorwhiteColor];
[selfaddSubview:self.headerTitleLabel];
[self.headerTitleLabelmas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.mas_centerX);
make.centerY.equalTo(self.mas_centerY);
make.height.mas_equalTo(30);
//此处不约束宽度也是可以的
make.width.mas_equalTo([UIScreenmainScreen].bounds.size.width);
}];
}
}
- (void)configHeaderViewWithModel:(TableViewModel *)model
{
self.headerTitleLabel.text = model.headerTitle;
}
@end