iOS 8中使用UIAlertController

iOS 8的新特性之一就是讓接口更有適應(yīng)性、更靈活,因此許多視圖控制器的實(shí)現(xiàn)方式發(fā)生了巨大的變化。全新的UIPresentationController在實(shí)現(xiàn)視圖控制器間的過(guò)渡動(dòng)畫(huà)效果和自適應(yīng)設(shè)備尺寸變化效果(比如說(shuō)旋轉(zhuǎn))中發(fā)揮了重要的作用,它有效地節(jié)省了程序員們的工作量(天地良心?。_€有,某些舊的UIKit控件也同樣發(fā)生了許多變化,比如說(shuō)Alert Views、Action Sheets、Popovers以及Search Bar Controllers。本文將會(huì)對(duì)Alert Views和Action Sheets發(fā)生的改變進(jìn)行一個(gè)大致的介紹,我們會(huì)采用Objective-C和swift兩種語(yǔ)言同時(shí)進(jìn)行代碼說(shuō)明。

UIAlertView

隨著蘋果上次iOS 5的發(fā)布,對(duì)話框視圖樣式出現(xiàn)在了我們面前,直到現(xiàn)在它都沒(méi)有發(fā)生過(guò)很大的變化。下面的代碼片段展示了如何初始化和顯示一個(gè)帶有“取消”和“好的”按鈕的對(duì)話框視圖。

Objective-C版本:

UIAlertView?*alertview?=?[[UIAlertView?alloc]?initWithTitle:@"標(biāo)題"?message:@"這個(gè)是UIAlertView的默認(rèn)樣式"?delegate:self?cancelButtonTitle:@"取消"?otherButtonTitles:@"好的",?nil];

[alertview?show];

UIAlertView的默認(rèn)樣式

swift版本和Objective-C版本不同,在swift中,alertView的初始化只允許創(chuàng)建擁有一個(gè)取消按鈕的對(duì)話框視圖。或許您可以看到帶有otherButtonTitles的init方法,但是很遺憾,這個(gè)方法是沒(méi)有辦法通過(guò)編譯的。

var?alertView?=?UIAlertView(title:?"標(biāo)題",?message:?"這個(gè)是UIAlertView的默認(rèn)樣式",?delegate:?self,?cancelButtonTitle:?"取消")

alertView.show()

swift版本的UIAlertView

要能夠創(chuàng)建和上面Objective-C版本相同的對(duì)話框視圖,我們可以采取曲線救國(guó)的方法,雖然麻煩了些,但是我們?yōu)榱四康目梢圆粨袷侄蔚?,是吧?/p>

var?alertView?=?UIAlertView()

alertView.delegate?=?self

alertView.title?=?"標(biāo)題"

alertView.message?=?"這個(gè)是UIAlertView的默認(rèn)樣式"

alertView.addButtonWithTitle("取消")

alertView.addButtonWithTitle("好的")

alertView.show()

您也可以通過(guò)更改UIAlertView的alertViewStyle屬性來(lái)實(shí)現(xiàn)輸入文字、密碼甚至登錄框的效果。

UIAlertView文本對(duì)話框

UIAlertView密碼對(duì)話框

UIAlertView登錄對(duì)話框

UIAlertViewDelegate協(xié)議擁有響應(yīng)對(duì)話框視圖的按鈕動(dòng)作的回調(diào)方法。還有當(dāng)文本框內(nèi)容改變時(shí),調(diào)用alertViewShouldEnableOtherButton:方法可以讓按鈕動(dòng)態(tài)地可用或者不可用。

要說(shuō)明一點(diǎn),蘋果官方現(xiàn)在并不提倡在iOS 8中使用UIAlertView,取而代之的是UIAlertController。下面我們就來(lái)介紹UIAlertController的使用方法。

UIAlertController

在iOS 8中,UIAlertController在功能上是和UIAlertView以及UIActionSheet相同的,UIAlertController以一種模塊化替換的方式來(lái)代替這兩貨的功能和作用。是使用對(duì)話框(alert)還是使用上拉菜單(action sheet),就取決于在創(chuàng)建控制器時(shí),您是如何設(shè)置首選樣式的。

一個(gè)簡(jiǎn)單的對(duì)話框例子

您可以比較一下兩種不同的創(chuàng)建對(duì)話框的代碼,創(chuàng)建基礎(chǔ)UIAlertController的代碼和創(chuàng)建UIAlertView的代碼非常相似:

Objective-C版本:

UIAlertController?*alertController?=?[UIAlertController?alertControllerWithTitle:@"標(biāo)題"?message:@"這個(gè)是UIAlertController的默認(rèn)樣式"?preferredStyle:UIAlertControllerStyleAlert];

swift版本:

var?alertController?=?UIAlertController(title:?"標(biāo)題",?message:?"這個(gè)是UIAlertController的默認(rèn)樣式",?preferredStyle:?UIAlertControllerStyle.Alert)

同創(chuàng)建UIAlertView相比,我們無(wú)需指定代理,也無(wú)需在初始化過(guò)程中指定按鈕。不過(guò)要特別注意第三個(gè)參數(shù),要確定您選擇的是對(duì)話框樣式還是上拉菜單樣式。

通過(guò)創(chuàng)建UIAlertAction的實(shí)例,您可以將動(dòng)作按鈕添加到控制器上。UIAlertAction由標(biāo)題字符串、樣式以及當(dāng)用戶選中該動(dòng)作時(shí)運(yùn)行的代碼塊組成。通過(guò)UIAlertActionStyle,您可以選擇如下三種動(dòng)作樣式:常規(guī)(default)、取消(cancel)以及警示(destruective)。為了實(shí)現(xiàn)原來(lái)我們?cè)趧?chuàng)建UIAlertView時(shí)創(chuàng)建的按鈕效果,我們只需創(chuàng)建這兩個(gè)動(dòng)作按鈕并將它們添加到控制器上即可。

Objective-C版本:

UIAlertAction?*cancelAction?=?[UIAlertAction?actionWithTitle:@"取消"?style:UIAlertActionStyleCancel?handler:nil];

UIAlertAction?*okAction?=?[UIAlertAction?actionWithTitle:@"好的"?style:UIAlertActionStyleDefault?handler:nil];

[alertController?addAction:cancelAction];

[alertController?addAction:okAction];

swift版本:

var?cancelAction?=?UIAlertAction(title:?"取消",?style:?UIAlertActionStyle.Cancel,?handler:?nil)

var?okAction?=?UIAlertAction(title:?"好的",?style:?UIAlertActionStyle.Default,?handler:?nil)

alertController.addAction(cancelAction)

alertController.addAction(okAction)

最后,我們只需顯示這個(gè)對(duì)話框視圖控制器即可:

Objective-C版本:

[self?presentViewController:alertController?animated:YES?completion:nil];

swift版本:

self.presentViewController(alertController,?animated:?true,?completion:?nil)

UIAlertController默認(rèn)樣式

按鈕顯示的次序取決于它們添加到對(duì)話框控制器上的次序。一般來(lái)說(shuō),根據(jù)蘋果官方制定的《iOS 用戶界面指南》,在擁有兩個(gè)按鈕的對(duì)話框中,您應(yīng)當(dāng)將取消按鈕放在左邊。要注意,取消按鈕是唯一的,如果您添加了第二個(gè)取消按鈕,那么你就會(huì)得到如下的一個(gè)運(yùn)行時(shí)異常:

* Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’

異常信息簡(jiǎn)潔明了,我們?cè)诖司筒毁樖隽恕?/p>

“警示”樣式

什么是“警示”樣式呢?我們先不著急回答這個(gè)問(wèn)題,先來(lái)看一下下面關(guān)于“警示”樣式的簡(jiǎn)單示例。在這個(gè)示例中,我們將前面的示例中的“好的”按鈕替換為了“重置”按鈕。

Objective-C版本:

UIAlertAction?*resetAction?=?[UIAlertAction?actionWithTitle:@"重置"?style:UIAlertActionStyleDestructive?handler:nil];

[alertController?addAction:resetAction];

swift版本:

var?resetAction?=?UIAlertAction(title:?"重置",?style:?UIAlertActionStyle.Destructive,?handler:?nil)

alertController.addAction(resetAction)

“警示”樣式

可以看出,我們新增的那個(gè)“重置”按鈕變成了紅色。根據(jù)蘋果官方的定義,“警示”樣式的按鈕是用在可能會(huì)改變或刪除數(shù)據(jù)的操作上。因此用了紅色的醒目標(biāo)識(shí)來(lái)警示用戶。

文本對(duì)話框

UIAlertController極大的靈活性意味著您不必拘泥于內(nèi)置樣式。以前我們只能在默認(rèn)視圖、文本框視圖、密碼框視圖、登錄和密碼輸入框視圖中選擇,現(xiàn)在我們可以向?qū)υ捒蛑刑砑尤我鈹?shù)目的UITextField對(duì)象,并且可以使用所有的UITextField特性。當(dāng)您向?qū)υ捒蚩刂破髦刑砑游谋究驎r(shí),您需要指定一個(gè)用來(lái)配置文本框的代碼塊。

舉個(gè)栗子吧,要重新建立原來(lái)的登錄和密碼樣式對(duì)話框,我們可以向其中添加兩個(gè)文本框,然后用合適的占位符來(lái)配置它們,最后將密碼輸入框設(shè)置使用安全文本輸入。

Objective-C版本:

UIAlertController?*alertController?=?[UIAlertController?alertControllerWithTitle:@"文本對(duì)話框"?message:@"登錄和密碼對(duì)話框示例"?preferredStyle:UIAlertControllerStyleAlert];

[alertController?addTextFieldWithConfigurationHandler:^(UITextField?*textField){

textField.placeholder?=?@"登錄";

}];

[alertController?addTextFieldWithConfigurationHandler:^(UITextField?*textField)?{

textField.placeholder?=?@"密碼";

textField.secureTextEntry?=?YES;

}];

swift版本:

alertController.addTextFieldWithConfigurationHandler?{

(textField:?UITextField!)?->?Void?in

textField.placeholder?=?"登錄"

}

alertController.addTextFieldWithConfigurationHandler?{

(textField:?UITextField!)?->?Void?in

textField.placeholder?=?"密碼"

textField.secureTextEntry?=?true

}

在“好的”按鈕按下時(shí),我們讓程序讀取文本框中的值。

Objective-C版本:

UIAlertAction?*okAction?=?[UIAlertAction?actionWithTitle:@"好的"?style:UIAlertActionStyleDefault?handler:^(UIAlertAction?*action)?{

UITextField?*login?=?alertController.textFields.firstObject;

UITextField?*password?=?alertController.textFields.lastObject;

...

}];

swift版本:

var?okAction?=?UIAlertAction(title:?"好的",?style:?UIAlertActionStyle.Default)?{

(action:?UIAlertAction!)?->?Void?in

var?login?=?alertController.textFields?.first?as?UITextField

var?password?=?alertController.textFields?.last?as?UITextField

}

如果我們想要實(shí)現(xiàn)UIAlertView中的委托方法alertViewShouldEnableOtherButton:方法的話可能會(huì)有一些復(fù)雜。假定我們要讓“登錄”文本框中至少有3個(gè)字符才能激活“好的”按鈕。很遺憾的是,在UIAlertController中并沒(méi)有相應(yīng)的委托方法,因此我們需要向“登錄”文本框中添加一個(gè)Observer。Observer模式定義對(duì)象間的一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí), 所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新。我們可以在構(gòu)造代碼塊中添加如下的代碼片段來(lái)實(shí)現(xiàn)。

Objective-C版本:

[alertController?addTextFieldWithConfigurationHandler:^(UITextField?*textField){

...

[[NSNotificationCenter?defaultCenter]?addObserver:self?selector:@selector(alertTextFieldDidChange:)?name:UITextFieldTextDidChangeNotification?object:textField];

}];

swift版本:

alertController.addTextFieldWithConfigurationHandler?{

(textField:?UITextField!)?->?Void?in

...

NSNotificationCenter.defaultCenter().addObserver(self,?selector:?Selector("alertTextFieldDidChange:"),?name:?UITextFieldTextDidChangeNotification,?object:?textField)

}

當(dāng)視圖控制器釋放的時(shí)候我們需要移除這個(gè)Observer,我們通過(guò)在每個(gè)按鈕動(dòng)作的handler代碼塊(還有其他任何可能釋放視圖控制器的地方)中添加合適的代碼來(lái)實(shí)現(xiàn)它。比如說(shuō)在okAction這個(gè)按鈕動(dòng)作中:

Objective-C版本:

UIAlertAction?*okAction?=?[UIAlertAction?actionWithTitle:@"好的"?style:UIAlertActionStyleDefault?handler:^(UIAlertAction?*action)?{

...

[[NSNotificationCenter?defaultCenter]?removeObserver:self?name:UITextFieldTextDidChangeNotification?object:nil];

}];

swift版本:

var?okAction?=?UIAlertAction(title:?"好的",?style:?UIAlertActionStyle.Default)?{

(action:?UIAlertAction!)?->?Void?in

...

NSNotificationCenter.defaultCenter().removeObserver(self,?name:?UITextFieldTextDidChangeNotification,?object:?nil)

}

在顯示對(duì)話框之前,我們要凍結(jié)“好的”按鈕

Objective-C版本:

okAction.enabled?=?NO;

swift版本:

okAction.enabled?=?false

接下來(lái),在通知觀察者(notification observer)中,我們需要在激活按鈕狀態(tài)前檢查“登錄”文本框的內(nèi)容。

Objective-C版本:

-?(void)alertTextFieldDidChange:(NSNotification?*)notification{

UIAlertController?*alertController?=?(UIAlertController?*)self.presentedViewController;

if?(alertController)?{

UITextField?*login?=?alertController.textFields.firstObject;

UIAlertAction?*okAction?=?alertController.actions.lastObject;

okAction.enabled?=?login.text.length?>?2;

? ? ? ? ? ? }

}

swift版本:

func?alertTextFieldDidChange(notification:?NSNotification){

var?alertController?=?self.presentedViewController?as?UIAlertController?

if?(alertController?!=?nil)?{

var?login?=?alertController!.textFields?.first?as?UITextField

var?okAction?=?alertController!.actions.last?as?UIAlertAction

okAction.enabled?=?countElements(login.text)?>?2

? ? ? ? ? ? ? ?}

}

UIAlertController的登錄和密碼對(duì)話框示例

好了,現(xiàn)在對(duì)話框的“好的”按鈕被凍結(jié)了,除非在“登錄”文本框中輸入3個(gè)以上的字符:

上拉菜單

當(dāng)需要給用戶展示一系列選擇的時(shí)候(選擇恐懼癥患者殺手),上拉菜單就能夠派上大用場(chǎng)了。和對(duì)話框不同,上拉菜單的展示形式和設(shè)備大小有關(guān)。在iPhone上(緊縮寬度),上拉菜單從屏幕底部升起。在iPad上(常規(guī)寬度),上拉菜單以彈出框的形式展現(xiàn)。

創(chuàng)建上拉菜單的方式和創(chuàng)建對(duì)話框的方式非常類似,唯一的區(qū)別是它們的形式。

Objective-C版本:

UIAlertController?*alertController?=?[UIAlertController?alertControllerWithTitle:@"保存或刪除數(shù)據(jù)"?message:@"刪除數(shù)據(jù)將不可恢復(fù)"?preferredStyle:?UIAlertControllerStyleActionSheet];

swift版本:

var?alertController?=?UIAlertController(title:?"保存或刪除數(shù)據(jù)",?message:?"刪除數(shù)據(jù)將不可恢復(fù)",?preferredStyle:?UIAlertControllerStyle.ActionSheet)

添加按鈕動(dòng)作的方式和對(duì)話框相同。

Objective-C版本:

UIAlertAction?*cancelAction?=?[UIAlertAction?actionWithTitle:@"取消"?style:UIAlertActionStyleCancel?handler:nil];

UIAlertAction?*deleteAction?=?[UIAlertAction?actionWithTitle:@"刪除"?style:UIAlertActionStyleDestructive?handler:nil];

UIAlertAction?*archiveAction?=?[UIAlertAction?actionWithTitle:@"保存"?style:UIAlertActionStyleDefault?handler:nil];

[alertController?addAction:cancelAction];

[alertController?addAction:deleteAction];

[alertController?addAction:archiveAction];

swift版本:

var?cancelAction?=?UIAlertAction(title:?"取消",?style:?UIAlertActionStyle.Cancel,?handler:?nil)

var?deleteAction?=?UIAlertAction(title:?"刪除",?style:?UIAlertActionStyle.Destructive,?handler:?nil)

var?archiveAction?=?UIAlertAction(title:?"保存",?style:?UIAlertActionStyle.Default,?handler:?nil)

alertController.addAction(cancelAction)

alertController.addAction(deleteAction)

alertController.addAction(archiveAction)

您不能在上拉菜單中添加文本框,如果您強(qiáng)行作死添加了文本框,那么就會(huì)榮幸地得到一個(gè)運(yùn)行時(shí)異常:

* Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert’

同樣,簡(jiǎn)單的異常說(shuō)明,我們也不多說(shuō)了。

接下來(lái)我們就可以在iPhone或者其他緊縮寬度的設(shè)備上展示了,不出我們所料,運(yùn)行得很成功。

Objective-C版本:

[self?presentViewController:alertController?animated:YES?completion:nil];

swift版本:

self.presentViewController(alertController,?animated:?true,?completion:?nil)

iPhone上的上拉菜單效果

如果上拉菜單中有“取消”按鈕的話,那么它永遠(yuǎn)都會(huì)出現(xiàn)在菜單的底部,不管添加的次序是如何(就是這么任性)。其他的按鈕將會(huì)按照添加的次序從上往下依次顯示?!秈OS 用戶界面指南》要求所有的“毀壞”樣式按鈕都必須排名第一(紅榜嘛,很好理解的,對(duì)不對(duì)?)。

別激動(dòng)得太早,我們現(xiàn)在還有一個(gè)很嚴(yán)重的問(wèn)題,這個(gè)問(wèn)題隱藏得比較深。當(dāng)我們使用iPad或其他常規(guī)寬度的設(shè)備時(shí),就會(huì)得到一個(gè)運(yùn)行時(shí)異常:

Terminating app due to uncaught exception ‘NSGenericException’, reason: ‘UIPopoverPresentationController (<_uialertcontrolleractionsheetregularpresentationcontroller: 0x7fc619588110="">) should have a non-nil sourceView or barButtonItem set before the presentation occurs.’

就如我們之前所說(shuō),在常規(guī)寬度的設(shè)備上,上拉菜單是以彈出框的形式展現(xiàn)。彈出框必須要有一個(gè)能夠作為源視圖或者欄按鈕項(xiàng)目的描點(diǎn)(anchor point)。由于在本例中我們是使用了常規(guī)的UIButton來(lái)觸發(fā)上拉菜單的,因此我們就將其作為描點(diǎn)。

在iOS 8中我們不再需要小心翼翼地計(jì)算出彈出框的大小,UIAlertController將會(huì)根據(jù)設(shè)備大小自適應(yīng)彈出框的大小。并且在iPhone或者緊縮寬度的設(shè)備中它將會(huì)返回nil值。配置該彈出框的代碼如下:

Objective-C版本:

UIPopoverPresentationController?*popover?=?alertController.popoverPresentationController;

if?(popover){

popover.sourceView?=?sender;

popover.sourceRect?=?sender.bounds;

popover.permittedArrowDirections?=?UIPopoverArrowDirectionAny;

}

swift版本:

var?popover?=?alertController.popoverPresentationController

if?(popover?!=?nil){

popover?.sourceView?=?sender

popover?.sourceRect?=?sender.bounds

popover?.permittedArrowDirections?=?UIPopoverArrowDirection.Any

}

iPad上的上拉菜單效果

UIPopoverPresentationController類同樣也是在iOS 8中新出現(xiàn)的類,用來(lái)替換UIPopoverController的。這個(gè)時(shí)候上拉菜單是以一個(gè)固定在源按鈕上的彈出框的形式顯示的。

要注意UIAlertController在使用彈出框的時(shí)候自動(dòng)移除了取消按鈕。用戶通過(guò)點(diǎn)擊彈出框的外圍部分來(lái)實(shí)現(xiàn)取消操作,因此取消按鈕便不再必需。

釋放對(duì)話框控制器

通常情況下,當(dāng)用戶選中一個(gè)動(dòng)作后對(duì)話框控制器將會(huì)自行釋放。不過(guò)您仍然可以在需要的時(shí)候以編程方式釋放它,就像釋放其他視圖控制器一樣。您應(yīng)當(dāng)在應(yīng)用程序轉(zhuǎn)至后臺(tái)運(yùn)行時(shí)移除對(duì)話框或者上拉菜單。假定我們正在監(jiān)聽(tīng)UIApplicationDidEnterBackgroundNotification通知消息,我們可以在observer中釋放任何顯示出來(lái)的視圖控制器。(參考在viewDidLoad方法中設(shè)立observer的示例代碼)。

Objective-C版本:

-?(void)didEnterBackground:(NSNotification?*)notification

{

[[NSNotificationCenter?defaultCenter]?removeObserver:self?name:UITextFieldTextDidChangeNotification?object:nil];

[self.presentedViewController?dismissViewControllerAnimated:NO?completion:nil];

}

swift版本:

func?didEnterackground(notification:?NSNotification){

NSNotificationCenter.defaultCenter().removeObserver(self,?name:?UITextFieldTextDidChangeNotification,?object:?nil)

self.presentedViewController?.dismissViewControllerAnimated(false,?completion:?nil)

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容