前言:
之前做過(guò)一套關(guān)于UIAlertView/UIAlertController的混合封裝(舊版封裝鏈接:iOS (封裝)一句話調(diào)用系統(tǒng)的alertView和alertController )
那個(gè)是將alertView和alertController做了版本適配封裝在一起的揍愁,提供了變參和數(shù)組兩種方式蝴悉,不過(guò)現(xiàn)在看來(lái),雖然是“一句話”調(diào)用咆贬,但并不是很優(yōu)雅的方式。
這次辟拷,改變了方案撞羽,將UIAlertView和UIAlertController分開(kāi)進(jìn)行了處理,整體代碼也輕量了很多衫冻。
新版的代碼及Demo見(jiàn)GitHub:
- 基于UIAlertView封裝的JXTAlertView诀紊,這個(gè)是將之前寫(xiě)Demo時(shí)搞的一套快捷使用alertView的工具抽離整理出來(lái)的,并提供了C函數(shù)直接調(diào)用隅俘,像這樣:
jxt_showAlertTitle(@"簡(jiǎn)易調(diào)試使用alert邻奠,單按鈕,標(biāo)題默認(rèn)為“確定”");
就可以直接顯示出一個(gè)alertView为居。 - 基于UIAlertController封裝的JXTAlertController碌宴,支持iOS8及以上。調(diào)用方式為UIViewController的擴(kuò)展分類方法蒙畴,支持使用鏈?zhǔn)秸Z(yǔ)法的方式配置alert的按鈕及樣式唧喉,相對(duì)于變參或者數(shù)組,更加簡(jiǎn)潔忍抽。
1. JXTAlertView 便捷調(diào)試工具
之所以叫做快捷調(diào)試工具八孝,就是因?yàn)檫@套代碼是之前寫(xiě)Demo時(shí)搞出來(lái)的。所以鸠项,如果不是要適配iOS7及以下版本的話干跛,這套代碼還是建議只用在平時(shí)Demo測(cè)試。也因此祟绊,并沒(méi)有針對(duì)UIActionSheet再進(jìn)行封裝楼入,說(shuō)白了是因?yàn)閼小?br> 平時(shí)寫(xiě)一些Demo代碼時(shí),總會(huì)用到alert牧抽、toast嘉熊、HUD這些工具,如果沒(méi)有一套簡(jiǎn)便的工具,會(huì)麻煩很多,所以便從輕量便捷角度出發(fā)阵漏,基于UIAlertView炫乓,封裝實(shí)現(xiàn)了alert吴藻、toast、HUD這些常用工具。
1.1.快捷使用alertView
如果只是簡(jiǎn)單的一個(gè)提示,可以這樣使用(這里只是一個(gè)示例衫画,詳細(xì)用法見(jiàn)源碼):
jxt_showAlertTitle(@"簡(jiǎn)易調(diào)試使用alert,單按鈕瓮栗,標(biāo)題默認(rèn)為“確定”");
其實(shí)現(xiàn)是基于:
[JXTAlertView showAlertViewWithTitle:title
message:message
cancelButtonTitle:cancelButtonTitle
otherButtonTitle:otherButtonTitle
cancelButtonBlock:cancelBlock
otherButtonBlock:otherBlock];
這是常用的兩個(gè)以內(nèi)的按鈕的alertView削罩,也可以這樣使用:
jxt_showAlertTwoButton(@"title", @"message", @"cancel", ^(NSInteger buttonIndex) {
NSLog(@"cancel");
}, @"other", ^(NSInteger buttonIndex) {
NSLog(@"other");
});
針對(duì)于復(fù)雜的多按鈕的alertView瞄勾,還是使用變參方式,按鈕響應(yīng)弥激,根據(jù)添加的按鈕標(biāo)題的index號(hào)依序區(qū)分:
[JXTAlertView showAlertViewWithTitle:@"title"
message:@"message"
cancelButtonTitle:@"cancel"
buttonIndexBlock:^(NSInteger buttonIndex) {
if (buttonIndex == 0) {
NSLog(@"cancel");
}
else if (buttonIndex == 1) {
NSLog(@"按鈕1");
}
else if (buttonIndex == 2) {
NSLog(@"按鈕2");
}
else if (buttonIndex == 3) {
NSLog(@"按鈕3");
}
else if (buttonIndex == 4) {
NSLog(@"按鈕4");
}
else if (buttonIndex == 5) {
NSLog(@"按鈕5");
}
} otherButtonTitles:@"按鈕1", @"按鈕2", @"按鈕3", @"按鈕4", @"按鈕5", nil];
1.2.簡(jiǎn)單的toast
這里的toast提示丰榴,有別于傳統(tǒng)意義上的toast,因?yàn)槠涫腔赼lertView實(shí)現(xiàn)的秆撮,是一個(gè)沒(méi)有按鈕的alertView』豢觯可自定義展示延時(shí)時(shí)間职辨,支持關(guān)閉回調(diào)的配置。
[JXTAlertView showToastViewWithTitle:@"title"
message:@"message"
duration:2
dismissCompletion:^(NSInteger buttonIndex) {
NSLog(@"關(guān)閉");
}];
1.3.三種HUD的實(shí)現(xiàn)
這里的HUD區(qū)別于toast之處在于戈二,其關(guān)閉時(shí)機(jī)可控舒裤,并不是單純的一個(gè)延時(shí)展示。
三種HUD是指單純的文字型觉吭、帶風(fēng)火輪(菊花)的加載窗腾供、帶進(jìn)度條的加載窗。
后兩者用KVC的方式訪問(wèn)了alertView的私有屬性accessoryView
實(shí)現(xiàn)鲜滩,這樣做可能沒(méi)有太大問(wèn)題伴鳖,不過(guò)還是不建議線上開(kāi)發(fā)使用,而且利用這種方式訪問(wèn)私有屬性本來(lái)就是不太安全的徙硅,一旦key(私有屬性名)改變了榜聂,不做容錯(cuò)處理,會(huì)崩潰嗓蘑,源碼實(shí)現(xiàn)中做了一定的容錯(cuò)须肆,但是,一旦對(duì)應(yīng)key變化桩皿,也就導(dǎo)致對(duì)應(yīng)功能失效了豌汇。
- 示例代碼(C函數(shù)方式):
jxt_showLoadingHUDTitleMessage(@"title", @"message");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
jxt_dismissHUD();
});
HUD還有對(duì)應(yīng)的簡(jiǎn)易的顯示加載成功失敗狀態(tài)的方法,以及刷新進(jìn)度條進(jìn)度值的方法泄隔,詳情見(jiàn)Demo拒贱。
2. JXTAlertController(iOS8)(鏈?zhǔn)秸Z(yǔ)法的“隱患”)
JXTAlertController是基于系統(tǒng)的UIAlertController封裝的,因此也只能支持iOS8及以上系統(tǒng)版本佛嬉。
雖然源碼中的JXTAlertManagerHeader.h
做了一個(gè)版本適配柜思,但是,其意義更多在于提示巷燥,很可能因此出錯(cuò)赡盘,所以,如果要適配iOS7缰揪,對(duì)應(yīng)方法還是需要自行適配陨享。
下面都以alert舉例葱淳,actionSheet同理。
2.1.結(jié)構(gòu)說(shuō)明
/**
JXTAlertController: show-alert(iOS8)
@param title title
@param message message
@param appearanceProcess alert配置過(guò)程
@param actionBlock alert點(diǎn)擊響應(yīng)回調(diào)
*/
- (void)jxt_showAlertWithTitle:(nullable NSString *)title
message:(nullable NSString *)message
appearanceProcess:(JXTAlertAppearanceProcess)appearanceProcess
actionsBlock:(nullable JXTAlertActionBlock)actionBlock NS_AVAILABLE_IOS(8_0);
上述方法是針對(duì)UIViewController
做的分類擴(kuò)展抛姑,詳見(jiàn)源碼赞厕。
也就是在某個(gè)VC中使用時(shí),可直接用self
指針調(diào)用定硝。
JXTAlertAppearanceProcess
是配置塊皿桑,JXTAlertActionBlock
是按鈕響應(yīng)回調(diào)塊。
2.2.鏈?zhǔn)秸Z(yǔ)法添加按鈕
[self jxt_showActionSheetWithTitle:@"title"
message:@"message"
appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
alertMaker.
addActionCancelTitle(@"cancel").
addActionDestructiveTitle(@"按鈕1").
addActionDefaultTitle(@"按鈕2").
addActionDefaultTitle(@"按鈕3").
addActionDestructiveTitle(@"按鈕4");
} actionsBlock:^(NSInteger buttonIndex, UIAlertAction * _Nonnull action, JXTAlertController * _Nonnull alertSelf) {
if ([action.title isEqualToString:@"cancel"]) {
NSLog(@"cancel");
}
else if ([action.title isEqualToString:@"按鈕1"]) {
NSLog(@"按鈕1");
}
else if ([action.title isEqualToString:@"按鈕2"]) {
NSLog(@"按鈕2");
}
else if ([action.title isEqualToString:@"按鈕3"]) {
NSLog(@"按鈕3");
}
else if ([action.title isEqualToString:@"按鈕4"]) {
NSLog(@"按鈕4");
}
}];
appearanceProcess
配置塊中蔬啡,alertMaker
是當(dāng)前alertController對(duì)象诲侮,addActionCancelTitle(@"cancel")
是添加一個(gè)按鈕,其等效于:
[alertController addAction:[UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}]];
這里引入了簡(jiǎn)單的鏈?zhǔn)秸Z(yǔ)法箱蟆,可以連續(xù)添加系統(tǒng)支持的三類action按鈕沟绪,當(dāng)然UIAlertActionStyleCancel
這個(gè)樣式的action只能添加一次。這樣可以大大簡(jiǎn)化代碼空猜。
actionsBlock
是action按鈕響應(yīng)回調(diào)绽慈,可以根據(jù)index區(qū)分響應(yīng),index根據(jù)執(zhí)行add的語(yǔ)法鏈從0依序增加辈毯,cancel類型的action布局位置是固定的坝疼,和添加順序無(wú)關(guān),但其index與添加順序有關(guān)谆沃。
對(duì)于復(fù)雜或者特殊的alertController裙士,也可以根據(jù)action.title或者action區(qū)分響應(yīng)。
2.3.鏈?zhǔn)秸Z(yǔ)法的“隱患”
用過(guò)Masonry
這個(gè)庫(kù)的管毙,應(yīng)該都對(duì)鏈?zhǔn)秸Z(yǔ)法不會(huì)太陌生腿椎。鏈?zhǔn)秸Z(yǔ)法可以使得代碼簡(jiǎn)化且邏輯清晰化。但是夭咬,其也有一定的“隱患”存在啃炸。
Masonry
應(yīng)該是用的最多的一個(gè)自動(dòng)布局的三方庫(kù),類似的還有SDAutoLayout
(這里只是舉例卓舵,同樣的三方還有很多南用,這個(gè)應(yīng)該是除了Masonry
外,用的相對(duì)多一些的一個(gè))這樣的掏湾,同樣的鏈?zhǔn)秸Z(yǔ)法裹虫,后者似乎更加簡(jiǎn)潔優(yōu)雅。那為什么大名鼎鼎的Masonry
不這么干呢融击?我想是因?yàn)椤鞍踩薄?/p>
用SDAutoLayout
的Demo做一個(gè)實(shí)驗(yàn):
這里把view0置為nil筑公,之后運(yùn)行,程序直接崩潰了尊浪。匣屡。封救。這類似于執(zhí)行一個(gè)未賦值的空block捣作。
有人可能會(huì)認(rèn)為這樣的實(shí)驗(yàn)沒(méi)有意義誉结,為nil了干嘛還要布局呢券躁?其實(shí)這是筆者前陣子在封裝一個(gè)鏈?zhǔn)綆?kù)時(shí)遇到的問(wèn)題:實(shí)際應(yīng)用開(kāi)發(fā)中惩坑,情況要復(fù)雜很多以舒,有些view是動(dòng)態(tài)添加的,甚至是根據(jù)接口數(shù)據(jù)動(dòng)態(tài)創(chuàng)建的搪泳,如果在處理這類代碼邏輯中稍有不慎岸军,就會(huì)造成上述問(wèn)題,給不存在的view進(jìn)行布局瓦侮,直接導(dǎo)致程序崩潰艰赞。。肚吏。
其實(shí)這也是代碼書(shū)寫(xiě)規(guī)范的問(wèn)題方妖,針對(duì)這類動(dòng)態(tài)view,在處理時(shí)罚攀,本就應(yīng)該添加if
條件判斷的党觅,不過(guò)有時(shí)容易忽視,或者他人接手相關(guān)代碼時(shí)斋泄,也容易忽略杯瞻。如果用Masonry
的塊配置布局,就不會(huì)發(fā)生這類問(wèn)題炫掐,因?yàn)檫@種情況魁莉,對(duì)于Masonry
那種寫(xiě)法,就是一個(gè)空指針執(zhí)行一個(gè)方法募胃,其結(jié)果就是不執(zhí)行旗唁,而像SDAutoLayout
這類的,不作判空處理痹束,就會(huì)導(dǎo)致程序崩潰检疫。這里尤其要注意。
2.4.其他配置
針對(duì)alert上的輸入框祷嘶,保持系統(tǒng)的添加方式电谣,示例如下:
[self jxt_showAlertWithTitle:@"title"
message:@"message"
appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
alertMaker.
addActionDestructiveTitle(@"獲取輸入框1").
addActionDestructiveTitle(@"獲取輸入框2");
[alertMaker setAlertDidShown:^{
[self logMsg:@"alertDidShown"];//不用擔(dān)心循環(huán)引用
}];
alertMaker.alertDidDismiss = ^{
[self logMsg:@"alertDidDismiss"];
};
[alertMaker addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"輸入框1-請(qǐng)輸入";
}];
[alertMaker addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"輸入框2-請(qǐng)輸入";
}];
} actionsBlock:^(NSInteger buttonIndex, UIAlertAction * _Nonnull action, JXTAlertController * _Nonnull alertSelf) {
if (buttonIndex == 0) {
UITextField *textField = alertSelf.textFields.firstObject;
[self logMsg:textField.text];//不用擔(dān)心循環(huán)引用
}
else if (buttonIndex == 1) {
UITextField *textField = alertSelf.textFields.lastObject;
[self logMsg:textField.text];
}
}];
對(duì)于alert展示和關(guān)閉的回調(diào)秽梅,同樣支持以block的方式配置。
如果appearanceProcess
塊不進(jìn)行任何配置操作剿牺,即無(wú)按鈕的alert企垦,同樣默認(rèn)以toast模式處理∩估矗可通過(guò)設(shè)置toastStyleDuration
屬性钞诡,配置toast展示延遲時(shí)間。
2.5.改變alertController的字體顏色
可以通過(guò)KVC的方式訪問(wèn)alertController的私有屬性湃崩,從而進(jìn)行修改對(duì)應(yīng)的字體的顏色荧降,甚至字體。
對(duì)于UIAlertAction
攒读,可以用下面的方式修改字體顏色:
[alertAction setValue:[UIColor grayColor] forKey:@"titleTextColor"];
但是就像前面說(shuō)的朵诫,個(gè)人并不推薦這類方式,所以源碼中沒(méi)有提供相關(guān)的方法薄扁。
如果有對(duì)應(yīng)的特殊需求剪返,總體來(lái)說(shuō),還是自定義alert視圖比較靈活邓梅,網(wǎng)上相關(guān)的開(kāi)源庫(kù)也有很多可以直接使用脱盲,不必總是糾結(jié)于系統(tǒng)的實(shí)現(xiàn)方式。
最后日缨,歡迎使用JXTAlertManager钱反,如果遇到任何問(wèn)題,請(qǐng)及時(shí)聯(lián)系作者匣距。
參考文章:
1.iOS更改UIActionController彈出字體的樣式
2.UIAlertController 簡(jiǎn)單修改title以及按鈕的字體顏色
3.How to add subview inside UIAlertView for iOS 7?
4.UIAlertView addSubview in iOS7
5.iOS UIAlertView中UIActivityindicatorView風(fēng)火輪提示加載等待