纯手写自动布局会有时会让人欲哭无泪。Masonry出现让这一事情简单多了。
Masonry是什么?去问问度娘你就知道了。
下面是开发中几种常用的布局在Masonry中的应用Case.
****Case1:并排label
Case2:动态居中
Case3:百分比高度
Case4:UITableView(主要是cell的自动布局)
Case5:top(bottom)GuideView
Case6:自定义baseline****
话不多说,上代码。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//将ViewController作为UINavigationController对象中
ViewController *VC=[[ViewController alloc] init];
UINavigationController *navi=[[UINavigationController alloc] initWithRootViewController:VC];
self.window.rootViewController=navi;
return YES;
}
接下来的class:Case1ViewController、Case2ViewController、Case3ViewController、Case4ViewController皆继承自BaseViewController
#import <UIKit/UIKit.h>
#import "Masonry.h"
@interface BaseViewController : UIViewController
@end
接下来分开来看这四种case
Case1:并排label:并排两个label,整体靠左边,宽度随内容增长,左边的lable”优先级更高“
#import "Case1ViewController.h"
@interface Case1ViewController ()
@property(nonatomic,retain) UILabel *introductionLabel;
@property(nonatomic,retain) UIView *containView;
@property(nonatomic,retain) UIStepper *leftStepper;
@property(nonatomic,retain) UIStepper *rightStepper;
@property(nonatomic,retain) UILabel *label1;
@property(nonatomic,retain) UILabel *label2;
@end
@implementation Case1ViewController
#pragma mark - Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self uiConfig];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Private Method
-(void)uiConfig
{
[self.view addSubview:self.introductionLabel];
[self.introductionLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view.mas_centerX);
make.top.equalTo(self.view.mas_top).offset(100);
make.width.equalTo(@280);
make.height.equalTo(@70);
}];
[self.view addSubview:self.containView];
[self.containView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view.mas_left).offset(10);
make.right.equalTo(self.view.mas_right).offset(-10);
make.height.equalTo(@50);
make.top.equalTo(self.introductionLabel.mas_top).offset(100);
}];
//label1、label2
[self.containView addSubview:self.label1];
[self.containView addSubview:self.label2];
//lable1:位于左上角
[self.label1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.containView.mas_top).offset(5);
make.left.equalTo(_containView.mas_left).offset(2);
//高度 45
make.height.equalTo(@45);
}];
//label2:位于右上角
[_label2 mas_makeConstraints:^(MASConstraintMaker *make) {
//左边贴着label1
make.left.equalTo(_label1.mas_right).offset(2);
//上边贴着父view
make.top.equalTo(self.containView.mas_top).offset(5);
//右边的间隔保持大于等于2,注意是lessThanOrEqual
//这里的“lessThanOrEqual”放在从左往右的X轴上考虑会更好理解
//即:label2的右边界的X坐标值“小于等于“containView的右边界-2
make.right.lessThanOrEqualTo(self.containView.mas_right).offset(-2);
make.height.equalTo(@45);
}];
[self.view addSubview:self.leftStepper];
[self.leftStepper mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view.mas_left).offset(20);
make.top.equalTo(_containView.mas_bottom).offset(40);
make.width.equalTo(@80);
make.height.equalTo(@50);
}];
[self.view addSubview:self.rightStepper];
[self.rightStepper mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view.mas_right).offset(-20);
make.top.equalTo(_containView.mas_bottom).offset(40);
make.width.equalTo(@80);
make.height.equalTo(@50);
}];
//设置label1的content hugging 为1000
[_label1 setContentHuggingPriority:UILayoutPriorityRequired forAxis:
UILayoutConstraintAxisHorizontal];
//设置lable1的content compression为1000
[_label1 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
//设置label2的content hugging 为1000
[_label2 setContentHuggingPriority:UILayoutPriorityRequired forAxis:
UILayoutConstraintAxisHorizontal];
//设置lable2的content compression为1000
[_label2 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
}
-(void)stepperAction:(UIStepper *)kStepper
{
switch (kStepper.tag) {
case 1:
_label1.text=[self getLabelContentWithCount:(NSInteger)kStepper.value+1];
break;
case 2:
_label2.text=[self getLabelContentWithCount:(NSInteger)kStepper.value+1];
break;
default:
break;
}
}
-(NSString *)getLabelContentWithCount:(NSInteger)count
{
NSMutableString *ret=[NSMutableString new];
for (NSInteger i=0; i<count; i++) {
[ret appendString:@"label,"];
}
return ret;
}
#pragma mark - Setter And Getter
-(UILabel *)introductionLabel
{
if (_introductionLabel==nil) {
_introductionLabel=[[UILabel alloc] init];
_introductionLabel.numberOfLines=0;
_introductionLabel.text=@"并排两个label,整体靠左边,宽度随内容增长,左边的label‘优先级’更高";
_introductionLabel.textAlignment=NSTextAlignmentCenter;
_introductionLabel.textColor=[UIColor blackColor];
}
return _introductionLabel;
}
-(UIView *)containView
{
if (_containView==nil) {
_containView=[[UIView alloc] init];
_containView.backgroundColor=[UIColor lightGrayColor];
}
return _containView;
}
-(UIStepper *)leftStepper
{
if (_leftStepper==nil) {
_leftStepper=[[UIStepper alloc] initWithFrame:CGRectZero];
// _leftStepper.maximumValue=8;
_leftStepper.tag=1;
[_leftStepper addTarget:self action:@selector(stepperAction:) forControlEvents:UIControlEventValueChanged];
}
return _leftStepper;
}
-(UIStepper *)rightStepper
{
if (_rightStepper==nil) {
_rightStepper=[[UIStepper alloc] initWithFrame:CGRectZero];
// _l_rightStepper.maximumValue=8;
_rightStepper.tag=2;
[_rightStepper addTarget:self action:@selector(stepperAction:) forControlEvents:UIControlEventValueChanged];
}
return _rightStepper;
}
-(UILabel *)label1
{
if (_label1==nil) {
_label1=[[UILabel alloc] init];
_label1.backgroundColor=[UIColor yellowColor];
_label1.textColor=[UIColor blackColor];
_label1.text=@"label,";
_label1.textAlignment=NSTextAlignmentCenter;
}
return _label1;
}
-(UILabel *)label2
{
if (_label2==nil) {
_label2=[[UILabel alloc] init];
_label2.backgroundColor=[UIColor redColor];
_label2.textColor=[UIColor blackColor];
_label2.text=@"label,";
_label2.textAlignment=NSTextAlignmentCenter;
}
return _label2;
}
@end
Case2:动态居中:四个图标并排显示,隐藏、显示其中任意一个,整体保持居中
#import "Case2ViewController.h"
static const CGFloat IMAGE_SIZE = 32;
@interface Case2ViewController ()
@property(nonatomic,retain) UILabel *titleLabel;
@property(nonatomic,retain) UIView *containerView;
@property(nonatomic,retain) NSMutableArray *imageViews;
@property(nonatomic,retain) NSMutableArray *widthConstraints;
@property(nonatomic,retain) NSArray *imageNames;
@end
@implementation Case2ViewController
#pragma mark - Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self uiConfig];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Private Method
-(void)uiConfig
{
[self.view addSubview:self.titleLabel];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view.mas_centerX);
make.top.equalTo(self.view.mas_top).offset(100);
make.height.mas_equalTo(60);
make.width.mas_equalTo(300);
}];
[self.view addSubview:self.containerView];
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view.mas_centerX);
make.top.equalTo(self.view.mas_top).offset(200);
make.height.mas_equalTo(40);
}];
UIView *switchContain=[[UIView alloc] init];
switchContain.backgroundColor=[UIColor lightGrayColor];
switchContain.alpha=0.2;
[self.view addSubview:switchContain];
[switchContain mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view.mas_centerX);
make.top.equalTo(self.view.mas_top).offset(270);
make.width.mas_equalTo(270);
make.height.mas_equalTo(40);
}];
for (int i=0; i<4; i++) {
UISwitch *switchView=[[UISwitch alloc] init];
switchView.on=YES;
switchView.tag=10+i;
[switchView addTarget:self action:@selector(switchValueChanged:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:switchView];
[switchView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(40);
make.width.mas_equalTo(60);
make.top.equalTo(switchContain.mas_top).offset(5);
make.left.equalTo(switchContain.mas_left).offset(i*70);
}];
}
[self initImageViews];
}
-(void)initImageViews
{
//循环创建,添加imageView
for (int i=0; i<4; i++) {
UIImageView *imgView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:self.imageNames[i]]];
[self.imageViews addObject:imgView];
[self.containerView addSubview:imgView];
}
//设定大小
CGSize imageViewSize=CGSizeMake(IMAGE_SIZE, IMAGE_SIZE);
//分别设置每个imageView的宽高、左边、垂直中心约束
//并排排列
// UIImageView *imageView1 = self.imageViews[0];
// MASConstraint *width1 = [self setView:imageView1 size:imageViewSize left:self.containerView.mas_left centerY:self.containerView.mas_centerY];
// [self.widthConstraints addObject:width1];
// UIImageView *imageView2 = self.imageViews[1];
// MASConstraint *width2 = [self setView:imageView2 size:imageViewSize left:imageView1.mas_right centerY:self.containerView.mas_centerY];
// [self.widthConstraints addObject:width2];
// UIImageView *imageView3 = self.imageViews[2];
// MASConstraint *width3 = [self setView:imageView3 size:imageViewSize left:imageView2.mas_right centerY:self.containerView.mas_centerY];
// [self.widthConstraints addObject:width3];
// UIImageView *imageView4 = self.imageViews[3];
// MASConstraint *width4 = [self setView:imageView4 size:imageViewSize left:imageView3.mas_right centerY:self.containerView.mas_centerY];
// [self.widthConstraints addObject:width4];
// //最后设置最右边的imageView的右边与父view的最右对齐
// [imageView4 mas_makeConstraints:^(MASConstraintMaker *make) {
// make.right.equalTo(self.containerView.mas_right);
// }];
//
//或者用下面的方法布局imageView
UIView *frontView;
for (int i=0; i<self.imageViews.count; i++) {
UIImageView *imgView=self.imageViews[i];
[self.containerView addSubview:imgView];
MASViewAttribute *left=i==0?self.containerView.mas_left:frontView.mas_right;
[self.widthConstraints addObject:[self setView:imgView size:imageViewSize left:left centerY:self.containerView.mas_centerY]];
if (i==self.imageViews.count-1) {
[imgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.containerView.mas_right);
}];
}
frontView=imgView;
}
}
/*!
* 设置view的宽高、左边约束,垂直中心约束
*
* @param view 要设置的view
* @param size CGSize
* @param left 左边对其的约束
* @param centerY 水平对齐的约束
*
* @return 返回宽约束,用于显示、隐藏单个view
*/
- (MASConstraint *)setView:(UIView *)view size:(CGSize)size left:(MASViewAttribute *)left centerY:(MASViewAttribute *)centerY
{
__block MASConstraint *widthConstraint;
[view mas_makeConstraints:^(MASConstraintMaker *make) {
//宽高固定
widthConstraint = make.width.equalTo(@(size.width));
make.height.equalTo(@(size.height));
//左边约束
make.left.equalTo(left);
//垂直中心对齐
make.centerY.equalTo(centerY);
}];
return widthConstraint;
}
-(void)switchValueChanged:(UISwitch *)kSwitch
{
NSInteger tag=kSwitch.tag-10;
MASConstraint *width = self.widthConstraints[tag];
if (kSwitch.on) {
width.equalTo(@(IMAGE_SIZE));
} else {
width.equalTo(@0);
}
}
#pragma makr - Setter And Getter
-(UIView *)containerView
{
if (_containerView==nil) {
_containerView=[[UIView alloc] init];
_containerView.backgroundColor=[UIColor lightGrayColor];
}
return _containerView;
}
-(NSMutableArray *)imageViews
{
if (_imageViews==nil) {
_imageViews=[[NSMutableArray alloc] init];
}
return _imageViews;
}
-(NSMutableArray *)widthConstraints
{
if (_widthConstraints==nil) {
_widthConstraints=[[NSMutableArray alloc] init];
}
return _widthConstraints;
}
-(NSArray *)imageNames
{
if (_imageNames==nil) {
_imageNames=@[@"bluefaces_1",@"bluefaces_2",@"bluefaces_3",@"bluefaces_4"];
}
return _imageNames;
}
-(UILabel *)titleLabel
{
if (_titleLabel==nil) {
_titleLabel=[[UILabel alloc] init];
_titleLabel.textColor=[UIColor blackColor];
_titleLabel.numberOfLines=0;
_titleLabel.lineBreakMode=NSLineBreakByWordWrapping;
_titleLabel.textAlignment=NSTextAlignmentCenter;
_titleLabel.text=@"四个图标并排显示,隐藏、显示其中任意一个,整体保持居中。";
}
return _titleLabel;
}
@end
Case3:百分比宽度:子View的宽度始终是父View宽度的一半
#import "Case3ViewController.h"
static const CGFloat MAXWIDTH = 300;
@interface Case3ViewController ()
@property(nonatomic,retain) UILabel *kTitleLable;
@property(nonatomic,retain) UISlider *kSlider;
@property(nonatomic,retain) UIView *containerView;
@end
@implementation Case3ViewController
#pragma mark - Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self uiConfig];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Private Method
-(void)uiConfig
{
[self.view addSubview:self.kTitleLable];
[self.kTitleLable mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(300);
make.height.mas_equalTo(40);
make.top.equalTo(self.view.mas_top).offset(100);
make.centerX.equalTo(self.view.mas_centerX);
}];
[self.view addSubview:self.containerView];
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.kTitleLable.mas_left);
make.width.mas_equalTo(MAXWIDTH);
make.top.equalTo(self.kTitleLable.mas_bottom).offset(40);
make.height.mas_equalTo(60);
}];
UIView *subView=[[UIView alloc] init];
subView.backgroundColor=[UIColor blueColor];
[self.containerView addSubview:subView];
[subView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.containerView.mas_left);
make.bottom.equalTo(self.containerView.mas_bottom);
make.top.equalTo(self.containerView.mas_top);
make.width.equalTo(self.containerView.mas_width).multipliedBy(0.5);
}];
[self.view addSubview:self.kSlider];
[self.kSlider mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.containerView.mas_left);
make.right.equalTo(self.kTitleLable.mas_right);
make.top.equalTo(self.containerView.mas_bottom).offset(40);
make.height.mas_equalTo(40);
}];
}
#pragma mark - Action
-(void)kSliderAction:(UISlider *)mSlider
{
if (mSlider.value) {
[self.containerView mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(MAXWIDTH*mSlider.value);
}];
}
}
#pragma mark - Setter And Getter
-(UISlider *)kSlider
{
if (_kSlider==nil) {
_kSlider=[[UISlider alloc] initWithFrame:CGRectZero];
[_kSlider setValue:1];
[_kSlider addTarget:self action:@selector(kSliderAction:) forControlEvents:UIControlEventValueChanged];
}
return _kSlider;
}
-(UIView *)containerView
{
if (_containerView==nil) {
_containerView=[[UIView alloc] init];
_containerView.backgroundColor=[UIColor lightGrayColor];
_containerView.alpha=0.3;
}
return _containerView;
}
-(UILabel *)kTitleLable
{
if (_kTitleLable==nil) {
_kTitleLable=[[UILabel alloc] init];
_kTitleLable.textColor=[UIColor blackColor];
_kTitleLable.textAlignment=NSTextAlignmentCenter;
_kTitleLable.text=@"子View的宽度始终是父View宽度的一半";
_kTitleLable.numberOfLines=0;
_kTitleLable.lineBreakMode=NSLineBreakByWordWrapping;
}
return _kTitleLable;
}
@end
Case4:UITableView(主要是cell的自动布局):变高的cell+简单的高度缓存
方法1、调用systemLayoutSizeFittingSize:获取高度。
方法2、使用iOS8的Self-Sizing特性。
Case4ViewController中的代码如下:
#import "Case4ViewController.h"
#import "Case4CustomCell.h"
#import "Case4Model.h"
#define kIOS8 [UIDevice currentDevice].systemVersion.floatValue>=8.0
@interface Case4ViewController () <UITableViewDataSource,UITableViewDelegate>
@property(nonatomic,retain) UITableView *kTableView;
@property(nonatomic,retain) NSMutableArray *kDataSource;
@property(nonatomic,retain) UILabel *kTitleLabel;
@end
@implementation Case4ViewController
#pragma mark - Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:self.kTitleLabel];
[self.kTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view.mas_centerX);
make.width.mas_equalTo(300);
make.top.equalTo(self.view.mas_top).offset(64);
make.height.mas_equalTo(80);
}];
[self.view addSubview:self.kTableView];
[self loadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - UITableViewDataSource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.kDataSource.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Case4CustomCell *cell=[tableView dequeueReusableCellWithIdentifier:NSStringFromClass([Case4CustomCell class]) forIndexPath:indexPath];
[cell setDataModel:[self.kDataSource objectAtIndex:indexPath.row]];
return cell;
}
#pragma mark - UITableViewDelegate
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//
if (kIOS8) {
return UITableViewAutomaticDimension;
}else{
static Case4CustomCell *templeCell;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
templeCell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([Case4CustomCell class])];
});
// 获取对应的数据
Case4Model *model = self.kDataSource[indexPath.row];
// 填充数据
[templeCell setDataModel:model];
// 判断高度是否已经计算过
if (model.kHeight <= 0) {
// 根据当前数据,计算Cell的高度,注意+1
model.kHeight = [templeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 1;
NSLog(@"Calculate height: %ld", (long) indexPath.row);
} else {
NSLog(@"Get cache %ld", (long) indexPath.row);
NSLog(@"height=%f",model.kHeight);
}
return model.kHeight;
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - Private Method
-(void)loadData
{
for (int i=0; i<15; i++) {
Case4Model *model=[[Case4Model alloc] init];
model.kImgName=[NSString stringWithFormat:@"bluefaces_%d",arc4random()%4+1];
model.kTitle=[NSString stringWithFormat:@"row:%d",i];
model.kContent=[self getTextWithCount:i];
[self.kDataSource addObject:model];
}
[self.kTableView reloadData];
}
-(NSString *)getTextWithCount:(int)count
{
NSMutableString *tempStr=[[NSMutableString alloc] init];
while (count>0) {
[tempStr appendString:@"试问谁可,洁白无比。天空是什么颜色,你就是什么颜色。当潮流爱新鲜。"];
count-=1;
}
return tempStr;
}
#pragma mark - Setter And Getter
-(UITableView *)kTableView
{
if (_kTableView==nil) {
_kTableView=[[UITableView alloc] initWithFrame:CGRectMake(0,64+80+10, self.view.frame.size.width, self.view.frame.size.height-64-80-10) style:UITableViewStylePlain];
_kTableView.tableFooterView=[UIView new];
_kTableView.dataSource=self;
_kTableView.delegate=self;
if (kIOS8) {
_kTableView.estimatedRowHeight=60;
_kTableView.rowHeight=UITableViewAutomaticDimension;
}
[_kTableView registerClass:[Case4CustomCell class] forCellReuseIdentifier:NSStringFromClass([Case4CustomCell class])];
}
return _kTableView;
}
-(NSMutableArray *)kDataSource
{
if (_kDataSource==nil) {
_kDataSource=[[NSMutableArray alloc] init];
}
return _kDataSource;
}
-(UILabel *)kTitleLabel
{
if (_kTitleLabel==nil) {
_kTitleLabel=[[UILabel alloc] init];
_kTitleLabel.numberOfLines=0;
_kTitleLabel.backgroundColor=[UIColor orangeColor];
_kTitleLabel.textAlignment=NSTextAlignmentCenter;
_kTitleLabel.textColor=[UIColor blackColor];
_kTitleLabel.text=@"变高的cell+简单的高度缓存 方法1:调用systemLayoutSizeFittingSize:获取高度。方法2:使用iOS8的Self-Sizing特性";
}
return _kTitleLabel;
}
@end
Case4CustomCell中的代码如下:
#import "Case4CustomCell.h"
#import "Masonry.h"
static NSString *cellId=@"Case4CustomCell";
@interface Case4CustomCell ()
@property(nonatomic,retain) UIImageView *avatarView;
@property(nonatomic,retain) UILabel *kTitleLabel;
@property(nonatomic,retain) UILabel *contentLabel;
@end
@implementation Case4CustomCell
//重写初始化方法
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self=[super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
if (self) {
[self uiconfig];
}
return self;
}
#pragma mark - Public Method
-(void)setDataModel:(Case4Model *)kModel
{
NSString *imgName=kModel.kImgName;
self.avatarView.image=[UIImage imageNamed:imgName];
self.kTitleLabel.text=kModel.kTitle;
self.contentLabel.text=kModel.kContent;
}
#pragma mark - Private Method
-(void)uiconfig
{
[self.contentView addSubview:self.avatarView];
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.and.height.equalTo(@40);
make.left.and.top.equalTo(self.contentView).with.offset(4);
}];
[self.contentView addSubview:self.kTitleLabel];
[self.kTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@15);
make.top.equalTo(self.contentView).with.offset(4);
make.left.equalTo(_avatarView.mas_right).with.offset(4);
make.right.equalTo(self.contentView).with.offset(-4);
}];
CGFloat preferredMaxWidth = [UIScreen mainScreen].bounds.size.width - 44-10;
// Content - 多行
self.contentLabel.preferredMaxLayoutWidth = preferredMaxWidth; // 多行时必须设置
[self.contentView addSubview:self.contentLabel];
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_kTitleLabel.mas_bottom).with.offset(4);
make.left.equalTo(_avatarView.mas_right).with.offset(4);
make.right.equalTo(self.contentView).with.offset(-4);
make.bottom.equalTo(self.contentView).with.offset(-4);
}];
[_contentLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
}
#pragma mark - Setter And Getter
-(UIImageView *)avatarView
{
if (_avatarView==nil) {
_avatarView=[[UIImageView alloc] initWithFrame:CGRectZero];
_avatarView.layer.masksToBounds=YES;
_avatarView.layer.cornerRadius=20;
}
return _avatarView;
}
-(UILabel *)kTitleLabel
{
//单行
if (_kTitleLabel==nil) {
_kTitleLabel=[[UILabel alloc] init];
}
return _kTitleLabel;
}
-(UILabel *)contentLabel
{
if (_contentLabel==nil) {
_contentLabel=[[UILabel alloc] initWithFrame:CGRectZero];
_contentLabel.numberOfLines=0;
_contentLabel.textColor=[UIColor lightGrayColor];
_contentLabel.font=[UIFont systemFontOfSize:14];
_contentLabel.lineBreakMode=NSLineBreakByWordWrapping;
}
return _contentLabel;
}
@end
Case4Model:如下
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Case4Model : NSObject
@property(nonatomic,copy) NSString *kTitle;
@property(nonatomic,copy) NSString *kContent;
@property(nonatomic,copy) NSString *kImgName;
//保存计算过的高度
@property(nonatomic,assign) CGFloat kHeight;
@end
Case4:UITableView(主要是cell的自动布局):变高的cell+简单的高度缓存 情况二(和上一个差不多,只是补充了一个个人在一种出现的问题的解决方案)*
#import "ViewController.h"
#import "ViewControllerCell.h"
#import "ViewControllerModel.h"
#define kIOS8 [[UIDevice currentDevice] systemVersion].floatValue>7.0
@interface ViewController () <UITableViewDataSource,UITableViewDelegate>
@property(nonatomic,retain) UITableView *kTableView;
@property(nonatomic,retain) NSMutableArray *kDataSource;
@end
@implementation ViewController
#pragma mark - Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self uiConfig];
[self loadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - UITableViewDataSource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.kDataSource.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ViewControllerCell *cell=[tableView dequeueReusableCellWithIdentifier:NSStringFromClass([ViewControllerCell class]) forIndexPath:indexPath];
ViewControllerModel *model=[self.kDataSource objectAtIndex:indexPath.row];
[cell setDataModel:model];
return cell;
}
#pragma mark - UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (kIOS8) {
_kTableView.rowHeight=UITableViewAutomaticDimension;
}
static ViewControllerCell *templeCell;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
templeCell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([ViewControllerCell class])];
});
// 获取对应的数据
ViewControllerModel *model = self.kDataSource[indexPath.row];
// 填充数据
[templeCell setDataModel:model];
// 判断高度是否已经计算过
if (model.kHeight <= 0) {
// 根据当前数据,计算Cell的高度,注意+1
model.kHeight = [templeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 1;
NSLog(@"Calculate height: %ld", (long) indexPath.row);
} else {
NSLog(@"Get cache %ld", (long) indexPath.row);
NSLog(@"height=%f",model.kHeight);
}
return model.kHeight;
}
#pragma mark - Private Method
-(void)uiConfig
{
self.view.backgroundColor=[UIColor whiteColor];
[self.view addSubview:self.kTableView];
}
-(void)loadData
{
for (int i=0; i<20; i++) {
ViewControllerModel *model=[[ViewControllerModel alloc] init];
model.kTitle=[NSString stringWithFormat:@"row:%d",i];
model.kContent=[self getTextWithCount:arc4random()%20];
model.kImgName=[NSString stringWithFormat:@"bluefaces_%d",arc4random()%4+1];
[self.kDataSource addObject:model];
}
[self.kTableView reloadData];
}
-(NSString *)getTextWithCount:(int)kCount
{
NSMutableString *tempStr=[[NSMutableString alloc] init];
while (kCount>=0) {
[tempStr appendString:@"试问谁可,洁白无比"];
kCount-=1;
}
return tempStr;
}
#pragma mark - Setter And Getter
-(UITableView *)kTableView
{
if (_kTableView==nil) {
_kTableView=[[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain];
_kTableView.dataSource=self;
_kTableView.delegate=self;
if (kIOS8) {
_kTableView.estimatedRowHeight=60;
_kTableView.rowHeight=UITableViewAutomaticDimension;
}
[_kTableView registerClass:[ViewControllerCell class] forCellReuseIdentifier:NSStringFromClass([ViewControllerCell class])];
_kTableView.tableFooterView=[UIView new];
}
return _kTableView;
}
-(NSMutableArray *)kDataSource
{
if (_kDataSource==nil) {
_kDataSource=[[NSMutableArray alloc] init];
}
return _kDataSource;
}
@end
model如下:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ViewControllerModel : NSObject
@property(nonatomic,copy) NSString *kContent;
@property(nonatomic,copy) NSString *kTitle;
@property(nonatomic,copy) NSString *kImgName;
//简单的高度缓存
@property(nonatomic,assign) CGFloat kHeight;
@end
cell:如下
#import "ViewControllerCell.h"
#import "Masonry.h"
@interface ViewControllerCell ()
@property(nonatomic,retain) UILabel *kContentLabel;
@property(nonatomic,retain) UIImageView *avatarView;
@property(nonatomic,retain) UILabel *kTitleLabel;
@end
@implementation ViewControllerCell
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self uiConfig];
}
return self;
}
-(void)setDataModel:(ViewControllerModel *)kModel
{
UIImage *img=[UIImage imageNamed:kModel.kImgName];
self.avatarView.image=img;
self.kContentLabel.text=kModel.kContent;
self.kTitleLabel.text=kModel.kTitle;
}
#pragma mark - Private Method
-(void)uiConfig
{
//在使用Masonry布局的时候 与cell的关系一定要写成self.contentView 别问我为什么,我不会告诉你是惨痛的教训
[self.contentView addSubview:self.kContentLabel];
[self.kContentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView.mas_top).offset(4);
make.left.equalTo(self.contentView.mas_left).offset(10);
make.right.equalTo(self.contentView.mas_right).offset(-10);
}];
[self.kContentLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.contentView addSubview:self.avatarView];
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(40);
make.height.mas_equalTo(40);
make.left.equalTo(self.mas_left).offset(10);
make.top.equalTo(self.kContentLabel.mas_bottom).offset(4);
make.bottom.lessThanOrEqualTo(self.contentView.mas_bottom).offset(2);
}];
[self.contentView addSubview:self.kTitleLabel];
[self.kTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.contentView.mas_centerX);
make.width.mas_equalTo(100);
make.height.mas_equalTo(21);
make.bottom.equalTo(self.contentView.mas_bottom).offset(-5);
}];
}
#pragma mark - Setter And Getter
-(UILabel *)kContentLabel
{
if (_kContentLabel==nil) {
_kContentLabel=[[UILabel alloc] initWithFrame:CGRectZero];
_kContentLabel.font=[UIFont systemFontOfSize:16];
_kContentLabel.textColor=[UIColor lightGrayColor];
_kContentLabel.numberOfLines=0;
_kContentLabel.lineBreakMode=NSLineBreakByWordWrapping;
CGFloat maxWidth=[UIScreen mainScreen].bounds.size.width-30;
_kContentLabel.preferredMaxLayoutWidth=maxWidth;
}
return _kContentLabel;
}
-(UIImageView *)avatarView
{
if (_avatarView==nil) {
_avatarView=[[UIImageView alloc] initWithFrame:CGRectZero];
_avatarView.layer.masksToBounds=YES;
_avatarView.layer.cornerRadius=20;
}
return _avatarView;
}
-(UILabel *)kTitleLabel
{
if (_kTitleLabel==nil) {
_kTitleLabel=[[UILabel alloc] initWithFrame:CGRectZero];
_kTitleLabel.font=[UIFont systemFontOfSize:16];
}
return _kTitleLabel;
}
@end
Case5:top(bottom)GuideView:使用top(bottom)LayoutGuide确定当前ViewController的最佳显示范围
方法1:直接使用length属性,避免强制转换成UIView所带来的风险。
方法2:使用新的mas_topLayoutGuide和mas_bottomLayoutGuide
#import "Case5ViewController.h"
#define NEW_METHOD 1
@interface Case5ViewController ()
@property(nonatomic,retain) UILabel *kTitleLabel;
@property(nonatomic,retain) UILabel *kMethod1Label;
@property(nonatomic,retain) UILabel *kMethod2Label;
@property(nonatomic,retain) UIButton *kBtn1;//show or hide NavigationBar
@property(nonatomic,retain) UIButton *kBtn2;//show or hide ToolBar
@property(nonatomic,retain) UIView *kTopView;
@property(nonatomic,retain) UIView *kBottomView;
@end
@implementation Case5ViewController
#pragma mark - Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self uiConfig];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Override
-(void)updateViewConstraints
{
#ifdef NEW_METHOD
//根据新的length值更新约束
[_kTopView mas_updateConstraints:^(MASConstraintMaker *make) {
//直接利用其length属性,避免ios、SDK版本升级后topoLayouGuide不再是UIView
make.top.equalTo(self.view.mas_top).offset(self.topLayoutGuide.length);
}];
// 根据新的length值更新约束
[_kBottomView mas_updateConstraints:^(MASConstraintMaker *make) {
// 直接利用其length属性,避免iOS、SDK版本升级后topLayoutGuide不再是UIView
make.bottom.equalTo(self.view.mas_bottom).with.offset(-(self.bottomLayoutGuide.length));
}];
#endif
[super updateViewConstraints];
}
#pragma mark - Private Method
-(void)uiConfig
{
[self.view addSubview:self.kTitleLabel];
[self configLabel:self.kTitleLabel withTag:0];
[self.view addSubview:self.kMethod1Label];
[self configLabel:self.kMethod1Label withTag:1];
[self.view addSubview:self.kMethod2Label];
[self configLabel:self.kMethod2Label withTag:2];
[self.view addSubview:self.kBtn1];
[self configButton:self.kBtn1 withTag:11];
[self.view addSubview:self.kBtn2];
[self configButton:self.kBtn2 withTag:12];
[self.view addSubview:self.kTopView];
[self.kTopView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(40);
make.left.and.right.equalTo(self.view);
#ifdef NEW_METHOD
make.top.equalTo(self.mas_topLayoutGuide);
#endif
[self.view addSubview:self.kBottomView];
[self.kBottomView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(40);
make.left.and.right.equalTo(self.view);
#ifdef NEW_METHOD
make.bottom.equalTo(self.mas_bottomLayoutGuide);
#endif
}];
}];
}
-(void)configLabel:(UILabel *)newLabel withTag:(NSInteger)tag
{
newLabel.textAlignment=NSTextAlignmentCenter;
newLabel.textColor=[UIColor lightGrayColor];
newLabel.numberOfLines=0;
[newLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view.mas_left).offset(20);
make.right.equalTo(self.view.mas_right).offset(-20);
make.top.equalTo(self.view.mas_top).offset(80+tag*45);
}];
[newLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[newLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
}
-(void)configButton:(UIButton *)kBtn withTag:(NSInteger)tag
{
kBtn.tag=tag;
NSInteger number=tag-10;
[kBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[kBtn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];
[kBtn addTarget:self action:@selector(kBtnAction:) forControlEvents:UIControlEventTouchUpInside];
[kBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view.mas_top).offset(300+number*60);
make.height.mas_equalTo(20);
make.centerX.equalTo(self.view.mas_centerX);
}];
[kBtn setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[kBtn setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
}
-(void)kBtnAction:(UIButton *)mBtn
{
if (mBtn.tag==11) {
[self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden animated:YES];
}else{
[self.navigationController setToolbarHidden:!self.navigationController.toolbarHidden animated:YES];
}
[self updateViewConstraints];
}
#pragma mark - Setter And Getter
-(UILabel *)kTitleLabel
{
if (_kTitleLabel==nil) {
_kTitleLabel=[[UILabel alloc] initWithFrame:CGRectZero];
_kTitleLabel.text=@"使用top(bottom)LayoutGuide确定当前ViewController的最佳显示范围";
}
return _kTitleLabel;
}
-(UILabel *)kMethod1Label
{
if (_kMethod1Label==nil) {
_kMethod1Label=[[UILabel alloc] initWithFrame:CGRectZero];
_kMethod1Label.text=@"方法1:直接使用length属性,避免强制转换成UIView所带来的风险。";
}
return _kMethod1Label;
}
-(UILabel *)kMethod2Label
{
if (_kMethod2Label==nil) {
_kMethod2Label=[[UILabel alloc] initWithFrame:CGRectZero];
_kMethod2Label.text=@"方法2:使用新的mas_topLayoutGuide和mas_bottomLayoutGuide";
}
return _kMethod2Label;
}
-(UIButton *)kBtn1
{
if (_kBtn1==nil) {
_kBtn1=[UIButton buttonWithType:UIButtonTypeCustom];
[_kBtn1 setTitle:@"show or hide NavigationBar" forState:UIControlStateNormal];
}
return _kBtn1;
}
-(UIButton *)kBtn2
{
if (_kBtn2==nil) {
_kBtn2=[UIButton buttonWithType:UIButtonTypeCustom];
[_kBtn2 setTitle:@"show or hide ToolBar" forState:UIControlStateNormal];
}
return _kBtn2;
}
-(UIView *)kTopView
{
if (_kTopView==nil) {
_kTopView=[[UIView alloc] init];
_kTopView.backgroundColor=[UIColor orangeColor];
}
return _kTopView;
}
-(UIView *)kBottomView
{
if (_kBottomView==nil) {
_kBottomView=[[UIView alloc] init];
_kBottomView.backgroundColor=[UIColor brownColor];
}
return _kBottomView;
}
@end