此前我曾有几次专门查阅过 AutoLayout 的相关资料,好吧其实就是一些牛牛在自己的博客发表的使用教程及一些心得😂。一直都想着试一下但是一直没有什么时间来实践,这篇文章主要说的是我是怎样将 Masonry 移植到原有代码中。
如果你的项目中还没有 Masonry,你可以通过第三方管理平台 Cocoapods 来下载,如果有兴趣的话,可以看一下我之前整理的关于 Cocoapods 下载与安装的文章: IOS依赖管理 - CocoaPods.
首先简单介绍一下 Masonry,Masonry 是一款能够让开发者十分容易使用iOS的自动布局(AutoLayout)机制。Masonry提供更加完善、友好的API来代替直接使用NSLayoutConstraint进行编程,能够使视图布局的过程更加轻松。(好吧我承认这句话是我拷贝过来的😂,这不是重点)
而我对 Masonry 最初的认识是通过这篇文章:Masonry介绍与使用实践:快速上手Autolayout - CocoaChina 苹果开发中文站 - 最热的iPhone开发社区 最热的苹果开发社区 最热的iPad开发社区,并且我发现网络上流传的大部分关于 Masonry 的文章基本都来自于此,所以如果你对 Masonry 一点了解都没有,这篇文章确实是很不错的。
前期都铺垫完了,接下来咱们就看看我是怎样把原来好好的代码改成了 Autolayout 的好好的代码的了😂
这是一个饼图的控件:
之前的代码是这样的:
通过 initWithFrame 初始化控件的时候传进来的 frame 计算饼图的半径,根据计算出来的半径确定各个 view 的摆放位置:
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if(self){
self.backgroundColor = [UIColor clearColor];
//UIScollView 容器
_scrollContentView = [[UIScrollView alloc] initWithFrame:self.bounds];
_scrollContentView.backgroundColor = [UIColor clearColor];
[self addSubview:_scrollContentView];
//饼图
_pieView = [[UIView alloc] initWithFrame:self.bounds];
_pieView.backgroundColor = [UIColor clearColor];
[_scrollContentView addSubview:_pieView];
//饼图中心白色信息区域
_infoView = [[UIView alloc] initWithFrame:self.bounds];
_infoView.backgroundColor = [UIColor whiteColor];
[_scrollContentView addSubview:_infoView];
//颜色说明
_descriptionView = [[UIView alloc] initWithFrame:self.bounds];
_descriptionView.backgroundColor = [UIColor clearColor];
[_scrollContentView addSubview:_descriptionView];
//计算饼图半径
self.pieRadius = MIN(self.bounds.size.width/2, self.bounds.size.height/2) - kMarginX*2;
self.pieCenter = CGPointMake(self.bounds.size.width/2, _pieRadius + kMarginY);
_animationArr = [NSMutableArray array];
self.textRadius = _pieRadius - (_pieRadius-kInfoRadius)/2;
}
return self;
}
- (void)setPieCenter:(CGPoint)pieCenter{
[_pieView setCenter:pieCenter];
[_infoView setCenter:pieCenter];
//这个点是方便用来在饼图上面画扇叶用的,是以饼图为基准的中心值
_pieCenter = CGPointMake(_pieView.frame.size.width/2, _pieView.frame.size.height/2);
}
- (void)setPieRadius:(CGFloat)pieRadius{
_pieRadius = pieRadius;
CGRect frame = CGRectMake(_pieCenter.x - pieRadius, _pieCenter.y - pieRadius, pieRadius*2, pieRadius*2);
_pieCenter = CGPointMake(frame.size.width/2,frame.size.height/2);
//设置饼图 frame
[_pieView setFrame:frame];
[_pieView.layer setCornerRadius:_pieRadius];
CGFloat infoRadius = kInfoRadius;
frame = CGRectMake(_pieCenter.x - infoRadius, _pieCenter.y - infoRadius, infoRadius*2, infoRadius*2);
//设置白色信息图 frame
[_infoView setFrame:frame];
[_infoView.layer setCornerRadius:infoRadius];
}
从上面的代码,你应该能看出代码原来的逻辑顺序,这样处理代码的目的就是通过在初始化这个控件的时候就根据给定的 frame 宽高取最小值作为饼图的直径,进而确定饼图以及白色信息图的frame,但是前提我刚说了,一切都建立在 frame 是一个给出的固定值的基础上的。我这样说你可能会觉得奇怪,frame 本来就是一个固定好的确切的CGRect 啊什么鬼啊是不是神经啊😂 那么什么情况下你并不知道 frame 到底是多少呢?那就是我在初始化这个控件的时候也用了 AutoLayout,也就是说我在上一个界面就是通过约束来管理这个控件的布局,那么我只需要给定约束条件就好并不需要传一个固定的值来给这个控件,像这样:
WS(weakSelf);
_pie = [[PieChart alloc] initWithFrame:CGRectZero];
_pie.dataSource = self;
[self.view addSubview:_pie];
[_pie mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(weakSelf.view);
}];
就像你看到的,我在初始化的时候并没有给出一个固定好的有用的 frame,而是加了一句约束条件,这一句话的意思就是 pie 的大小要跟当前的 view 一样大,是的,这一切都是自动的。
那么现在我要做的就是让 pie 里面的部分控件也 autoLayout,但是我还是需要把 view 的 frame 告诉 pie,因为我原本有一个逻辑是需要取frame 宽高最小值来作为饼图的直径的,真恼人,那么我们就应该想办法告诉 pie 我现在的 frame 是多大,你再来做相应调整。好吧,我先来通知 pie:
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
_pie.frame = self.view.bounds;
}
那么现在我在 pie 里就需要改了:
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if(self){
self.backgroundColor = [UIColor clearColor];
WS(weakSelf);
_scrollContentView = [[UIScrollView alloc] initWithFrame:self.bounds];
_scrollContentView.backgroundColor = [UIColor clearColor];
[self addSubview:_scrollContentView];
[_scrollContentView mas_makeConstraints:^(MASConstraintMaker *make) {
//重点来了,scrollview 要求跟当前 view 一边大
make.edges.equalTo(weakSelf);
}];
__weak UIScrollView *weakScroll = _scrollContentView;
_pieView = [[UIView alloc] initWithFrame:self.bounds];
_pieView.backgroundColor = [UIColor clearColor];
[_scrollContentView addSubview:_pieView];
[_pieView mas_makeConstraints:^(MASConstraintMaker *make) {
//饼图中心点 X 值要跟 scrollview 一样,头部要在 scrollview 上留出kMarginY大小的距离
make.centerX.equalTo(weakScroll.centerX);
make.top.equalTo(weakScroll.top).with.offset(kMarginY);
}];
__weak UIView *weakPie = _pieView;
_infoView = [[UIView alloc] initWithFrame:self.bounds];
_infoView.backgroundColor = [UIColor whiteColor];
[_scrollContentView addSubview:_infoView];
[_infoView mas_makeConstraints:^(MASConstraintMaker *make) {
//白色信息图的中心点 X 值 Y 值都要跟饼图一样
make.centerX.equalTo(weakPie.centerX);
make.centerY.equalTo(weakPie.centerY);
}];
_descriptionView = [[UIView alloc] initWithFrame:self.bounds];
_descriptionView.backgroundColor = [UIColor clearColor];
[_scrollContentView addSubview:_descriptionView];
[_descriptionView mas_makeConstraints:^(MASConstraintMaker *make) {
//颜色说明 view 的宽度要跟 scrollview 一样,头部要在饼图底部距离kPieDesSpace的位置
make.width.equalTo(weakScroll);
make.top.equalTo(weakPie.bottom).with.offset(kPieDesSpace);
}];
}
return self;
}
-(void)setFrame:(CGRect)frame{
[super setFrame:frame];
self.pieRadius = MIN(self.bounds.size.width/2, self.bounds.size.height/2) - kMarginX*2;
_animationArr = [NSMutableArray array];
self.textRadius = _pieRadius - (_pieRadius-kInfoRadius)/2;
//注意这里用到的是 update,因为我之前已经对他们设置过约束,我只是想添加新的约束,如果还是用make 的话之前的所有约束都会无效,如果用 remake 的话就是把之前的相应约束替换掉。因为我现在已经知道 frame 了,现在我可以将他们的大小进行约束了
[_pieView updateConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(_pieRadius*2, _pieRadius*2));
}];
[_infoView updateConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(kInfoRadius *2, kInfoRadius *2));
}];
}
- (void)setPieRadius:(CGFloat)pieRadius{
_pieRadius = pieRadius;
[_pieView.layer setCornerRadius:_pieRadius];
[_infoView.layer setCornerRadius:kInfoRadius];
}
完成。
我已经不想再说什么啦,这个代码为毛只能一行一行的复制粘贴进去啊!并且我的空格怎么都不见了啊!我是手动的敲的这些空格啊!!手都快抽筋了啊啊啊!!!
好吧,其实这个复制粘贴代码这么难用我还是坚持着手动一行一行复制粘贴下来空格敲的这么完美,都是因为我的好朋友在帮我摘我最喜欢吃的樱桃准备给我寄过来!我不禁哼起歌来~一想到这呀~就让我快乐~贴一张图馋馋你们哈哈哈!
噢噢太激动了忘记了总结😒
其实一开始用autolayout我是拒绝的,想到要xb、sb还有官方那么繁琐的语句喔喔还有那个看不懂的象形文字😒我就浑身脑袋疼!但是现在有了这么方便的Masonry,就学来用用吧,毕竟苹果的屏幕大小已经开始不一样了,用一个朋友的话来说,autolayout是趋势。不管怎样,了解下总是好的😜