iOS:简单使用UIAlertVIew和UIActionSheet

做iOS开发的同学想必都用过UIAlertVIew或者UIActionSheet。UIAlertVIew 可以弹出一个出现在屏幕中间的提示视图,给用户展示信息,并让用户自己选择操作,UIActionSheet可以弹出一个选择列表,让用户选择列表中的某一项操作。使用UIAlertVIew和UIActionSheet非常简单,以下是一个简单的示例代码:

//UIAlertView
- (void)someButtonClicked {//初始化AlertView  
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AlertViewTest"  
                                               message:@"message"  
                                              delegate:self  
                                     cancelButtonTitle:@"Cancel"  
                                     otherButtonTitles:@"OtherBtn",nil]; 
[alert show]; 
}
//按钮点击事件的代理
- (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);
}

虽然使用已经算是比较简单了,但我觉得还是比较麻烦他们都需要设置delegate来获得用户选择的结果。这么小的界面,把调用显示和回调方法分开写在2个方法中,使得原本简单的逻辑复杂了。虽然也不会复杂到哪儿去,但是每次调用他们就需要另外写一个delegate回调方法,觉得还是比较麻烦。
于是便产生了,分别给它们写一个category 用来对原生的ui再做一层简单地封装。(一些复杂的暂不考虑)然后用block来做回调,这样子,一块简单地东西就不用分开在两个地方了(才不要拆散它们)。
我们先简单地分析 UIAlertVIew 和 UIActionSheet,其实他们需要的东西,并不多,只是按钮的事件和对应的action,UIAlertVIew还多了一个Title和message,但这些在初始化里面就已经初始化好了。造成他们分离的主要原因还是action和init分离了。所以要完成这个不让他们分离的目的,实现这个category 首先我们需要一个 button的模型来封装 button的title 和 对应的事件,事件用block来代替代理(这样就可以让他们在一起了)。
于是我顺手在github上搜索了一下,发现了这个
https://github.com/jivadevoe/UIAlertView-Blocks
哈哈哈哈,全文终~~
好吧,不闹,既然那让我们来看一下它的实现,这个扩展很简单,就是六个文件,对应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,我们很容易看到,这里面的内容和我们前面想的实现几乎一样,用一个label来存储标题,(^action)()来记录点击按钮的事件。
RIButtonItem.m代码很简单,这里不贴了。

剩下的两个UIAlertView+Blocks UIActionSheet+Blocks 因为实现类似我们来看一个的实现

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来代替原来的按钮标题,用RIButtonItem把action带上就省略了原来的delegate方法
2.这个方法则对应了 addButtonWithTitle 方法

重点来了,来看UIAlertView+Blocks.m的实现

#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
  1. va_list 是ios实现传递不定长的多个参数的方法时所使用的
  2. 然后用va_start初始化刚定义的va_list变量
  3. 然后用va_arg返回可变的参数,va_arg的第二个参数是你要返回的参数的类型.如果函数有多个可变参数的,依次调用va_arg获取各个参数;
    下面就是如果还有其他的buttonItem就把它加到buttonsArray
  4. 最后用va_end宏结束可变参数的获取。
  5. 因为在category里面不能添加成员变量,所以用objc_setAssociatedObject和objc_getAssociatedObject来变相的添加buttonArray方便下面delegate的时候取出buttonArray里的action
  6. 取出buttonArray,使用block来实现回调方法。
  7. set nil;

代码分析差不多,还学习了va_list 以后也能方便的使用这两个弹出框了。

上一个使用例子


code.png

敲下一块代码就出现了下面的弹框,很方便是不是。

alertView.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容