如今蘋果生態圈中的設備尺寸也已經變得種類繁多了,設備種類以下:
iPad:iPad1,iPad2,newPad,iPad4,iPad air,iPad air2,iPad mini1,iPad mini2,iPad mini3,iPad pro;
iPhone:iPhone3Gs,iPhone4,iPhone4S,iPhone5,iPhone5S,iPhone5C iPhone6,iPhone6 Plus,iPhone6S,ipad iPhone6S Plus;
iWatchios
屏幕大小:markdown
想必蘋果也意識到這一點。都知道蘋果是以化繁爲簡的設計哲學深刻人心的,此次再一次證實了。SizeClass是對設備尺寸的一個抽象概念,如今任何設備的 長、寬 被簡潔地分爲三種狀況:普通 (Regular) 、緊密 (Compact) 和 任意(Any) ,這樣,根據長和寬不一樣的搭配就能產生 3 * 3 = 9 種不一樣尺寸。下圖展現個每種狀況對應的設備。工具
之前爲不一樣的iOS設備尺寸或者同尺寸橫豎屏不一樣適配UI,都要根據實際狀況而去計算frame。使用Size Classes是根據當前的屏幕size類型而使用Auto Layout方式進行佈局了,要摒棄以前計算frame的思路,而改用相對佈局的思惟去思考(實際上仍是要計算frame).佈局
並且Xcode6最大的突破也是這裏,不在須要創建不一樣尺寸的storyboard了,只要創建一個,而後修改其view的size就能夠作各類屏幕尺寸的適配,以下:動畫
例如我要作iPad頁面設計,就設置成w (Regular)/h(Regular)ui
而後一樣的工程,又要兼容橫屏的iPhone6 plus,就能夠把view的size class設置成:w (Regular)/h(Compact),而後繼續適配spa
而後當程序跑在不一樣的設備上,或者設備橫屏和豎屏切換,就能顯示相應的UI了。.net
示例:設計
適配iPhone6,在RootViewController的view上添加一個新的view,讓這個新的view不管屏幕橫屏仍是豎屏時候都距離其superview的邊緣50點寬,而且橫屏時候爲綠顏色,豎屏時候爲紅顏色。3d
操做以下:
而且添加一個view,不用管其frame,並設置其背景色爲紅色
接下來選中紅色的view,而後點擊Xcode頂部工具欄的Editor-Pin,而後分別添加紅色view相對superview邊框的約束(上下左右
添加約束的過程當中會看到約束的線是黃顏色,代表當前的約束還不能肯定view的frame,須要繼續添加,當添加完4個約束後,約束線的顏色是藍色的,代表當前約束是正確的。
而後選中約束,設定約束的值(咱們不是想讓新的view距離其superview邊界50點寬嗎!),4個約束都要設置。
設置完後點擊下view會自動更新frame,應該是這樣的:
2.切換size class爲wRegular/hCompact模式,而後重複第一步中的設置,區別是新添加的view背景顏色設置爲綠色。
示例2:
基於iPhone適配界面,添加三個view到rootView上,而後不管橫屏仍是豎屏,新添加的三個view之間及與屏幕邊框的距離都保持不變的間距20點寬,效果如圖:
由於要適配iPhone橫豎屏,因此修改size class爲wCompact/hRegular來適配豎屏:拖拽3個view到rootView上,並設置其背景顏色
爲了知足設計要求,要添加以下constraint:
操做以下:
選中綠色view,Eidtor->Pin->Leading Space to Superview給綠色view添加相對其superview的左邊距,而後選中constraint,修改約束的值爲20,其餘constraint以此類推
添加完如圖:
其中紅色框部分清晰的表達了所添加的constraint;藍色框部分時添加的constraint,目前爲黃色線,代表當前的constraint還不能定位view,當一個view的constraint正確的時候,constraint的顏色會變爲藍色。綠色線框的部分表達了constraint的數值,咱們想讓邊距爲20,因此設置數值爲20 。wC hR Installed代表當前constraint適用於wC hR這種size class,不適合any any的size class。
添加綠色view與黃色view以前的距離時候,因爲是設定兩個子view的constraint,因此要選中兩個view,而後Editor->Pin ->Horizontal,設定值爲20:
一樣方法Editor->Pin ->Width Equally,設定綠色view與黃色view等寬度,藍色view與綠色view等高,結果如圖:
但發現constraint顏色仍而後黃色,緣由是當前view的位置和constraint但願的不一致,更新下frame(要選中3個view,由於constraint關聯3個view)或者點擊Document Outline中的黃色小箭頭,而後會看到具體的constraint信息來一步步調試,這個也是Xcode6最有突破的地方:
而後效果如圖:
而後運行下項目吧,發現確實和預期的同樣。而後旋轉屏幕,是否是發現橫屏時候白了,屏幕什麼都沒有了?緣由是咱們僅僅適配的豎屏,橫屏尚未適配啊!
修改size class,iPhone4s橫屏的size class爲wCompact/hCompact,而iPhone6 plus爲wReguage/hCompact,那咱們不如設置爲wAny/hCompact吧!而後安裝上邊適配豎屏的方式適配橫屏。適配好後再次運行,橫豎屏都應該是咱們想要的了。
小小技巧: 查看不一樣設備適配狀況
在 ios6 以前沒有AutoLayout佈局UI,咱們佈局UI是基於固定的frame,bound對控件的佈局,設置控件的 位置(x,y), 尺寸(width,height)就能夠把控件放在相應的位置。
出現Autolayout後,咱們用AutoLayout佈局控件就要把以前固定設置frame、bound忘記;要想佈局顯示一個控件,Autolayout以兩個詞:約束,參照 動態設置一個控件兩個東西,位置,尺寸;
小結:
1. 添加約束不宜過多,當添加的約束足以表達該控件的位置與尺寸,就足夠了 2. 約束就是對控件的大小或者位置進行約束,參照就是以某個控件的位置進行約束,其實這二者沒有明確的分別,它們均可以對控件的位置與尺寸起到做用。
1)手動添加約束(蘋果官方API)
/** * 這個是系統默認添加約束的方法,它是NSLayoutConstraint的類方法 * * @param view1 傳入想要添加約束的控件 * @param attr1 傳入想要添加約束的方向,這個枚舉值有不少,能夠本身看看 * @param relation 傳入與約束值的關係,大於,等於仍是小於 * @param view2 傳入被參照對象 * @param attr2 傳入被參照對象所被參照的方向,如頂部,左邊,右邊等等 * @param multiplier 傳入想要的間距倍數關係 * @param c 傳入最終的差值 * * @return NSLayoutConstraint對象 */ +(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c //一部分NSLayoutAttribute枚舉值 NSLayoutAttributeLeft = 1,//控件左邊 NSLayoutAttributeRight,//控件右邊 NSLayoutAttributeTop, NSLayoutAttributeBottom, NSLayoutAttributeLeading,//控件左邊 NSLayoutAttributeTrailing,//控件右邊 NSLayoutAttributeWidth,//控件的寬 NSLayoutAttributeHeight,//控件的高 NSLayoutAttributeCenterX,//豎直方向中點 NSLayoutAttributeCenterY,//水平方向中點
這個方法的參數我很想用形象的語言描述出來,可是仍是想不出,更多須要你們從下面的代碼中傳入的參數去體會
//建立redView UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; redView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:redView]; //建立redView第一個約束,相對self.view的左邊緣間距20 NSLayoutConstraint * redLeftLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeLeftMargin relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:20.0]; //只有在沒有參照控件的狀況下,約束才加到自身,否則加到父控件上 [self.view addConstraint:redLeftLc]; //建立redView第二個約束,相對self。view的底邊緣間距20 NSLayoutConstraint *redBottomLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottomMargin multiplier:1.0f constant:-20];//因爲是redview相對self.view往上減20,因此是-20 //添加約束 [self.view addConstraint:redBottomLc]; //這裏直接設置自身寬爲50 NSLayoutConstraint * redWLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0f constant:50.0f]; //因爲沒有參照物,因此約束添加於自身身上 [redView addConstraint:redWLc]; //建立最後一個約束,自身的高 NSLayoutConstraint * redHLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0f constant:50]; //因爲沒有參照物,因此約束添加於自身身上 [redView addConstraint:redHLc];
運行的效果圖
接下來咱們繼續增長需求,在紅色方塊的右邊放一個離它20間距,離self.view底部也間距20,寬高相等的藍色方塊
//先建立一個一個藍色的view添加到視圖上,剩下的就是用autolayout來設置它的「frame」了 UIView *blueView = [[UIView alloc]init]; blueView.backgroundColor = [UIColor blueColor]; blueView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:blueView]; self.blueView = blueView; //建立第一個約束,左邊間距,因爲是想要與紅色有20的間距,那麼參照參數「toItem」就應該填redView NSLayoutConstraint *blueLeft = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeRight multiplier:1.0f constant:20.0f]; //與其餘控件發生約束,因此約束添加到父控件上 [self.view addConstraint:blueLeft]; //如今咱們已經能夠肯定本身水平方向的位置了,還差垂直方向的位置,如今咱們來建立第二個約束,參照物依然是紅色方塊,需求是要離self.view底部20間距,這不是正好和紅色同樣麼,那麼咱們能夠直接與紅色方塊底部對齊就好了 NSLayoutConstraint *blueBottom = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];//與紅色方塊底部對齊,倍數1.0f.差值0.0f //與其餘控件發生約束,因此約束添加到父控件上 [self.view addConstraint:blueBottom]; //剩下兩個約束差很少,我就一併描述了,它們都以redView爲參照,與其等寬等高 NSLayoutConstraint *blueW = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]; [self.view addConstraint:blueW]; NSLayoutConstraint *blueH = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; [self.view addConstraint:blueH];
接下來看看效果圖
小結:
1.其實Autolayout的思想很是簡單,剛開始使用的時候不要想着立刻一鼓作氣,最好一個控件一個控件的實現依賴,分別知足其位置與尺寸的需求,若是一會兒幾個控件一塊兒弄的話,每每你們犯錯是犯在約束添多了,而不是添少了。 2.就如上面的例子,不少人會在設置了與紅色等高等寬後,還同時去添加頂部對齊與底部對齊,這樣高度就重複設置了,他會忽略了,上下同時對齊不只給予了垂直位置,也給予了高度,因此思路必須清晰!
Autolayout 下添加動畫
我將在藍色方塊的右邊再加個一樣大小的黃色方塊,而後,要求點擊屏幕,而後藍色方塊被移除,黃色方塊替代藍色方塊的位置
還有一個autolayout的知識點:優先級(priority)
//一如往常,先建立黃色View UIView *yellowV = [[UIView alloc]init]; yellowV.backgroundColor = [UIColor yellowColor]; yellowV.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:yellowV]; //開始建立約束,第一個約束是什麼呢?一看就知道是左間距約束啦 NSLayoutConstraint *yellowLeft = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeRight multiplier:1.0f constant:20]; //與其餘控件發生約束,因此約束添加到父控件上 [self.view addConstraint:yellowLeft]; //添加底部約束 NSLayoutConstraint *yellowBottom = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-20]; //與其餘控件發生約束,因此約束添加到父控件上 [self.view addConstraint:yellowBottom]; //這裏我直接設置寬高約束了,就省事不加參照控件了 NSLayoutConstraint *yellowW = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0f constant:50.0f]; [yellowV addConstraint:yellowW]; NSLayoutConstraint *yellowH = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0f constant:50.0f]; [yellowV addConstraint:yellowH];
運行效果
接下來我再給黃色View添加一個約束,這個約束涉及到優先級,你們注意看代碼了哈
//對黃色View添加約束,約束黃色view與紅色View的間距爲20 NSLayoutConstraint *yellowAnotherLeft = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeRight multiplier:1.0f constant:20]; UILayoutPriority priority = 250;//設置優先級 yellowAnotherLeft.priority = priority; //與其餘控件發生約束,因此約束添加到父控件上 [self.view addConstraint:yellowAnotherLeft];
想必你們應該看出些端倪了,我在前面已經給黃色View添加了對藍色View間距位20的view,如今又給黃色view對紅色View添加一個間距20的約束,這很明顯是不可能出現的狀況,黃色View怎麼可能同時作到這兩個約束呢,用術語來講就是約束衝突,可是你們注意看這段代碼
UILayoutPriority priority = 250;//設置優先級
我給yellowAnotherLeft這個約束添加了優先級,優先級的範圍是0~1000,數字越大,優先級越高,在不設置的狀況下默認爲1000
這說明了,我最後添加的這個約束的優先級是低的,這個約束只有在它的衝突約束被抹掉後,它才能實現
也就是說,我把藍色view移除後,黃色View相對於藍色View左間距20這個約束就不成立了,那麼黃色view會自動的變爲與紅色View間距20
讓咱們最後加幾行代碼,來實現這個動畫吧!
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //先把藍色方塊從父視圖上移除 [self.blueView removeFromSuperview]; //動畫更新界面 [UIView animateWithDuration:1.0f animations:^{ [self.view layoutIfNeeded]; }]; }
autolayout的動畫就是這樣實現的,將操做代碼走完後,再讓動畫塊去更新界面,動畫就出來了,效果以下:
2)VFL(visual format language)
需求:適配iPhone6,在RootViewController的view上添加一個新的view,讓這個新的view不管屏幕橫屏仍是豎屏時候都距離其superview的邊緣20
H:|-20-[newView]-20-|
V:|-20-[newView]-20-|
每個 [] 中表示一個視圖或一個控件;V 表示垂直約束,H 表示水平約束,而後兩個視圖之間的 -0- 的意思就很簡單了,意思就是這兩個視圖之間間隔爲0
好比:
V:[view0(67)]-0-[view1(67)]-0-[view2(67)]-0-[view3(67)]-0-[view4(67)]-0-|
self.view.translatesAutoresizingMaskIntoConstraints = NO; UIView *newView = [UIView new]; newView.backgroundColor = [UIColor greenColor]; [self.view addSubview:newView]; newView.translatesAutoresizingMaskIntoConstraints = NO; NSMutableArray *constraintArray = [NSMutableArray array]; [constraintArray addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[newView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(newView,self.view)]]; [constraintArray addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[newView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(newView,self.view)]]; [self.view addConstraints:constraintArray];
運行效果
示例
需求:以下所示
實現以下:
UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; UIView *blueView = [[UIView alloc]init]; blueView.backgroundColor = [UIColor blueColor]; [self.view addSubview:blueView]; UIView *yellow = [[UIView alloc]init]; yellow.backgroundColor = [UIColor yellowColor]; [self.view addSubview:yellow]; UIView *green = [[UIView alloc]init]; green.backgroundColor = [UIColor greenColor]; [self.view addSubview:green]; [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view.mas_left).offset(0);// 使左邊等於self.view的控件,間隔爲0; make.top.equalTo(self.view.mas_top).offset(0); // 使頂部與self.view的控件的間隔爲0; make.width.equalTo(self.view.mas_width).multipliedBy(0.5); // 設置寬度爲self.view的一半,multipliedBy是倍數的意思,也就是,使寬度等於self.view寬度的0.5倍 make.height.equalTo(self.view.mas_height).multipliedBy(0.5);// 設置高度爲self.view的一半。 }]; [blueView mas_makeConstraints:^(MASConstraintMaker *make) { make.width.and.height.equalTo(redView); // 跟redview等寬高 make.top.equalTo(redView.mas_top); // 與redview頂部對齊 make.leading.equalTo(redView.mas_right); // 與 redview的間隔爲0 }]; [yellow mas_makeConstraints:^(MASConstraintMaker *make) { make.width.and.height.equalTo(redView); // 跟redview等寬高 make.top.equalTo(redView.mas_bottom); // 與 redview的間隔爲0 make.leading.equalTo(redView); // 與redvie左對齊 }]; [green mas_makeConstraints:^(MASConstraintMaker *make) { make.width.and.height.equalTo(redView); // 跟redview等寬高 make.top.equalTo(yellow.mas_top); // 與yellow頂部對齊 make.leading.equalTo(yellow.mas_right); // 與 yellow的間隔爲0
}];
PS:須要下載第三庫 Masonry ,並導入 #import "Masonry.h"
Masonry 下的 Autolayout Animation
UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; UIView *greenView = [[UIView alloc]init]; greenView.backgroundColor = [UIColor greenColor]; [self.view addSubview:greenView]; self.greenView = greenView; UIView *blueView = [[UIView alloc]init]; blueView.backgroundColor = [UIColor blueColor]; [self.view addSubview:blueView]; [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view.mas_left).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); }]; [greenView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(redView.mas_right).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); }]; [blueView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(greenView.mas_right).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); make.left.equalTo(redView.mas_right).offset(20).priority(250); }];
讓咱們最後加幾行代碼,來實現這個動畫吧!
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //先把綠色方塊從父視圖上移除 [self.greenView removeFromSuperview]; //動畫更新界面 [UIView animateWithDuration:1.0f animations:^{ [self.view layoutIfNeeded]; }]; }
運行效果
使用autolayout 利弊
autolayout有沒有侷限性和解決不了的問題?兼容性怎麼樣?效率怎麼樣