此前我曾有幾次專門查閱過 AutoLayout 的相關(guān)資料,好吧其實(shí)就是一些牛牛在自己的博客發(fā)表的使用教程及一些心得??。一直都想著試一下但是一直沒有什么時間來實(shí)踐劫侧,這篇文章主要說的是我是怎樣將 Masonry 移植到原有代碼中惭蹂。
如果你的項(xiàng)目中還沒有 Masonry挪捕,你可以通過第三方管理平臺 Cocoapods 來下載谒府,如果有興趣的話,可以看一下我之前整理的關(guān)于 Cocoapods 下載與安裝的文章: IOS依賴管理 - CocoaPods.
首先簡單介紹一下 Masonry浮毯,Masonry 是一款能夠讓開發(fā)者十分容易使用iOS的自動布局(AutoLayout)機(jī)制完疫。Masonry提供更加完善、友好的API來代替直接使用NSLayoutConstraint進(jìn)行編程债蓝,能夠使視圖布局的過程更加輕松壳鹤。(好吧我承認(rèn)這句話是我拷貝過來的??,這不是重點(diǎn))
而我對 Masonry 最初的認(rèn)識是通過這篇文章:Masonry介紹與使用實(shí)踐:快速上手Autolayout - ?CocoaChina 蘋果開發(fā)中文站 - 最熱的iPhone開發(fā)社區(qū) 最熱的蘋果開發(fā)社區(qū) 最熱的iPad開發(fā)社區(qū)饰迹,并且我發(fā)現(xiàn)網(wǎng)絡(luò)上流傳的大部分關(guān)于 Masonry 的文章基本都來自于此芳誓,所以如果你對 Masonry 一點(diǎn)了解都沒有,這篇文章確實(shí)是很不錯的啊鸭。
前期都鋪墊完了锹淌,接下來咱們就看看我是怎樣把原來好好的代碼改成了 Autolayout 的好好的代碼的了??
這是一個餅圖的控件:
之前的代碼是這樣的:
通過 initWithFrame 初始化控件的時候傳進(jìn)來的 frame 計(jì)算餅圖的半徑,根據(jù)計(jì)算出來的半徑確定各個 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];
? ? ? ? ?//餅圖中心白色信息區(qū)域
? ? ? ? ?_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];
? ? ? ? ?//計(jì)算餅圖半徑
? ? ? ? ?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];
? ? //這個點(diǎn)是方便用來在餅圖上面畫扇葉用的赠制,是以餅圖為基準(zhǔn)的中心值
? ? _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);
? ? //設(shè)置餅圖 frame
? ? [_pieView setFrame:frame];
? ? [_pieView.layer setCornerRadius:_pieRadius];
? ? CGFloat infoRadius = kInfoRadius;
? ? frame = CGRectMake(_pieCenter.x - infoRadius, _pieCenter.y - infoRadius, infoRadius*2, infoRadius*2);
? ? //設(shè)置白色信息圖 frame
? ? [_infoView setFrame:frame];
? ? [_infoView.layer setCornerRadius:infoRadius];
}
從上面的代碼赂摆,你應(yīng)該能看出代碼原來的邏輯順序,這樣處理代碼的目的就是通過在初始化這個控件的時候就根據(jù)給定的 frame 寬高取最小值作為餅圖的直徑钟些,進(jìn)而確定餅圖以及白色信息圖的frame烟号,但是前提我剛說了,一切都建立在 frame 是一個給出的固定值的基礎(chǔ)上的政恍。我這樣說你可能會覺得奇怪汪拥,frame 本來就是一個固定好的確切的CGRect 啊什么鬼啊是不是神經(jīng)啊?? 那么什么情況下你并不知道 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 的大小要跟當(dāng)前的 view 一樣大罕伯,是的曲伊,這一切都是自動的。
那么現(xiàn)在我要做的就是讓 pie 里面的部分控件也 autoLayout,但是我還是需要把 view 的 frame 告訴 pie,因?yàn)槲以居幸粋€邏輯是需要取frame 寬高最小值來作為餅圖的直徑的坟募,真惱人岛蚤,那么我們就應(yīng)該想辦法告訴 pie 我現(xiàn)在的 frame 是多大,你再來做相應(yīng)調(diào)整懈糯。好吧涤妒,我先來通知 pie:
-(void)viewWillAppear:(BOOL)animated{
? ? [super viewWillAppear:animated];
? ? _pie.frame = self.view.bounds;
}
那么現(xiàn)在我在 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) {
? ? ? ? ? ? ? //重點(diǎn)來了,scrollview 要求跟當(dāng)前 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) {
? ? ? ? ? ? ? //餅圖中心點(diǎn) 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) {
? ? ? ? ? ? ? //白色信息圖的中心點(diǎn) 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,因?yàn)槲抑耙呀?jīng)對他們設(shè)置過約束屿储,我只是想添加新的約束贿讹,如果還是用make 的話之前的所有約束都會無效,如果用 remake 的話就是把之前的相應(yīng)約束替換掉够掠。因?yàn)槲椰F(xiàn)在已經(jīng)知道 frame 了民褂,現(xiàn)在我可以將他們的大小進(jìn)行約束了
? ? [_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];
}
完成。
我已經(jīng)不想再說什么啦疯潭,這個代碼為毛只能一行一行的復(fù)制粘貼進(jìn)去霸伞赦政!并且我的空格怎么都不見了啊!我是手動的敲的這些空格疤棠弧6パ唷欢瞪!手都快抽筋了啊啊暗型辍!6鄣础街立!
好吧,其實(shí)這個復(fù)制粘貼代碼這么難用我還是堅(jiān)持著手動一行一行復(fù)制粘貼下來空格敲的這么完美埠通,都是因?yàn)槲业暮门笥言趲臀艺易钕矚g吃的櫻桃準(zhǔn)備給我寄過來赎离!我不禁哼起歌來~一想到這呀~就讓我快樂~貼一張圖饞饞你們哈哈哈!
噢噢太激動了忘記了總結(jié)??
其實(shí)一開始用autolayout我是拒絕的端辱,想到要xb梁剔、sb還有官方那么繁瑣的語句喔喔還有那個看不懂的象形文字??我就渾身腦袋疼!但是現(xiàn)在有了這么方便的Masonry舞蔽,就學(xué)來用用吧荣病,畢竟蘋果的屏幕大小已經(jīng)開始不一樣了,用一個朋友的話來說渗柿,autolayout是趨勢个盆。不管怎樣脖岛,了解下總是好的??