屏幕適配問題共有四種解決方案:(1)根據屏幕寬高寫控件frame(下策);(2)Autoresizing的使用(中策);(3)AutoLayout的使用(上策);(4)sizeClasses+AutoLayout的使用(上上策)。下面將會分別來進行敘述。
(1)根據屏幕寬高寫控件frame
利用寬高比,在不同的屏幕中來進行對控件的位置與控件的寬高進行等比例縮放.選定一個型號的屏幕的寬高為基准,進行等比例縮放.例如以iPhone6或者iPhone6s為基准.
其寬高分別是375與667.Iphone6ScaleWidth = [UIScreen mainScreen].bounds.size.width/375; Iphone6ScaleHeight = [UIScreen mainScreen].bounds.size.height/667;
如果是iPhone6或者iPhone6s則Iphone6ScaleWidth與Iphone6ScaleHeight的值都為1.但是此方法對於iPhone5之后的型號可以適用.因為我們知道iPhone4或者iPhone4s尺寸是320x480.iPhone5是320x568.所以對於4或者4s來說計算得到的寬高比不相同.可能會造成一個方形控件,在iPhone5之后的機型上顯示的都是正方形.但是在4或者4s上顯示的是長方形.需要進行自己的判斷(目前來說4或者4s市場上已經不多見了).
同時也可以在代理增加兩個屬性,寬高比例屬性,例如:
1 @interface AppDelegate : UIResponder <UIApplicationDelegate> 2 @property float autoSizeScaleX; 3 @property float autoSizeScaleY; 4 5 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 6 if(CurrentScreenHeight > 480){ 7 nowAppDelegate().autoSizeScaleX = CurrentScreenWidth/320.0; 8 nowAppDelegate().autoSizeScaleY = CurrentScreenHeight/568.0; 9 }else{ 10 nowAppDelegate().autoSizeScaleX = 1.0;其中nowAppDelegate() = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 11 nowAppDelegate().autoSizeScaleY = 1.0; 12 } 13 14 }
在項目對於控件的位置和尺寸乘以這兩個縮放比例.
(2)Autoresizing的使用
在Autolayout以前,有Autoresizing可以做屏幕適配,但局限性較大,只能針對父子關系進行有限調整,如邊距固定,尺寸可變,對於兄弟關系的調整無法實現。對於UI比較固定的app,這種方式基本滿足。相比之下,Autolayout比Autoresizing強大很多。
(3)AutoLayout的使用
在以前的iOS程序是怎樣布局UI的?
經常編寫大量的坐標計算代碼;
為了保證在各種屏幕上都能有完美的UI界面效果,有時還需要分別為幾種屏幕編寫不同的坐標計算代碼(即傳說中的“屏幕適配”)
什么是Autolayout?
Autolayout是一種“自動布局”技術,專門用來布局UI界面的。
Autolayout自iOS6開始引入,由於Xcode4的不給力,當時並沒有得到很大的推廣。
自iOS7(Xcode5)開始,Autolayout的開發效率得到很大的提升。
蘋果官方也推薦開發者使用Autolayout來布局UI界面。
Autolayout能夠很輕松的解決屏幕適配的問題。
代碼如下:
1 UIView *headView = [[UIView alloc] init]; 2 headView.translatesAutoresizingMaskIntoConstraints = NO; 3 [self.view addSubview:headView]; 4 headView.backgroundColor = [UIColor redColor]; 5 NSLayoutConstraint *headViewLeft = [NSLayoutConstraint constraintWithItem:headView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0]; 6 NSLayoutConstraint *headViewTop = [NSLayoutConstraint constraintWithItem:headView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]; 7 NSLayoutConstraint *headViewRight = [NSLayoutConstraint constraintWithItem:headView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0]; 8 NSLayoutConstraint *headViewHeight = [NSLayoutConstraint constraintWithItem:headView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:0 constant:200]; 9 self.headHeightCons = headViewHeight; 10 [self.view addConstraints:@[headViewTop,headViewLeft,headViewRight]]; 11 [headView addConstraint:headViewHeight]; 12 13 14 UIImage *imageLol = [UIImage imageNamed:@"lol"]; 15 UIImageView *imageViewLol = [[UIImageView alloc] initWithImage:imageLol]; 16 [headView addSubview:imageViewLol]; 17 imageViewLol.translatesAutoresizingMaskIntoConstraints = NO; 18 [imageViewLol setContentMode:UIViewContentModeScaleAspectFill]; 19 20 21 NSLayoutConstraint *imageLolViewLeft = [NSLayoutConstraint constraintWithItem:imageViewLol attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:headView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0]; 22 NSLayoutConstraint *imageViewLolViewTop = [NSLayoutConstraint constraintWithItem:imageViewLol attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:headView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]; 23 NSLayoutConstraint *imageViewLolViewRight = [NSLayoutConstraint constraintWithItem:imageViewLol attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:headView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0]; 24 NSLayoutConstraint *imageViewLolViewBottom = [NSLayoutConstraint constraintWithItem:imageViewLol attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:headView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]; 25 [headView addConstraints:@[imageLolViewLeft,imageViewLolViewTop,imageViewLolViewRight,imageViewLolViewBottom]];
(4)sizeClasses+AutoLayout的使用
iOS8中新增了Size Classes特性,他是對當前所有iOS設備尺寸的一個抽象。
用法:
屏幕的寬和高分別分成三種情況:(Compact,Regular,Any).也就是緊湊,正常和任意。這樣寬和高三三整合,一共九種情況。針對每一種情況,如果需要的話,我們可以單獨在storyboard或xib中設置UIView的自動布局約束,甚至某一個button是否顯示都是能輕松實現的。
當然,還有一種就是使用Masonry框架進行屏幕適配
Masonry是一個輕量級的布局框架,擁有自己的描述語法,采用更優雅的鏈式語法封裝自動布局,簡潔明了並具有高可讀性,而且同時支持 iOS 和 Max OS X。Masonry是一個用代碼寫iOS或OS界面的庫,可以代替Auto layout。Masonry的github地址:https://github.com/SnapKit/Masonry
Masonry配置
- 推薦使用pods方式引入類庫,pod 'Masonry',若不知道pod如何使用,情況我的另一篇文章: 提高ios開發效率的工具
- 引入頭文件 #import "Masonry.h"
Masonry使用講解
mas_makeConstraints 是給view添加約束,約束有幾種,分別是邊距,寬,高,左上右下距離,基准線。添加過約束后可以有修正,修正有offset(位移)修正和multipliedBy(倍率)修正。
語法一般是 make.equalTo or make.greaterThanOrEqualTo or make.lessThanOrEqualTo + 倍數和位移修正。
注意點1: 使用 mas_makeConstraints方法的元素必須事先添加到父元素的中,例如[self.view addSubview:view];
注意點2: masequalTo 和 equalTo 區別:masequalTo 比equalTo多了類型轉換操作,一般來說,大多數時候兩個方法都是 通用的,但是對於數值元素使用mas_equalTo。對於對象或是多個屬性的處理,使用equalTo。特別是多個屬性時,必須使用equalTo,例如 make.left.and.right.equalTo(self.view);
注意點3: 注意到方法with和and,這連個方法其實沒有做任何操作,方法只是返回對象本身,這這個方法的左右完全是為了方法寫的時候的可讀性 。make.left.and.right.equalTo(self.view);和make.left.right.equalTo(self.view);是完全一樣的,但是明顯的加了and方法的語句可讀性 更好點。
Masonry初級使用例子
1 // exp1: 中心點與self.view相同,寬度為400*400 2 -(void)exp1{ 3 UIView *view = [UIView new]; 4 [view setBackgroundColor:[UIColor redColor]]; 5 [self.view addSubview:view]; 6 [view mas_makeConstraints:^(MASConstraintMaker *make) { 7 make.center.equalTo(self.view); 8 make.size.mas_equalTo(CGSizeMake(400,400)); 9 }]; 10 } 11 //exp2: 上下左右邊距都為10 12 -(void)exp2{ 13 UIView *view = [UIView new]; 14 [view setBackgroundColor:[UIColor redColor]]; 15 [self.view addSubview:view]; 16 [view mas_makeConstraints:^(MASConstraintMaker *make) { 17 make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(10, 10, 10, 10)); 18 // make.left.equalTo(self.view).with.offset(10); 19 // make.right.equalTo(self.view).with.offset(-10); 20 // make.top.equalTo(self.view).with.offset(10); 21 // make.bottom.equalTo(self.view).with.offset(-10); 22 }]; 23 } 24 //exp3 讓兩個高度為150的view垂直居中且等寬且等間隔排列 間隔為10 25 -(void)exp3{ 26 UIView *view1 = [UIView new]; 27 [view1 setBackgroundColor:[UIColor redColor]]; 28 [self.view addSubview:view1]; 29 UIView *view2 = [UIView new]; 30 [view2 setBackgroundColor:[UIColor redColor]]; 31 [self.view addSubview:view2]; 32 [view1 mas_makeConstraints:^(MASConstraintMaker *make) { 33 make.centerY.mas_equalTo(self.view.mas_centerY); 34 make.height.mas_equalTo(150); 35 make.width.mas_equalTo(view2.mas_width); 36 make.left.mas_equalTo(self.view.mas_left).with.offset(10); 37 make.right.mas_equalTo(view2.mas_left).offset(-10); 38 }]; 39 [view2 mas_makeConstraints:^(MASConstraintMaker *make) { 40 make.centerY.mas_equalTo(self.view.mas_centerY); 41 make.height.mas_equalTo(150); 42 make.width.mas_equalTo(view1.mas_width); 43 make.left.mas_equalTo(view1.mas_right).with.offset(10); 44 make.right.equalTo(self.view.mas_right).offset(-10); 45 }]; 46 }
Masonry高級使用例子1
iOS計算器使用Masorny布局:
1 //高級布局練習 ios自帶計算器布局 2 -(void)exp4{ 3 //申明區域,displayView是顯示區域,keyboardView是鍵盤區域 4 UIView *displayView = [UIView new]; 5 [displayView setBackgroundColor:[UIColor blackColor]]; 6 [self.view addSubview:displayView]; 7 UIView *keyboardView = [UIView new]; 8 [self.view addSubview:keyboardView]; 9 //先按1:3分割 displView(顯示結果區域)和 keyboardView(鍵盤區域) 10 [displayView mas_makeConstraints:^(MASConstraintMaker *make) { 11 make.top.equalTo(self.view.mas_top); 12 make.left.and.right.equalTo(self.view); 13 make.height.equalTo(keyboardView).multipliedBy(0.3f); 14 }]; 15 [keyboardView mas_makeConstraints:^(MASConstraintMaker *make) { 16 make.top.equalTo(displayView.mas_bottom); 17 make.bottom.equalTo(self.view.mas_bottom); 18 make.left.and.right.equalTo(self.view); 19 }]; 20 //設置顯示位置的數字為0 21 UILabel *displayNum = [[UILabel alloc]init]; 22 [displayView addSubview:displayNum]; 23 displayNum.text = @"0"; 24 displayNum.font = [UIFont fontWithName:@"HeiTi SC" size:70]; 25 displayNum.textColor = [UIColor whiteColor]; 26 displayNum.textAlignment = NSTextAlignmentRight; 27 [displayNum mas_makeConstraints:^(MASConstraintMaker *make) { 28 make.left.and.right.equalTo(displayView).with.offset(-10); 29 make.bottom.equalTo(displayView).with.offset(-10); 30 }]; 31 //定義鍵盤鍵名稱,?號代表合並的單元格 32 NSArray *keys = @[@"AC",@"+/-",@"%",@"÷" 33 ,@"7",@"8",@"9",@"x" 34 ,@"4",@"5",@"6",@"-" 35 ,@"1",@"2",@"3",@"+" 36 ,@"0",@"?",@".",@"="]; 37 int indexOfKeys = 0; 38 for (NSString *key in keys){ 39 //循環所有鍵 40 indexOfKeys++; 41 int rowNum = indexOfKeys %4 ==0? indexOfKeys/4:indexOfKeys/4 +1; 42 int colNum = indexOfKeys %4 ==0? 4 :indexOfKeys %4; 43 NSLog(@"index is:%d and row:%d,col:%d",indexOfKeys,rowNum,colNum); 44 //鍵樣式 45 UIButton *keyView = [UIButton buttonWithType:UIButtonTypeCustom]; 46 [keyboardView addSubview:keyView]; 47 [keyView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 48 [keyView setTitle:key forState:UIControlStateNormal]; 49 [keyView.layer setBorderWidth:1]; 50 [keyView.layer setBorderColor:[[UIColor blackColor]CGColor]]; 51 [keyView.titleLabel setFont:[UIFont fontWithName:@"Arial-BoldItalicMT" size:30]]; 52 //鍵約束 53 [keyView mas_makeConstraints:^(MASConstraintMaker *make) { 54 //處理 0 合並單元格 55 if([key isEqualToString:@"0"] || [key isEqualToString:@"?"] ){ 56 if([key isEqualToString:@"0"]){ 57 [keyView mas_makeConstraints:^(MASConstraintMaker *make) { 58 make.height.equalTo(keyboardView.mas_height).with.multipliedBy(.2f); 59 make.width.equalTo(keyboardView.mas_width).multipliedBy(.5); 60 make.left.equalTo(keyboardView.mas_left); 61 make.baseline.equalTo(keyboardView.mas_baseline).with.multipliedBy(.9f); 62 }]; 63 }if([key isEqualToString:@"?"]){ 64 [keyView removeFromSuperview]; 65 } 66 } 67 //正常的單元格 68 else{ 69 make.width.equalTo(keyboardView.mas_width).with.multipliedBy(.25f); 70 make.height.equalTo(keyboardView.mas_height).with.multipliedBy(.2f); 71 //按照行和列添加約束,這里添加行約束 72 switch (rowNum) { 73 case 1: 74 { 75 make.baseline.equalTo(keyboardView.mas_baseline).with.multipliedBy(.1f); 76 keyView.backgroundColor = [UIColor colorWithRed:205 green:205 blue:205 alpha:1]; 77 } 78 break; 79 case 2: 80 { 81 make.baseline.equalTo(keyboardView.mas_baseline).with.multipliedBy(.3f); 82 } 83 break; 84 case 3: 85 { 86 make.baseline.equalTo(keyboardView.mas_baseline).with.multipliedBy(.5f); 87 } 88 break; 89 case 4: 90 { 91 make.baseline.equalTo(keyboardView.mas_baseline).with.multipliedBy(.7f); 92 } 93 break; 94 case 5: 95 { 96 make.baseline.equalTo(keyboardView.mas_baseline).with.multipliedBy(.9f); 97 } 98 break; 99 default: 100 break; 101 } 102 //按照行和列添加約束,這里添加列約束 103 switch (colNum) { 104 case 1: 105 { 106 make.left.equalTo(keyboardView.mas_left); 107 } 108 break; 109 case 2: 110 { 111 make.right.equalTo(keyboardView.mas_centerX); 112 } 113 break; 114 case 3: 115 { 116 make.left.equalTo(keyboardView.mas_centerX); 117 } 118 break; 119 case 4: 120 { 121 make.right.equalTo(keyboardView.mas_right); 122 [keyView setBackgroundColor:[UIColor colorWithRed:243 green:127 blue:38 alpha:1]]; 123 } 124 break; 125 default: 126 break; 127 } 128 } 129 }]; 130 } 131 }
本例子使用的baseline去控制高度位置,這似乎不是太准,如果想要精准控制高度位置,可以使用一行一行添加的方法,每次當前行的top去equelTo上一行的bottom。 給個提示:
for(遍歷所有行) for(遍歷所以列) //當前行約束根據上一行去設置 ......