做iOS開發(fā)的同學(xué)想必都用過UIAlertVIew或者UIActionSheet。UIAlertVIew 可以彈出一個(gè)出現(xiàn)在屏幕中間的提示視圖仗嗦,給用戶展示信息雪标,并讓用戶自己選擇操作筷狼,UIActionSheet可以彈出一個(gè)選擇列表动看,讓用戶選擇列表中的某一項(xiàng)操作。使用UIAlertVIew和UIActionSheet非常簡(jiǎn)單躲撰,以下是一個(gè)簡(jiǎn)單的示例代碼:
//UIAlertView
- (void)someButtonClicked {//初始化AlertView
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AlertViewTest"
message:@"message"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"OtherBtn",nil];
[alert show];
}
//按鈕點(diǎn)擊事件的代理
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSLog(@"clickButtonAtIndex:%d",(int)buttonIndex);
//index為-1則是取消针贬,
}
//UIActionSheet
- (void)someButtonClicked {
UIActionSheet * sheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"ddd" destructiveButtonTitle:@"aaa" otherButtonTitles:@"bbb", @"ccc", @"ddd", nil];
sheet.destructiveButtonIndex = 1;
[sheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(@"result = %d", (int)buttonIndex);
}
雖然使用已經(jīng)算是比較簡(jiǎn)單了,但我覺得還是比較麻煩他們都需要設(shè)置delegate來獲得用戶選擇的結(jié)果拢蛋。這么小的界面桦他,把調(diào)用顯示和回調(diào)方法分開寫在2個(gè)方法中,使得原本簡(jiǎn)單的邏輯復(fù)雜了。雖然也不會(huì)復(fù)雜到哪兒去快压,但是每次調(diào)用他們就需要另外寫一個(gè)delegate回調(diào)方法圆仔,覺得還是比較麻煩。
于是便產(chǎn)生了蔫劣,分別給它們寫一個(gè)category 用來對(duì)原生的ui再做一層簡(jiǎn)單地封裝坪郭。(一些復(fù)雜的暫不考慮)然后用block來做回調(diào),這樣子脉幢,一塊簡(jiǎn)單地東西就不用分開在兩個(gè)地方了(才不要拆散它們)歪沃。
我們先簡(jiǎn)單地分析 UIAlertVIew 和 UIActionSheet,其實(shí)他們需要的東西嫌松,并不多沪曙,只是按鈕的事件和對(duì)應(yīng)的action,UIAlertVIew還多了一個(gè)Title和message萎羔,但這些在初始化里面就已經(jīng)初始化好了液走。造成他們分離的主要原因還是action和init分離了。所以要完成這個(gè)不讓他們分離的目的贾陷,實(shí)現(xiàn)這個(gè)category 首先我們需要一個(gè) button的模型來封裝 button的title 和 對(duì)應(yīng)的事件缘眶,事件用block來代替代理(這樣就可以讓他們?cè)谝黄鹆耍?br>
于是我順手在github上搜索了一下,發(fā)現(xiàn)了這個(gè)
https://github.com/jivadevoe/UIAlertView-Blocks
哈哈哈哈髓废,全文終~~
好吧巷懈,不鬧,既然那讓我們來看一下它的實(shí)現(xiàn)慌洪,這個(gè)擴(kuò)展很簡(jiǎn)單砸喻,就是六個(gè)文件,對(duì)應(yīng)RIButtonItem.h蒋譬、RIButtonItem.m UIActionSheet+Blocks.h、UIActionSheet+Blocks.m UIAlertView+Blocks.h愉适、UIAlertView+Blocks.m
RIButtonItem.h
@interface RIButtonItem : NSObject
{
NSString *label;
void (^action)();
}
@property (strong, nonatomic) NSString *label;
@property (copy, nonatomic) void (^action)();
+(id)item;
+(id)itemWithLabel:(NSString *)inLabel;
@end
ok犯助,我們很容易看到,這里面的內(nèi)容和我們前面想的實(shí)現(xiàn)幾乎一樣维咸,用一個(gè)label來存儲(chǔ)標(biāo)題剂买,(^action)()來記錄點(diǎn)擊按鈕的事件。
RIButtonItem.m代碼很簡(jiǎn)單癌蓖,這里不貼了瞬哼。
剩下的兩個(gè)UIAlertView+Blocks UIActionSheet+Blocks 因?yàn)閷?shí)現(xiàn)類似我們來看一個(gè)的實(shí)現(xiàn)
UIAlertView+Blocks.h
#import <UIKit/UIKit.h>
#import "RIButtonItem.h"`
@interface UIAlertView (Blocks) <UIActionSheetDelegate>
-(id)initWithTitle:(NSString *)inTitle message:(NSString *)inMessage cancelButtonItem:(RIButtonItem *)inCancelButtonItem otherButtonItems:(RIButtonItem *)inOtherButtonItems, ... NS_REQUIRES_NIL_TERMINATION; //1
- (NSInteger)addButtonItem:(RIButtonItem *)item; //2
@end
1.我們可以看到初始化方法幾乎和UIAlertView 初始化一樣,只是用RIButtonItem來代替原來的按鈕標(biāo)題租副,用RIButtonItem把a(bǔ)ction帶上就省略了原來的delegate方法
2.這個(gè)方法則對(duì)應(yīng)了 addButtonWithTitle 方法
重點(diǎn)來了坐慰,來看UIAlertView+Blocks.m的實(shí)現(xiàn)
#import "UIAlertView+Blocks.h"
#import <objc/runtime.h>
static NSString *RI_BUTTON_ASS_KEY = @"com.random-ideas.BUTTONS";
@implementation UIAlertView (Blocks)
-(id)initWithTitle:(NSString *)inTitle message:(NSString *)inMessage cancelButtonItem:(RIButtonItem *)inCancelButtonItem otherButtonItems:(RIButtonItem *)inOtherButtonItems, ...
{
if((self = [self initWithTitle:inTitle message:inMessage delegate:self cancelButtonTitle:inCancelButtonItem.label otherButtonTitles:nil]))
{
NSMutableArray *buttonsArray = [NSMutableArray array];
RIButtonItem *eachItem;
va_list argumentList; //1
if (inOtherButtonItems)
{
[buttonsArray addObject: inOtherButtonItems];
va_start(argumentList, inOtherButtonItems); //2
while((eachItem = va_arg(argumentList, RIButtonItem *))) //3
{
[buttonsArray addObject: eachItem];
}
va_end(argumentList); //4
}
for(RIButtonItem *item in buttonsArray)
{
[self addButtonWithTitle:item.label];
}
if(inCancelButtonItem)
[buttonsArray insertObject:inCancelButtonItem atIndex:0];
objc_setAssociatedObject(self, (const void *)RI_BUTTON_ASS_KEY, buttonsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC); //5
[self setDelegate:self];
}
return self;
}
- (NSInteger)addButtonItem:(RIButtonItem *)item
{
NSMutableArray *buttonsArray = objc_getAssociatedObject(self, (const void *)RI_BUTTON_ASS_KEY);
NSInteger buttonIndex = [self addButtonWithTitle:item.label];
[buttonsArray addObject:item];
return buttonIndex;
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// If the button index is -1 it means we were dismissed with no selection
if (buttonIndex >= 0)
{
NSArray *buttonsArray = objc_getAssociatedObject(self, (const void *)RI_BUTTON_ASS_KEY); //6
RIButtonItem *item = [buttonsArray objectAtIndex:buttonIndex];
if(item.action)
item.action();
}
objc_setAssociatedObject(self, (const void *)RI_BUTTON_ASS_KEY, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); //7
}
@end
- va_list 是ios實(shí)現(xiàn)傳遞不定長(zhǎng)的多個(gè)參數(shù)的方法時(shí)所使用的
- 然后用va_start初始化剛定義的va_list變量
- 然后用va_arg返回可變的參數(shù),va_arg的第二個(gè)參數(shù)是你要返回的參數(shù)的類型.如果函數(shù)有多個(gè)可變參數(shù)的用僧,依次調(diào)用va_arg獲取各個(gè)參數(shù)结胀;
下面就是如果還有其他的buttonItem就把它加到buttonsArray - 最后用va_end宏結(jié)束可變參數(shù)的獲取赞咙。
- 因?yàn)樵赾ategory里面不能添加成員變量,所以用objc_setAssociatedObject和objc_getAssociatedObject來變相的添加buttonArray方便下面delegate的時(shí)候取出buttonArray里的action
- 取出buttonArray糟港,使用block來實(shí)現(xiàn)回調(diào)方法攀操。
- set nil;
代碼分析差不多,還學(xué)習(xí)了va_list 以后也能方便的使用這兩個(gè)彈出框了秸抚。
上一個(gè)使用例子
敲下一塊代碼就出現(xiàn)了下面的彈框速和,很方便是不是。