921更新宣言
感謝大家回來聽我道個(gè)歉堰乔。Sooooorryyyyy~~~仓犬,更好的解決方案來晚了。
最近抽空繼續(xù)研究了下超棺,又和中國(guó)好同事們一起商討(在西貝門口圍著13寸電腦邊排隊(duì)邊討論向族,此情此景)。終于有了一些新的發(fā)現(xiàn)棠绘。
之前B哥哥(我)說件相,storyboard的開機(jī)圖,我只能通過截圖的方式拿到view氧苍。這句話即對(duì)又錯(cuò)夜矗,的確如果是拿view,那么目前是只有截圖的方式让虐,但是原因并不只是約束紊撕,具體的后面說。然后換種思路赡突,如果我們拿controller对扶,會(huì)更加的方便。
接下來我會(huì)更新本篇文檔麸俘,增加補(bǔ)充controller的相關(guān)處理辩稽。根據(jù)實(shí)踐惧笛,就展示開屏从媚,我覺得(controller + new window) is more 簡(jiǎn)單 than (keywindow add view)
。
bBbBbBbBbBbBbBbBbBbB 華麗麗的分割線患整,以下正文 BbBbBbBbBbBbBbBbBbBb
前言的前言
作者 ==> 我 ==> 大娃 ==> Big Baby ==> BB ==> BB ==> B
以后文中出現(xiàn)B拜效,大家不要驚訝喷众,請(qǐng)保持冷靜。
前言
所謂的開機(jī)畫面紧憾,就是應(yīng)用啟動(dòng)圖到千。打開應(yīng)用的第一福畫面,這個(gè)畫面不是通過代碼寫的赴穗,而是工程配置憔四。那么我們是否有辦法通過代碼獲取到,并且呈現(xiàn)出來呢般眉?這里B給你YES了赵。
發(fā)展至今有2種方式實(shí)現(xiàn):Launch Image Source、Launch Screen File甸赃。如下圖:
其實(shí)柿汛,B一直理解為 3 種,Launch Screen File可以是xib和storyboard埠对。
基本上每個(gè)APP都會(huì)用到開機(jī)畫面络断。如果你還沒有使用,看完本文就可以和產(chǎn)品同學(xué)一起規(guī)劃了项玛。開機(jī)后貌笨,如果需要平滑延長(zhǎng)開機(jī)畫面,然后做點(diǎn)什么襟沮,就需要使用到躁绸。
如果是要實(shí)現(xiàn)開機(jī)后再顯示一會(huì)開機(jī)圖(主要是為了將這個(gè)圖片作為背景,來顯示廣告臣嚣,啊~~~~~還說出了自己的目的)净刮,大家可能會(huì)想到一些簡(jiǎn)單的解決方案:
- 【基礎(chǔ)方案】除了APP配置使用到的
Launch Image Source
或者Launch Screen File
,多存一份launch image硅则,在代碼中引用到這張圖片淹父,創(chuàng)建view≡醭妫【毒舌】看似簡(jiǎn)單暑认,不過問題來了,如何解決多屏幕比例問題大审? - 【加強(qiáng)版】存多個(gè)尺寸的圖片蘸际,在不同的設(shè)備,使用不同的徒扶×竿【毒舌】可以,沒毛病,和設(shè)計(jì)師配合好导坟,切圖就是了屿良。
- 【加強(qiáng)版EX】一般開機(jī)圖都是元素相同,布局不同惫周。代碼中我也使用動(dòng)態(tài)布局尘惧,獲取image,手動(dòng)布局递递,嘔了喷橙。【毒舌】也是思路登舞。
- 【加強(qiáng)版EX PRO】……
方法有很多重慢,都能解決問題,不過有個(gè)共通的問題逊躁,一旦開機(jī)圖更新似踱,復(fù)工量不小。接下來B介紹下目前自己的方法稽煤。
B介紹的方式核芽,適用iPad、iPhone及其橫酵熙、豎屏情況下轧简。如果有不適配的,請(qǐng)及時(shí)聯(lián)系我匾二,謝謝哮独。
一、思路
開機(jī)圖至少有3種方式設(shè)置察藐,我們需要通過代碼的方式獲取到這些資源皮璧。
期初我想獲取到啟動(dòng)圖的UIView,然后在keywindow上add分飞。的確這種方式挺好悴务,也方便。不過目前看來獲取UIView會(huì)有一些麻煩譬猫,而且如果APP的window一直變化讯檐,那么會(huì)造成更多意料之外的事情。所以B現(xiàn)在更傾向獲取controller染服,然后創(chuàng)建一個(gè)新的window别洪。
接下來分別介紹下如何有效獲取各種資源。
二柳刮、獲取Launch Image Source
此處先獲取開機(jī)圖的View(畢竟image的直接獲取就是view)挖垛,我們?cè)诤竺娼M建controller痒钝。
+ (NSString *)launchImageName {
NSString *viewOrientation = UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) ? @"Portrait" : @"Landscape";
CGSize viewSize = [UIScreen mainScreen].bounds.size;
NSString *launchImage = nil;
NSArray* imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"];
for (NSDictionary* dict in imagesDict) {
CGSize imageSize = CGSizeFromString(dict[@"UILaunchImageSize"]);
if ([self size1:imageSize equleToSize2:viewSize] &&
[viewOrientation isEqualToString:dict[@"UILaunchImageOrientation"]]) {
launchImage = dict[@"UILaunchImageName"];
}
}
return launchImage;
}
+ (UIView *)picLaunchView {
UIView *launchView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self launchImageName]]];
launchView.frame = [UIScreen mainScreen].bounds;
launchView.contentMode = UIViewContentModeScaleAspectFill;
return launchView;
}
其中有個(gè)size比較的方法,因?yàn)榭紤]到了屏幕旋轉(zhuǎn)晕换,所以寫了個(gè)模糊判斷午乓。寫的比較隨意站宗,大家隨便看看即可闸准,這里的吐槽B就不管了。
+ (BOOL)size1:(CGSize)size1 equleToSize2:(CGSize)size2 {
CGSize _size1;
CGSize _size2;
_size1.width = MIN(size1.width, size1.height);
_size1.height = MAX(size1.width, size1.height);
_size2.width = MIN(size2.width, size2.height);
_size2.height = MAX(size2.width, size2.height);
return CGSizeEqualToSize(_size1, _size2);
}
要點(diǎn)
- 通過
UILaunchImages
獲取到圖片的名字梢灭; - 根據(jù)size比較夷家,拿到適合本設(shè)備的圖片;
- 判斷圖片的方向敏释,拿到正確的圖片库快。這里估計(jì)有同學(xué)會(huì)問為什么要判斷方向,因?yàn)?em>B做過一個(gè)應(yīng)用同時(shí)適配豎屏iPhone和橫屏iPad钥顽。(>_<)
三义屏、獲取Launch Screen File(xib)
此處有更新,直接獲取controller蜂大。
+ (UIViewController *)nibLaunchView {
UIView *launchView = nil;
NSString *xibName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UILaunchStoryboardName"];
if ([xibName length] > 0) {
@try {
launchView = [[[NSBundle mainBundle] loadNibNamed: xibName owner:nil options:nil] firstObject];
} @catch (NSException *exception) {
}
}
[launchView setFrame:[UIScreen mainScreen].bounds];
UIViewController *controller = [UIViewController new];
[controller.view addSubview:view];
return controller;
}
要點(diǎn)
- 通過
UILaunchStoryboardName
獲取到nib的名字闽铐。沒錯(cuò),雖然是xib奶浦,但是因?yàn)槎际?code>Launch Screen File兄墅; - 通過name,獲取到view array澳叉。B偷懶隙咸,在這里直接使用了
firstObject
,作為嚴(yán)謹(jǐn)?shù)娜顺上矗鋵?shí)是可以判斷下的五督; - 這里的
try
大家也要加上。雖然你拿到了名字瓶殃,但是不一定可以拿到nib概荷。如果拿不到,loadNibNamed
會(huì)拋異常的碌燕,在沒有try
的情況下误证,就直接再見了。 -
setFrame
是一個(gè)必要過程修壕,如果不加愈捅,你可以試試看哦。
四慈鸠、獲取Launch Screen File(storyboard)
執(zhí)意獲取UIView蓝谨,把事情變的復(fù)雜許多。直接獲取Controller,簡(jiǎn)單譬巫、有效咖楣。
+ (UIViewController *)nibLaunchView { __FunctionPoint__
UIViewController *controller = nil;
NSString *storyboardName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UILaunchStoryboardName"];
if ([storyboardName length] > 0) {
@try {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:name bundle:nil];
controller = [storyboard instantiateInitialViewController];
} @catch (NSException *exception) {
}
}
return controller;
}
說明
刪除了之前的解釋,B來說說之前所謂的約束當(dāng)?shù)缆簦瑂toryboard就無效的原因诱贿。
其實(shí)這么理解是不對(duì)的。當(dāng)我們獲取到storyboard.controller.view
時(shí)咕缎,大部分約束是有效的珠十,那么無效的是什么——Top Layout Guide。就是它凭豪,在拿到view的時(shí)候焙蹭,這個(gè)約束是無效的。各種姿勢(shì)都試了嫂伞,始終無法獲取有效的view孔厉,除非截圖。
題外話帖努,可以忽略這段撰豺。為什么B一開始沒發(fā)現(xiàn)問題根源。說來慚愧然磷,B做頁面的經(jīng)驗(yàn)一般郑趁,特別是IB方式,還好有龍哥和山哥幫忙姿搜,讓我瞬間領(lǐng)悟寡润。懷念自己曾經(jīng)的iOS團(tuán)隊(duì):無所不知的龍哥、最穩(wěn)的特種兵強(qiáng)哥舅柜、務(wù)實(shí)的偉哥梭纹、無所不會(huì)的山哥。現(xiàn)在想想致份,都能笑出聲來变抽。匆匆2年多,感謝你們陪我一起玩氮块。分開不重要……說多了绍载。
好了,現(xiàn)在看來滔蝉,storyboard的情況下獲取controller击儡,尤為的簡(jiǎn)單。同樣是通過UILaunchStoryboardName
獲取到storyboard文件蝠引。并且通過instantiateInitialViewController
拿到controller阳谍。
既然xib和storyboard是類似的蛀柴,那么代碼可以整合下,一次性獲取有效內(nèi)容矫夯。
+ (UIViewController *)nibLaunchViewController {
UIViewController *launchViewController = nil;
NSString *storyboardName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UILaunchStoryboardName"];
if ([storyboardName length] > 0) {
@try {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
launchViewController = [storyboard instantiateInitialViewController];
} @catch (NSException *exception) {
}
if (!launchViewController) {
@try {
UIView *view = [[[NSBundle mainBundle] loadNibNamed:storyboardName owner:nil options:nil] firstObject];
[view setFrame:[UIScreen mainScreen].bounds];
launchViewController = [UIViewController new];
[launchViewController.view addSubview:view];
} @catch (NSException *exception) {
}
}
}
return launchViewController;
}
五鸽疾、其余代碼
現(xiàn)在使用UIWindow來啟動(dòng)圖。省略的代碼上文查找训貌。
+ (BOOL)size1:(CGSize)size1 equleToSize2:(CGSize)size2 {
...
}
+ (UIViewController *)nibLaunchViewController {
...
}
+ (UIView *)picLaunchView {
...
}
+ (NSString *)launchImageName {
...
}
+ (UIViewController *)defaultLaunchViewController {
UIViewController *launchViewController = [self nibLaunchViewController];
if (launchViewController) {
return launchViewController;
}
UIView *picLaunchView = [self picLaunchView];
if (picLaunchView) {
launchViewController = [UIViewController new];
[launchViewController.view addSubview:picLaunchView];
}
return launchViewController;
}
+ (void)showLaunchView {
UIViewController *controller = [self defaultLaunchViewController];
if (!controller) {
controller = [UIViewController new];
[controller.view setBackgroundColor:[UIColor whiteColor]];
}
UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.rootViewController = rootController;
[window makeKeyAndVisible];
}
- 通過
[obj showLaunchView]
直接顯示制肮; - 優(yōu)先級(jí)storyboard > xib > launch image;
- 支持iPhone旺订、iPad弄企,橫屏超燃、豎屏区拳。
本文又臭又長(zhǎng),感謝再次品味~~~~
其實(shí)意乓,其實(shí)樱调,在window顯示的地方還是有點(diǎn)細(xì)節(jié),本文可以讓你做完事情届良,但不是做好笆凌。
B的口頭禪是“不要在意這些細(xì)節(jié)”,然而又是個(gè)非常注重細(xì)節(jié)的人士葫。
本來打住的話題乞而,重新打開,發(fā)現(xiàn)有更多想說的慢显。下篇預(yù)告《iOS啟動(dòng)圖你需要關(guān)注的小問題》