iOS 更加優雅便捷的UIAlertView/UIAlertController封裝使用

發表於2017-01-02

前言:

之前做過一套關於UIAlertView/UIAlertController的混合封裝,詳見:

iOS (封裝)一句話呼叫系統的alertView和alertController

這個是將alertView和alertController做了版本適配封裝在一起的,提供了變參和陣列兩種方式,不過現在看來,雖然是“一句話”呼叫,但並不是很優雅的方式。

這次,改變了方案,將UIAlertView和UIAlertController分開進行了處理,整體程式碼也輕量了很多。

  • 基於UIAlertView封裝的JXTAlertView,這個是將之前寫Demo時搞的一套快捷使用alertView的工具抽離整理出來的,並提供了C函式直接呼叫,像這樣:
    jxt_showAlertTitle(@"簡易除錯使用alert,單按鈕,標題預設為“確定”");
    就可以直接顯示出一個alertView。
  • 基於UIAlertController封裝的JXTAlertController,支援iOS8及以上。呼叫方式為UIViewController的擴充套件分類方法,支援使用鏈式語法的方式配置alert的按鈕及樣式,相對於變參或者陣列,更加簡潔。

程式碼及Demo見GitHub:

JXTAlertManager

111468630-5faebd1f6f2a3ccf
JXTAlertManager大體結構

1. JXTAlertView 便捷除錯工具

之所以叫做快捷除錯工具,就是因為這套程式碼是之前寫Demo時搞出來的。所以,如果不是要適配iOS7及以下版本的話,這套程式碼還是建議只用在平時Demo測試。也因此,並沒有針對UIActionSheet再進行封裝,說白了是因為懶……
平時寫一些Demo程式碼時,總會用到alert、toast、HUD這些工具,如果沒有一套簡便的工具,會麻煩很多,所以便從輕量便捷角度出發,基於UIAlertView,封裝實現了alert、toast、HUD這些常用工具。

121468630-e99f5311021af24a
JXTAlertView大致效果演示

1.1.快捷使用alertView

如果只是簡單的一個提示,可以這樣使用(這裡只是一個示例,詳細用法見原始碼):
jxt_showAlertTitle(@"簡易除錯使用alert,單按鈕,標題預設為“確定”");
其實現是基於:

這是常用的兩個以內的按鈕的alertView,也可以這樣使用:

針對於複雜的多按鈕的alertView,還是使用變參方式,按鈕響應,根據新增的按鈕標題的index號依序區分:

1.2.簡單的toast

這裡的toast提示,有別於傳統意義上的toast,因為其是基於alertView實現的,是一個沒有按鈕的alertView。可自定義展示延時時間,支援關閉回撥的配置。

1.3.三種HUD的實現

這裡的HUD區別於toast之處在於,其關閉時機可控,並不是單純的一個延時展示。
三種HUD是指單純的文字型、帶風火輪(菊花)的載入窗、帶進度條的載入窗。
後兩者用KVC的方式訪問了alertView的私有屬性accessoryView實現,這樣做可能沒有太大問題,不過還是不建議線上開發使用,而且利用這種方式訪問私有屬性本來就是不太安全的,一旦key(私有屬性名)改變了,不做容錯處理,會崩潰,原始碼實現中做了一定的容錯,但是,一旦對應key變化,也就導致對應功能失效了。

  • 示例程式碼(C函式方式):

    HUD還有對應的簡易的顯示載入成功失敗狀態的方法,以及重新整理進度條進度值的方法,詳情見Demo。

2. JXTAlertController(iOS8)(鏈式語法的“隱患”)

JXTAlertController是基於系統的UIAlertController封裝的,因此也只能支援iOS8及以上系統版本。
雖然原始碼中的JXTAlertManagerHeader.h做了一個版本適配,但是,其意義更多在於提示,很可能因此出錯,所以,如果要適配iOS7,對應方法還是需要自行適配。
下面都以alert舉例,actionSheet同理。

131468630-b1e71fb54160106c
JXTAlertController大致效果演示

2.1.結構說明

上述方法是針對UIViewController做的分類擴充套件,詳見原始碼。
也就是在某個VC中使用時,可直接用self指標呼叫。
JXTAlertAppearanceProcess是配置塊,JXTAlertActionBlock是按鈕響應回撥塊。

2.2.鏈式語法新增按鈕

appearanceProcess配置塊中,alertMaker是當前alertController物件,addActionCancelTitle(@"cancel")是新增一個按鈕,其等效於:

這裡引入了簡單的鏈式語法,可以連續新增系統支援的三類action按鈕,當然UIAlertActionStyleCancel這個樣式的action只能新增一次。這樣可以大大簡化程式碼。

actionsBlock是action按鈕響應回撥,可以根據index區分響應,index根據執行add的語法鏈從0依序增加,cancel型別的action佈局位置是固定的,和新增順序無關,但其index與新增順序有關。
對於複雜或者特殊的alertController,也可以根據action.title或者action區分響應。

2.3.鏈式語法的“隱患”

用過Masonry這個庫的,應該都對鏈式語法不會太陌生。鏈式語法可以使得程式碼簡化且邏輯清晰化。但是,其也有一定的“隱患”存在。
Masonry應該是用的最多的一個自動佈局的三方庫,類似的還有SDAutoLayout(這裡只是舉例,同樣的三方還有很多,這個應該是除了Masonry外,用的相對多一些的一個)這樣的,同樣的鏈式語法,後者似乎更加簡潔優雅。那為什麼大名鼎鼎的Masonry不這麼幹呢?我想是因為“安全”。

SDAutoLayout的Demo做一個實驗:

141468630-1ab34f91d23640d2
view為nil導致的崩潰

這裡把view0置為nil,之後執行,程式直接崩潰了。。。這類似於執行一個未賦值的空block。
有人可能會認為這樣的實驗沒有意義,為nil了幹嘛還要佈局呢?其實這是筆者前陣子在封裝一個鏈式庫時遇到的問題:實際應用開發中,情況要複雜很多,有些view是動態新增的,甚至是根據介面資料動態建立的,如果在處理這類程式碼邏輯中稍有不慎,就會造成上述問題,給不存在的view進行佈局,直接導致程式崩潰。。。
其實這也是程式碼書寫規範的問題,針對這類動態view,在處理時,本就應該新增if條件判斷的,不過有時容易忽視,或者他人接手相關程式碼時,也容易忽略。如果用Masonry的塊配置佈局,就不會發生這類問題,因為這種情況,對於Masonry那種寫法,就是一個空指標執行一個方法,其結果就是不執行,而像SDAutoLayout這類的,不作判空處理,就會導致程式崩潰。這裡尤其要注意。

2.4.其他配置

針對alert上的輸入框,保持系統的新增方式,示例如下:

對於alert展示和關閉的回撥,同樣支援以block的方式配置。
如果appearanceProcess塊不進行任何配置操作,即無按鈕的alert,同樣預設以toast模式處理。可通過設定toastStyleDuration屬性,配置toast展示延遲時間。

2.5.改變alertController的字型顏色

可以通過KVC的方式訪問alertController的私有屬性,從而進行修改對應的字型的顏色,甚至字型。
對於UIAlertAction,可以用下面的方式修改字型顏色:
[alertAction setValue:[UIColor grayColor] forKey:@"titleTextColor"];

151468630-2e11fedfd07f701b
修改UIAlertAction字型顏色的效果

但是就像前面說的,個人並不推薦這類方式,所以原始碼中沒有提供相關的方法。
如果有對應的特殊需求,總體來說,還是自定義alert檢視比較靈活,網上相關的開源庫也有很多可以直接使用,不必總是糾結於系統的實現方式。

最後,歡迎使用JXTAlertManager,如果遇到任何問題,請及時聯絡作者。

參考文章:
1.iOS更改UIActionController彈出字型的樣式
2.UIAlertController 簡單修改title以及按鈕的字型顏色
3.How to add subview inside UIAlertView for iOS 7?
4.UIAlertView addSubview in iOS7
5.iOS UIAlertView中UIActivityindicatorView風火輪提示載入等待

相關文章