1. 程式人生 > >黑馬程式設計師--分享自定義UIActionSheet

黑馬程式設計師--分享自定義UIActionSheet

學完黑馬和基礎視訊許久, 最近牛刀小試, 發現在開發過程中很多UI介面都跟IOS原生的不一樣, 加上要考慮4寸與3.5寸, 許多UI都要自定義, 在處分享一下自定義UIActionSheet的實現, 希望跟大家交流學習.

首先講一下我的實現思路, 我是使用一個UIView來完成ActionSheet的介面, 之後在需要彈出的時候, 通過獲取當前keyWindow, 然後新增我的UIView起到一個模仿UIActionSheet的效果, 這裡我開放了比較多的屬性, 使ActionSheet的介面效果可以調整. 另外命名還是比較容易看懂的, 就不加太多註釋了,  自己添加了一些簡單的動畫效果,  介面佈局的, 我用一些簡單的計算去得出每一個控制元件的frame, 支援多個OtherButton的新增. 本人小菜鳥一個, 希望大神能指定一下其中的錯誤. 方便我改進. 

標頭檔案:  

#import <UIKit/UIKit.h>
@class SettingActionSheet;

@protocol SettingActionSheetDelegate <NSObject>

- (void)settingActionSheet:(SettingActionSheet *)actionSheet ClickButtonAtIndex:(NSInteger)buttonIndex;

@end

@interface SettingActionSheet : UIView

@property (weak, nonatomic) id<SettingActionSheetDelegate> delegate;

@property (weak, nonatomic) UIImageView *backgroundView;
@property (weak, nonatomic) UILabel *titleLabel;
@property (strong, nonatomic) UIImage *cancelButtonImage;
@property (strong, nonatomic) UIImage *cancelButtonHighLightImage;
@property (strong, nonatomic) UIImage *otherButtonImage;
@property (strong, nonatomic) UIImage *otherButtonHighLightImage;

- (instancetype)initWithTitle:(NSString *)title Delegate:(id<SettingActionSheetDelegate>)delegate cancelButtonTitle:(NSString *)cancelButtonTitle ButtonTitles:(NSArray *)titles;

- (void)show;

@end

下面是.m檔案的實現

#import "SettingActionSheet.h"

#define TitleLabelTopSpace 0    //標題欄頂部空隙
#define TitleLabelWidth 320
#define TitleLabelHeight 60

#define ButtonHeight 40
#define ButtonWidth 280
#define ButtonSpace 10             // otherButton之間的距離

#define CancelButtonHeight 40

#define CancelButtonSpace 20      //Cancel按鈕與Other按鈕之間的間距

#define LucencyViewAlpha 0.2

@interface SettingActionSheet()

@property (weak, nonatomic) UIView *lucencyView;
@property (copy, nonatomic) NSString *title;
@property (copy, nonatomic) NSString *cancelButtonTitle;
@property (strong, nonatomic) NSArray *otherButtontitles;

@end

@implementation SettingActionSheet

- (id)initWithTitle:(NSString *)title Delegate:(id<SettingActionSheetDelegate>)delegate cancelButtonTitle:(NSString *)cancelButtonTitle ButtonTitles:(NSArray *)titles {
    
    self = [super initWithFrame:[UIScreen mainScreen].bounds];
    
    if (self) {
        // 使ActionSheet的View全透明
        [self setBackgroundColor:[UIColor clearColor]];

        self.title = title;
        self.cancelButtonTitle = cancelButtonTitle;
        self.delegate = delegate;
        self.otherButtontitles = titles;
}
    
    return self;
}

#pragma mark - 載入所有子檢視
- (void)initSubViews {
    // 計算背景檢視高度
    NSInteger backgroundHeight = TitleLabelTopSpace + TitleLabelHeight + self.otherButtontitles.count * (ButtonHeight + ButtonSpace) + CancelButtonSpace + CancelButtonHeight + CancelButtonSpace;
    
    // 頂部半透明檢視
    UIControl *lucencyView = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height - backgroundHeight)];
    [lucencyView setBackgroundColor:[UIColor lightGrayColor]];
    [lucencyView setAlpha:0];
    [lucencyView addTarget:self action:@selector(dismissActionSheet) forControlEvents:UIControlEventTouchDown];
    self.lucencyView = lucencyView;
    [self addSubview:lucencyView];
    
    // 底部背景檢視
    UIImageView *bgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.frame.size.height - backgroundHeight, self.frame.size.width, backgroundHeight)];
    [bgView setBackgroundColor:[UIColor blackColor]];
    [bgView setUserInteractionEnabled:YES];
    
    self.backgroundView = bgView;
    [self addSubview:bgView];
    
    // 標題
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake( (320 - TitleLabelWidth) / 2,  TitleLabelTopSpace, TitleLabelWidth, TitleLabelHeight)];
    [titleLabel setBackgroundColor:[UIColor clearColor]];
    [titleLabel setFont:[UIFont systemFontOfSize:17]];
    [titleLabel setTextColor:[UIColor whiteColor]];
    [titleLabel setTextAlignment:NSTextAlignmentCenter];
    titleLabel.text = self.title;
    
    self.titleLabel = titleLabel;
    [self.backgroundView addSubview:titleLabel];
    
    // 其它按鈕
    CGFloat x = (self.frame.size.width - ButtonWidth) / 2;
    CGFloat otherY = TitleLabelTopSpace + TitleLabelHeight;
    
    NSInteger i = 0;
    for (NSString *title in self.otherButtontitles) {
        [self createButtonWithFrame:CGRectMake(x, otherY, ButtonWidth, ButtonHeight) Title:title Index:i];
        
        otherY += (ButtonSpace + ButtonHeight);
        i++;
    }
    
    // 取消按鈕
    CGFloat y = TitleLabelTopSpace + TitleLabelHeight + (ButtonHeight + ButtonSpace) * self.otherButtontitles.count + CancelButtonSpace;
    
    [self createCancelButtonWithFrame:CGRectMake(x, y, ButtonWidth, CancelButtonHeight) Title:self.cancelButtonTitle];

}


#pragma mark - 建立OtherButton
- (void)createButtonWithFrame:(CGRect)buttonFrame Title:(NSString *)title Index:(NSInteger)index {
    UIButton *button = [[UIButton alloc] initWithFrame:buttonFrame];
    [button setTitle:title forState:UIControlStateNormal];
    // 使用tag記錄index
    button.tag = index;
    
    // 使用設定的背景
    if (self.otherButtonImage) {
        [button setBackgroundImage:self.otherButtonImage forState:UIControlStateNormal];
    }
    if (self.otherButtonHighLightImage) {
        [button setBackgroundImage:self.otherButtonHighLightImage forState:UIControlStateHighlighted];
    }
    
    // 新增響應事件
    [button addTarget:self action:@selector(clickButtonAtIndex:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.backgroundView addSubview:button];
}

#pragma mark - OtherButton監聽事件
- (void)clickButtonAtIndex:(UIButton *)button{
    // 執行代理實現的方法
    [self.delegate settingActionSheet:self ClickButtonAtIndex:button.tag];
    
    [self dismissActionSheet];
}

#pragma mark - 建立cancelButton
- (void)createCancelButtonWithFrame:(CGRect)frame Title:(NSString *)title {
    UIButton *cancelButton = [[UIButton alloc] initWithFrame:frame];
    [cancelButton setTitle:title forState:UIControlStateNormal];
    
    if (self.cancelButtonImage) {
        [cancelButton setBackgroundImage:self.cancelButtonImage forState:UIControlStateNormal];
    }
    if (self.cancelButtonHighLightImage) {
        [cancelButton setBackgroundImage:self.cancelButtonHighLightImage forState:UIControlStateHighlighted];
    }
    
    // 響應事件
    [cancelButton addTarget:self action:@selector(dismissActionSheet) forControlEvents:UIControlEventTouchUpInside];
    
    [self.backgroundView addSubview:cancelButton];
}

#pragma mark 顯示ActionSheet
- (void)show {
    // 載入子檢視
    [self initSubViews];
    
    // 將ActionSheet新增到主螢幕上
    UIView *windowView = [UIApplication sharedApplication].keyWindow;
    [windowView addSubview:self];

    // 移出螢幕
    CGRect temp = self.backgroundView.frame;
    CGRect rect = CGRectMake(0, [UIScreen mainScreen].bounds.size.height, temp.size.width, temp.size.height);
    [self.backgroundView setFrame:rect];

    // 稱回螢幕
    [UIView animateWithDuration:LucencyViewAlpha animations:^{
        self.backgroundView.frame = temp;
        [self.lucencyView setAlpha:LucencyViewAlpha];
    }];
}

#pragma mark 退出ActionSheet
- (void)dismissActionSheet {
    [self.lucencyView setAlpha:0];
    
    [UIView animateWithDuration:LucencyViewAlpha animations:^{
        self.backgroundView.frame = CGRectMake(0, self.frame.size.height, self.backgroundView.frame.size.width, self.backgroundView.frame.size.height);
    } completion:^(BOOL finished) {
        [self removeFromSuperview];
    }];
}


@end

最後是實現程式碼:
 SettingActionSheet *actionSheet = [[SettingActionSheet alloc] initWithTitle:@"恢復預設設定 ?" Delegate:self cancelButtonTitle:@"取消" ButtonTitles:@[@"確定"]];
        
        actionSheet.cancelButtonImage = [UIImage imageNamed:@"shipin_btn_anniu2_normal"];
        actionSheet.cancelButtonHighLightImage = [UIImage imageNamed:@"shipin_btn_anniu2_press"];
        actionSheet.otherButtonImage = [UIImage imageNamed:@"shipin_btn_anniu1_normal"];
        actionSheet.otherButtonHighLightImage = [UIImage imageNamed:@"shipin_btn_anniu1_press"];
        
        [actionSheet show];
效果圖下如: 按鈕的圖片背景可以自定義.