初識(shí)
在IOS中最常用的兩種布局方式是Frame布局和AutoLayout布局。本文主要講解Frame布局的相關(guān)知識(shí)譬涡。
Frame布局使用簡(jiǎn)單闪幽,適合初學(xué)者,可以采用手寫或者xib進(jìn)行布局涡匀,適用于比較簡(jiǎn)單的界面布局盯腌,復(fù)雜的布局如果使用Frame布局邏輯會(huì)很復(fù)雜,不利于布局和后期維護(hù)陨瘩。
Frame的數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單腕够,類型為CGRect,其中original屬性定義point舌劳,size屬性定義大小帚湘,初始化成功一個(gè)Frame布局之后,可以使用setFrame修改布局甚淡。frame的值影響自己的布局大诸,bounds只影響其子view的布局。
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[self.view addSubview:view];
適用場(chǎng)景
有時(shí)候會(huì)遇到一些稍微復(fù)雜度一點(diǎn)的界面布局贯卦,這時(shí)候可以使用函數(shù)或者對(duì)象封裝原生的frame布局方法资柔,好的封裝讓我們可以使用鏈?zhǔn)讲季諿^1]的方法,和更簡(jiǎn)單的方式進(jìn)行frame布局撵割。
已經(jīng)有前人實(shí)現(xiàn)了frame布局的相對(duì)布局[5]
也有三方庫(kù)支持像使用masory一樣使用frame布局[6]和[7]
但是很復(fù)雜的界面就不建議使用frame布局了贿堰,可以使用autolayout布局,當(dāng)然還有其它布局方式睁枕,這兒不討論官边。
Frame布局的效率比AutoLayout高得多,下面是他們的效率比較圖表外遇。
圖片來(lái)源和性能分析更詳細(xì)可參考[2]
調(diào)試
可以使用系統(tǒng)自帶的debug view hierachy和第三方的Reveal查看當(dāng)前界面的布局情況注簿。
Debug view hierachy:
Reveal:
可以在lldb中使用po查看view的frame值,這也是我們調(diào)試界面布局的一個(gè)重要參考指標(biāo)跳仿,如果不能查看诡渴,需要手動(dòng)在lldb中運(yùn)行e @import UIKit,然后po就可以了菲语。(如果不清楚po是什么妄辩,需要先去看下lldb的基礎(chǔ)知識(shí))
Frame動(dòng)畫
可以通過(guò)改變frame布局的值來(lái)實(shí)現(xiàn)一些簡(jiǎn)單的動(dòng)畫,當(dāng)然這兒不使用frame是因?yàn)?br> 一般外部使用view,使用frame山上;內(nèi)部使用或者定義view眼耀,使用bounds;動(dòng)畫和旋轉(zhuǎn)一般基于center來(lái)進(jìn)行佩憾,很少通過(guò)操作frame哮伟。
[UIView animateWithDuration:0.5 animations:^{
self.view.center = CGPointMake(20, 20);
} completion:^(BOOL finished) {
//do something
}];
Frame的本質(zhì)
每個(gè)view都有一個(gè)frame干花,這個(gè)frame實(shí)際是layer的frame,view只是透?jìng)鱢rame的值楞黄。修改view的frame布局池凄,其實(shí)修改的是layer的frame布局。
Frame屬性只是一個(gè)計(jì)算屬性鬼廓,它最后的值由bounds肿仑,anchor,position和transform這幾個(gè)實(shí)際屬性計(jì)算獲得碎税,他們之間會(huì)相互影響尤慰。具體的算法如下,參考文章[3]和參考[4]蚣录。
下面是frame計(jì)算的偽代碼
-(CGRect)frame
{
CGRect retValue = CGRectZero;
if (CGAffineTransformIsIdentity(self.transform))
{ //沒(méi)有設(shè)置仿射變換的情況下
//位置等于中心點(diǎn)的位置減去視圖尺寸乘以錨點(diǎn)的值割择。
retValue.origin.x = self.center.x - self.bounds.size.width * self.layer.anchorPoint.x;
retValue.origin.y = self.center.y - self.bounds.size.height * self.layer.anchorPoint.y;
//尺寸等于視圖的尺寸
retValue.size.width = self.bounds.size.width;
retValue.size.height = self.bounds.size.height;
}
else
{
CGAffineTransform left = CGAffineTransformMakeTranslation(-1 * self.bounds.size.width * self.layer.anchorPoint.x, -1 * self.bounds.size.height * self.layer.anchorPoint.y);
//因?yàn)橄旅娴淖鴺?biāo)變換應(yīng)用是從(0,0)開始的,因此這里的right指定中心點(diǎn)的位置萎河,也就是下面的復(fù)合變換右乘right來(lái)實(shí)現(xiàn)位置的變換處理荔泳。
CGAffineTransform right = CGAffineTransformMakeTranslation(self.center.x, self.center.y);
//整個(gè)復(fù)合變換是left 左乘 視圖的tansform屬性然后再右乘right變換。
CGAffineTransform concat = CGAffineTransformConcat(CGAffineTransformConcat(left, self.transform), right);
retValue = CGRectApplyAffineTransform(CGRectMake(0,0,self.bounds.size.width, self.bounds.size.height), concat);
}
return retValue
}
立即刷新Frame
frame布局可以使用setneedlayout設(shè)置刷新布局標(biāo)志位虐杯,如果需要立即刷新調(diào)用layoutifneed方法玛歌,會(huì)立即觸發(fā)調(diào)用layoutsubviews,你可以在這個(gè)接口中做很多事擎椰,比如你可以在這個(gè)接口里面刷新它父親的布局支子。
@implementation ViewController
-(void)viewDidLayoutSubviews
{
//Second
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView* test = [[UIView alloc] initWithFrame:CGRectMake(0, 44, 20, 20)];
test.backgroundColor = [UIColor blackColor];
[self.view addSubview:test];//First
[self.view layoutIfNeeded];
NSLog(@"3"); //Third
}
@end
從上述代碼中的First,Second和Third可以看出執(zhí)行順序达舒。
Autoresizingmask
使用Autoresizingmask值朋,系統(tǒng)會(huì)自動(dòng)生成frame布局,并且這個(gè)布局在父view變化的時(shí)候會(huì)跟隨變化巩搏。
適配
frame布局在處理適配的問(wèn)題上比autolayout需要做更多工作昨登。frame布局在適配不同的機(jī)型上可能會(huì)出現(xiàn)很多的魔法變量,當(dāng)然可以用宏定義解決一部分問(wèn)題贯底,但是會(huì)使得后期難以維護(hù)和理解丰辣,畢竟代碼大部分時(shí)間都是用來(lái)閱讀的,所以可讀性還是很重要的禽捆。
[1] 鏈?zhǔn)讲季郑?a href="http://www.reibang.com/p/67fd5332e7b9" target="_blank">http://www.reibang.com/p/67fd5332e7b9
[2] 性能分析:https://draveness.me/layout-performance
[3] Frame計(jì)算:http://www.reibang.com/p/a12cc7356c99
[4] Frame計(jì)算:http://www.reibang.com/p/00482643234d
[5] Frame相對(duì)布局:https://github.com/huisedediao/UIView-FrameLayout
[6] Frame相對(duì)布局:http://www.reibang.com/p/d99e94e6b9f9
[7] Frame相對(duì)布局:http://www.reibang.com/p/b76947766583