最近準備學習OC,先簡單地搜索一下屏幕適配,發(fā)現(xiàn)沒有特別省事的適配方法,決定按照android適配的方法簡單地寫一個適配方案。希望有人可以受到啟發(fā),寫出一套懶人適配方案,還請記得告訴我一下,謝謝。另外,由于接觸OC不久,所以很多常識性的東西都還不懂,請見諒。
來到正文,android手機的屏幕千奇百怪,推薦鴻洋大神的百分比自動適配方案: http://blog.csdn.net/lmj623565791/article/details/49990941 也有其他大神精簡的方案: http://blog.csdn.net/zhengjingle/article/details/51742839 可以根據(jù)自己的需求適當改寫。
核心原理
原則上來說知道了控件寬度和高度以及左邊距和上邊距就可以確定一個控件。 所以我們只需要根據(jù)設(shè)計圖的寬高與實際屏幕寬高比例對各種控件的寬度、高度、上下左右邊距進行縮放就可以完成初步布局,再加上字體、內(nèi)邊距、圓角大小等就可以完美實現(xiàn)布局效果。
目前我選取的方式是使用storyboard拖拽控件布局,因為拖拽很快。
首先假設(shè)我們的設(shè)計圖是750x1334,然后我們根據(jù)設(shè)計圖拖拽控件,設(shè)置好控件的寬度和高度,然后設(shè)置依賴關(guān)系即可。上面提到我們只需要設(shè)置寬度、高度、左邊距和上邊距就可以確定一個控件。我們直接往默認的ViewController對應(yīng)的main.storyboard上拖拽一個UIButton。設(shè)置寬度為200,高度100,距離屏幕左邊40,屏幕頂部50。
首先獲取屏幕寬度與高度,6s的屏幕尺寸也是750x1334,在6s上的寬度縮放比例wRate =750 /750=1,高度縮放比例hRate=1334/1334=1。SE的屏幕尺寸是640x1138,寬度縮放比例wRate=640/750,高度縮放比例hRate=1138/1334。
高度和寬度
我們首先處理View的寬度與高度。每一個view都有寬度與高度,如果明確指定了寬度與高度的約束,那么我們就可以拿到寬度與高度的值;如果沒有指定,我們拿不到寬度與高度的值,那么我們不需要處理,系統(tǒng)會處理好。
比如我們指定一個buttonA,寬度50,高度60,左邊距40,上邊距50,那么我們就可以通過NSLayoutAttributeWidth和NSLayoutAttributeHeight約束拿到50和60。 我們在指定buttonB,高度50,上邊距50,左邊距50,右邊距50,我們可以通過NSLayoutAttributeHeight拿到高度50,我們只要改變左邊距和右邊距的值,系統(tǒng)會自動處理寬度。
//所有的view都需要適配寬高
NSArray* constrains = view.constraints;
for (NSLayoutConstraint* constraint in constrains) {CGFloat temp =constraint.constant; if(temp!=0){if (constraint.firstAttribute == NSLayoutAttributeHeight) {printf("適配前高度的約束--%f\n",constraint.constant);constraint.constant = temp * hRate;printf("適配后高度的約束--%f\n",constraint.constant);}else if(constraint.firstAttribute == NSLayoutAttributeWidth){printf("適配前寬度的約束--%f\n",constraint.constant);constraint.constant = temp * wRate;printf("適配后寬度的約束--%f\n",constraint.constant);}}
}
上下左右邊距
然后處理VIew的上下左右邊距,我們把所有的邊距處理都交給父View,在父View里可以得到所有的依賴關(guān)系。
NSArray* constrains = view.constraints;
for (NSLayoutConstraint* constraint in constrains) {CGFloat temp=constraint.constant;if(temp!=0){//這里只需要判斷firstAttribute即可//因為leading只可能跟leading或者trailing有關(guān)系,都是水平的if (constraint.firstAttribute == NSLayoutAttributeLeading|| constraint.firstAttribute == NSLayoutAttributeTrailing) {printf("find width\n");constraint.constant = temp * wRate;//左右水平縮放}else if(constraint.firstAttribute ==NSLayoutAttributeTop||constraint.firstAttribute == NSLayoutAttributeBottom){printf("find heihgt\n");constraint.constant = temp * hRate;//上下豎直縮放}}
}
通過處理View的寬度、高度、上下左右邊距就可以確定View。當然繪制View的時候系統(tǒng)可能會對小數(shù)點進行截斷,比如button縮放之后的寬度可能是200.66666667,系統(tǒng)只繪制了200.5,如果布局要求特別精準的話需要特別處理。
從1到100
上面我們已經(jīng)可以確定一個View的位置以及尺寸,接下來我們要做的就是確定每一個View的位置以及尺寸。 我們首先判斷一個view是否有子view ,如果沒有子View,那么很簡單,只需要管好自己就好,直接寬高按比例縮放即可;如果有子View,那么不僅需要對自身寬高進行縮放,還需要縮放子View之間的margin以及子View與父View之間的上下左右邊距,然后處理每一個子View。一直遞歸,直到全部處理完畢。
我們新建一個工程,默認的是ViewController.m。我們拖拽一個UIButton到main.storyboard,設(shè)置寬度200,高度100,左邊距40,上邊距50,傳入viewController.view,首先縮放viewController.view的寬度與高度。然后縮放viewController.view與UIButton的依賴。 處理viewController.view之后,處理UIButton,先處理UIButton的寬度與高度,由于UIButton沒有子View,就不需要再處理對應(yīng)的子View之間的依賴關(guān)系以及父子View之間的對應(yīng)關(guān)系。 如果在6s上,最后UIButton的寬度是200 * wRate=200 * 1=200,高度是100* hRate=100 * 1=100,左邊距是40*wRate =40*1 =40,上邊距是50 * hRate=50*1=50。 如果在SE上,最后UIButton寬度是200 * wRate=200*640/750, 高度是100 * hRate=100 * 1138/1334,左邊距是40 * wRate= 40 * 640 /750,上邊距是50 * 1138 / 1334。
至此,View的位置、大小都已經(jīng)處理完畢。然后我們還需要處理字體、內(nèi)邊距、圓角等。
適配字體
UIButton、UITextView、UILabel、UITextField等需要適配字體,這些和寬高一樣屬于View的自身屬性,與其他的View沒有關(guān)系。所以可以和處理寬高寫在一起。
if([view isKindOfClass:[UIButton class]]){UIButton *button=(UIButton *)view;[self autoUIButton:button:wRate:hRate];}else if([view isKindOfClass:[UILabel class]]){UILabel *label = (UILabel *)view;[self autoUILabel:label:wRate :hRate];}else if([view isKindOfClass:[UITextField class]]){UITextField *textField = (UITextField *)view;[self autoUITextField:textField :wRate :hRate];}else if([view isKindOfClass:[UITextView class]]){UITextView *textView = (UITextView *)view;[self autoTextView:textView :wRate :hRate];}else if([view isKindOfClass:[UIImageView class]]){UIImageView *imageView = (UIImageView *)view;[self autoUIImageView:imageView :wRate :hRate];}
對每一種View需要單獨處理:比如UIButton、UITextView等需要處理字體大小。 UIButton適配字體: +(void)autoUIButton:(UIButton *)button:(float)wRate:(float)hRate{ //適配字體 textRate = wRate; float textSize =button.titleLabel.font.pointSize * textRate; button.titleLabel.font = [UIFont systemFontOfSize: textSize]; } UITextView字體適配: +(void)autoTextView:(UITextView *)textView :(float)wRate :(float)hRate{ //適配字體 textRate = hRate; float textSize =textView.font.pointSize * textRate; textView.font =[UIFont systemFontOfSize: textSize]; } 這里字體適配可以根據(jù)自己的需要來選擇字體是根據(jù)寬度、高度或者對角線的縮放比例來縮放,按照最終效果適當調(diào)整。
圖片處理
iOS在設(shè)置圖片寬高時可以直接指定寬高的比例,這一點很贊。不用擔心原本寬高一樣的圖片縮放后變形。
狀態(tài)欄處理
由于iphoneX的狀態(tài)欄高度和之前的手機狀態(tài)欄不一樣,所以適配時需要考慮到狀態(tài)欄高度??梢园言镜脑O(shè)計圖尺寸高度減去狀態(tài)欄的高度當作標準,比如原本750*1334的設(shè)計圖,減去狀態(tài)欄高度后就是750 * 1294,當然一直對應(yīng)獲取屏幕高度是也要減去狀態(tài)欄高度,這樣縮放比例才是正常的。
導航欄處理
和狀態(tài)欄處理類似,減去系統(tǒng)導航欄的高度再進行縮放。沒有測試過每一個手機的導航欄高度是多少,之后會測試一下每一個手機。如果有tabbar的話,處理也是類似。
后續(xù)改進
至此我們已經(jīng)可以完成基本布局的適配, 后續(xù)還需要適配UIButton等的背景圖片,距離水平中心20等特殊屬性,性能方面還需要測試。
有些東西沒說明白的,可以去通過上面的連接去查看鴻洋大神的介紹,雖然是Android,不過道理是一樣的。
代碼很亂,之后會改進,輕噴。
// // AutoUtils.h // ScreenPercent // // Created by D on 2018/2/1. // Copyright ? 2018年 D. All rights reserved. //
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <math.h>@interface AutoUtils : NSObject@property float designWidth;//設(shè)計寬
@property float designHeight;//設(shè)計高
@property float _wRate;//寬拉伸比例
@property float _hRate;//高拉伸比例/**初始化todo 加入對tabbar的處理@param designWidth 設(shè)計圖尺寸的寬度@param designHeight 設(shè)計圖尺寸的高度(不包含狀態(tài)欄)*/
+(void)initAuto:(float) designWidth:(float) designHeight;/**適配UIViewController這個方法主要是為了之后處理UINavigationBar、UITabBar*/
+(void)autoUIViewController:(UIViewController *)viewController;/***//**適配UIViewController這個方法主要是為了之后處理UINavigationBar、UITabBar@param viewController UIViewController對象@param hasNavigationBar 是否有NavigationBar@param hasTabBar 是否有TabBar*/
+(void)autoUIViewController:(UIViewController *)viewController:(Boolean)hasNavigationBar
:(Boolean)hasTabBar;/**獲取navigationbar高度@return float*/
+(float)getNavigationBarHeight:(UIViewController *)viewController;/**獲取tabbar高度@return float*/
+(float)getTabBarHeight:(UIViewController *)viewController;/**適配普通的View@param view void*/
+(void)autoView:(UIView *)view;/**縮放后的寬度@param viewWidth 要縮放View的寬度@param designWidth 設(shè)計圖的寬度尺寸 例如375@return <#return value description#>*/
+(float)getDisplayWidth:(float) viewWidth:(float) designWidth;/**Description 縮放后的高度@param viewHeight 要縮放的View的高度@param designHeight 設(shè)計圖的高度尺寸,去掉狀態(tài)之后的高度 例如647@return <#return value description#>*/
+(float)getDisplayHeight:(float) viewHeight:(float) designHeight;
/**含有子View的View,需要處理子View之間以及子View與父View的距離*/
+(void)autoRelatives:(UIView *)view:(float)wRate:(float)hRate;/**不含有子View的View 處理自身的寬高信息@param view <#view description#>*/
+(void)autoSelf:(UIView *)view:(float)wRate:(float)hRate;/**適配button@param button 要適配的button@param wRate 水平方向拉伸比例@param hRate 豎直方向拉伸比例*/
+(void)autoUIButton:(UIButton *)button:(float)wRate:(float)hRate;/**適配textView@param textView 要適配的textView@param wRate 水平方向拉伸比例@param hRate 豎直方向拉伸比例*/
+(void)autoTextView:(UITextView *)textView:(float)wRate:(float)hRate;/**適配label@param label 要適配的label@param wRate 水平方向拉伸比例@param hRate 豎直方向拉伸比例*/
+(void)autoUILabel:(UILabel *)label:(float)wRate:(float)hRate;/**適配textField@param textField 要適配的textField@param wRate 水平方向拉伸比例@param hRate 豎直方向拉伸比例*/
+(void)autoUITextField:(UITextField *)textField:(float)wRate:(float)hRate;/**適配imageView如果寬高都按照寬縮放,那么固定寬度(如50),高度通過設(shè)置aspect ratio同理寬高都按照高縮放,那么固定高度(如50),寬度通過設(shè)置aspect ratio如果寬按寬縮放,高按照高縮放,那么設(shè)置寬高的值即可@param textField 要適配的imageView@param wRate 水平方向拉伸比例@param hRate 豎直方向拉伸比例*/
+(void)autoUIImageView:(UIImageView *)imageView:(float)wRate:(float)hRate;
@end//
// AutoUtils.m
// ScreenPercent
//
// Created by D on 2018/2/1.
// Copyright ? 2018年 D. All rights reserved.
//#import "AutoUtils.h"//默認的設(shè)計圖尺寸
static float designWidth = 375.0;
static float designHeight = 667.0;
//屏幕顯示區(qū)域的寬高
static float displayWidth = 0;
static float displayHeight = 0;//只去除狀態(tài)欄的高度后的縮放比例
static float designWidthRate = 0;
static float designHeightRate = 0;static float textRate = 0;//暫時不考慮navigationbar和tabbar等的影響,目前只適配基本控件@implementation AutoUtils+(void)initAuto:(float)designW:(float)designH{//設(shè)計圖尺寸designWidth = designW;designHeight = designH;//導航欄高度displayWidth =[UIScreen mainScreen].bounds.size.width;displayHeight = [UIScreen mainScreen].bounds.size.height;//計算縮放比例designWidthRate = displayWidth / designWidth;designHeightRate= displayHeight / designHeight;textRate =displayWidth /designWidth;
// textRate =hypotf(displayWidth,displayHeight) /hypotf(designWidth,designHeight);
}
+(void)autoUIViewController:(UIViewController *)viewController{[self autoUIViewController:viewController :false :false];
}+(void)autoUIViewController:(UIViewController *)viewController :(Boolean)hasNavigationBar :(Boolean)hasTabBar{float navigationBarHeight = 0;float tabBarheight = 0;if(hasNavigationBar){navigationBarHeight = [self getNavigationBarHeight:viewController];}if(hasTabBar){tabBarheight = [self getTabBarHeight:viewController];}[self autoSelf:viewController.view:designWidthRate:designHeightRate];[self autoRelatives:viewController.view:designWidthRate:designHeightRate];
//
}
+(void)autoView:(UIView *)view{[self autoSelf:view:designWidthRate:designHeightRate];//處理自己的寬高//有子View[self autoRelatives:view:designWidthRate:designHeightRate];//處理
}+(void)autoRelatives:(UIView *)view :(float)wRate :(float)hRate{//必須有子ViewNSArray *subviews = [view subviews];if ([subviews count] == 0){return;}//適配子View之間的間距,適配子View與自己的間距//目前只處理上下左右的間距NSArray* constrains = view.constraints;
// printf("最外層的contrains count--%lu\n",constrains.count);
// printf("NSLayoutAttributeLeft%lu\n",NSLayoutAttributeLeft);
//printf("NSLayoutAttributeRight%lu\n",NSLayoutAttributeRight); printf("NSLayoutAttributeTop%lu\n",NSLayoutAttributeTop); printf("NSLayoutAttributeBottom%lu\n",NSLayoutAttributeBottom); printf("NSLayoutAttributeLeading%lu\n",NSLayoutAttributeLeading); printf("NSLayoutAttributeTrailing%lu\n",NSLayoutAttributeTrailing); printf("NSLayoutAttributeWidth%lu\n",NSLayoutAttributeWidth); printf("NSLayoutAttributeHeight%lu\n",NSLayoutAttributeHeight); printf("NSLayoutAttributeCenterX%lu\n",NSLayoutAttributeCenterX);
//printf("NSLayoutAttributeCenterY%lu\n",NSLayoutAttributeCenterY);
// printf("NSLayoutAttributeLastBaseline%lu\n",NSLayoutAttributeLastBaseline);
//
// printf("stop\n");for (NSLayoutConstraint* constraint in constrains) {
// printf("%lu--%lu--%f\n",constraint.firstAttribute,constraint.secondAttribute,constraint.constant);CGFloat temp=constraint.constant;if(temp!=0){//這里只需要判斷firstAttribute即可//因為leading只可能跟leading或者trailing有關(guān)系,都是水平的if (constraint.firstAttribute == NSLayoutAttributeLeading|| constraint.firstAttribute == NSLayoutAttributeTrailing) {printf("find width\n");constraint.constant = temp * wRate;//左右水平縮放}else if(constraint.firstAttribute ==NSLayoutAttributeTop||constraint.firstAttribute == NSLayoutAttributeBottom){printf("find heihgt\n");constraint.constant = temp * hRate;//上下豎直縮放}}}//接著循環(huán)遍歷處理每一個子Viewfor (UIView *subview in subviews) {[self autoView:subview];}
}+(void)autoSelf:(UIView *)view:(float)wRate:(float)hRate{printf("------View自己的屬性------\n");printf("NSLayoutAttributeLeft%lu\n",NSLayoutAttributeLeft);printf("NSLayoutAttributeRight%lu\n",NSLayoutAttributeRight); printf("NSLayoutAttributeTop%lu\n",NSLayoutAttributeTop); printf("NSLayoutAttributeBottom%lu\n",NSLayoutAttributeBottom); printf("NSLayoutAttributeLeading%lu\n",NSLayoutAttributeLeading); printf("NSLayoutAttributeTrailing%lu\n",NSLayoutAttributeTrailing); printf("NSLayoutAttributeWidth%lu\n",NSLayoutAttributeWidth); printf("NSLayoutAttributeHeight%lu\n",NSLayoutAttributeHeight); printf("NSLayoutAttributeCenterX%lu\n",NSLayoutAttributeCenterX);printf("NSLayoutAttributeCenterY%lu\n",NSLayoutAttributeCenterY);printf("NSLayoutAttributeLastBaseline%lu\n",NSLayoutAttributeLastBaseline);//所有的view都需要適配寬高NSArray* constrains = view.constraints;printf("最外層的contrains count--%lu\n",constrains.count);for (NSLayoutConstraint* constraint in constrains) {CGFloat temp =constraint.constant;printf("constant is %ld =%f\n",constraint.firstAttribute,temp);if(temp!=0){if (constraint.firstAttribute == NSLayoutAttributeHeight) {printf("適配前高度的約束--%f\n",constraint.constant);constraint.constant = temp * hRate;printf("適配后高度的約束--%f\n",constraint.constant);}else if(constraint.firstAttribute == NSLayoutAttributeWidth){printf("適配前寬度的約束--%f\n",constraint.constant);constraint.constant = temp * wRate;printf("適配后寬度的約束--%f\n",constraint.constant);}}}//是否buttonif([view isKindOfClass:[UIButton class]]){UIButton *button=(UIButton *)view;[self autoUIButton:button:wRate:hRate];printf("------以上時UIButton自己的屬性------\n");}else if([view isKindOfClass:[UILabel class]]){UILabel *label = (UILabel *)view;[self autoUILabel:label:wRate :hRate];printf("-----以上時UILabel自己的屬性------\n");}else if([view isKindOfClass:[UITextField class]]){UITextField *textField = (UITextField *)view;[self autoUITextField:textField :wRate :hRate];printf("------以上時UITextField自己的屬性------\n");}else if([view isKindOfClass:[UITextView class]]){UITextView *textView = (UITextView *)view;[self autoTextView:textView :wRate :hRate];printf("------以上是UITextView自己的屬性------\n");}else if([view isKindOfClass:[UIImageView class]]){UIImageView *imageView = (UIImageView *)view;[self autoUIImageView:imageView :wRate :hRate];printf("------以上是UIImageView自己的屬性------\n");}}+(float)getDisplayWidth:(float)viewWidth :(float)designWidth{return viewWidth * displayWidth / designWidth;}+(float)getDisplayHeight:(float)viewHeight :(float)designHeight{return viewHeight * displayHeight / designHeight;}/**目前不考慮Navigationbar的影響之后減去navigationbar高度或者對navigationbar的高度進行適配@param viewController viewController@return 0*/+(float)getNavigationBarHeight:(UIViewController *)viewController{return 0;// return viewController.navigationController.navigationBar.frame.size.height;}/**目前不考慮tabbar的影響之后減去tabbar高度或者對tabbar的高度進行適配@param viewController viewController@return 0*/+(float)getTabBarHeight:(UIViewController *)viewController{return 0;// return viewController.tabBarController.tabBar.frame.size.height;}+(void)autoUIButton:(UIButton *)button:(float)wRate:(float)hRate{textRate = wRate;printf("適配button\n");printf("button child view 個數(shù) %ld\n", button.subviews.count);//獲取約束NSArray* constrains = button.constraints;printf("contrains count--%lu\n",constrains.count);//適配字體float textSize =button.titleLabel.font.pointSize * textRate;button.titleLabel.font = [UIFont systemFontOfSize: textSize];}+(void)autoUILabel:(UILabel *)label :(float)wRate :(float)hRate{textRate = wRate;printf("適配label\n");printf("label child view 個數(shù) %ld\n", label.subviews.count);//適配字體float textSize =label.font.pointSize * textRate;label.font = [UIFont systemFontOfSize: textSize];}+(void)autoTextView:(UITextView *)textView :(float)wRate :(float)hRate{textRate = wRate;printf("適配textView\n");printf("textView child view 個數(shù) %ld\n", textView.subviews.count);//適配字體float textSize =textView.font.pointSize * textRate;textView.font =[UIFont systemFontOfSize: textSize];}+(void)autoUITextField:(UITextField *)textField :(float)wRate :(float)hRate{textRate = wRate;printf("適配textField\n");printf("textField child view 個數(shù) %ld\n", textField.subviews.count);//適配字體float textSize =textField.font.pointSize * textRate;textField.font =[UIFont systemFontOfSize: textSize];}+(void)autoUIImageView:(UIImageView *)imageView :(float)wRate :(float)hRate{}@end
調(diào)用 - (void)viewDidLoad { [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.[AutoUtils initAuto:375.0:647.0];
[AutoUtils autoUIViewController:self :false :false];
}
tableView適配 在contentView套一層UIView,指定contentView與UIView高度一致,通過指定UIView的高度來設(shè)置contentView的高度。
獲取cell的時候?qū)ell進行適配即可。 [AutoUtils autoView:cell];
總結(jié)
以上是生活随笔 為你收集整理的iOS屏幕适配 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。