在iOS實際項目開發中, 我們經常要適配不同尺寸的屏幕,如iPhone4s,iPhone5/s,iPhone6/s,iPhone6Plus等. 在代碼中創建一個控件如:
UILabel *label = [UILabel alloc] init];
label.frame = CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height);
[self.view addSubView : label];
我相信很多童鞋都是這么寫的. 這樣寫也沒有錯. 但是當控件一多,設置控件的frame就成了一個難題. 有時候我們只能去估算控件的大小以及相對位置. 這樣就有一個不好之處: 當你在一個設備上(如iPhone5s) 調整好了布局,那么當你運行在iPhone4s, 或者iPhone6s或者iPhone6s+ 上面的時候,你會發現原本已經布局好的界面變形了. 這就是由于屏幕尺寸的不同導致的問題.那我們該如何解決這個問題呢? 下面我將娓娓道來:
第一種方式也是我們經常使用的Autolayout(自動布局), 值得注意的是,Autolayout只適用 xib 跟 storyBoard. Autolayout是一種“自動布局”技術,專門用來布局UI界面的.Autolayout自iOS6開始引入,由于Xcode4的不給力,當時并沒有得到很大的推廣.自iOS7(Xcode5)開始,Autolayout的開發效率得到很大的提升.蘋果官方也推薦開發者使用Autolayout來布局UI界面.Autolayout能夠很輕松的解決屏幕適配的問題. 它是通過在xib或者storyBoard中設置控件的依賴關系,從而適配.
提到Autolayout,不得不提Autoresizing.在Autolayout以前,有Autoresizing可以做屏幕適配,但局限性較大,只能針對父子關系進行有限調整,如邊距固定,尺寸可變,對于兄弟關系的調整無法實現.對于UI比較固定的app,這種方式基本滿足.相比之下,Autolayout比Autoresizing強大很多.
還有一個就是Size Classes. Size Classes是iOS8中新增了特性,他是對當前所有iOS設備尺寸的一個抽象. 屏幕的寬和高分別分成三種情況:(Compact,Regular,Any).也就是緊湊,正常和任意. 這樣寬和高三三整合,一共九種情況. 針對每一種情況,如果需要的話,我們可以單獨在storyboard或xib中設置UIView的自動布局約束,甚至某一個button是否顯示都是能輕松實現的. 具體使用方法這里就不做詳細說明.
下面所要說的就是今天的重點: 純代碼實現屏幕適配. 在開始說之前,先讓我們了解一下iPhone的機型和尺寸的對應關系:
Snip20160520_1.png
很明顯能看出這三種屏幕的尺寸寬高比是差不多的,因此可以在5的基礎上,按比例放大來適配6和6Plus的屏幕.
// 在AppDelegate.h中
@property float autoSizeScaleX;
@property float autoSizeScaleY;
// 在AppDelegate.m中
#define ScreenHeight [[UIScreen mainScreen] bounds].size.height
#define ScreenWidth [[UIScreen mainScreen] bounds].size.width
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];
if(ScreenHeight > 480){ // 這里以(iPhone4S)為準
myDelegate.autoSizeScaleX = ScreenWidth/320;
myDelegate.autoSizeScaleY = ScreenHeight/568;
}else{
myDelegate.autoSizeScaleX = 1.0;
myDelegate.autoSizeScaleY = 1.0;
}
}
因為iPhone4s屏幕的高度是480, 因此當屏幕尺寸大于iPhone4時, autoSizeScaleX和autoSizeScaleY即為當前屏幕和iPhone5尺寸的寬高比, 比如,
如果是5,autoSizeScaleX=1,autoSizeScaleY=1;
如果是6,autoSizeScaleX=1.171875,autoSizeScaleY=1.17429577;
如果是6Plus,autoSizeScaleX=1.29375,autoSizeScaleY=1.2957;
現在我們獲取了比例關系后,先來看一下如何解決代碼設置界面時的適配。CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)這個方法使我們常用的設置尺寸的方法,現在我設置了一個類似于這樣的方法。在.m文件中
CG_INLINE CGRect
TS_CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];
CGRect rect;
rect.origin.x = x * myDelegate.autoSizeScaleX;
rect.origin.y = y * myDelegate.autoSizeScaleY;
rect.size.width = width * myDelegate.autoSizeScaleX;
rect.size.height = height * myDelegate.autoSizeScaleY;
return rect;
}
當我們使用的時候直接這樣做
UIImageView *imageview = [[UIImageView alloc] initWithFrame:TS_CGRectMake(100, 100, 50, 50)];
這樣我們得出的就是轉換后的坐標了. 這樣,這個imageview在5,6和6Plus的位置和尺寸比例都是一樣的. 媽媽再也不用擔心屏幕的適配了.
如果整個項目做完后才開始做適配的話這個方法的優勢就體現出來了,面對幾十個工程文件,只需自定義并且替換你的CGRectMake方法,再加上storyBoradAutoLay這個方法就瞬間完成大部分甚至全部的適配,如果遇到tableView的或者其他的手動調整一下即可.
當然這個我已經準備設計一個類, 寫好了我會第一時間放在我的gitHub上,方便大家的使用.