仿写微信的AlertActionSheet

本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含Java, 数据结构与算法, iOS, 安卓, python, flutter等等, 如有需要, 联系微信tsaievan.

现在大多数APP都不再使用系统原生的AlertController了, 而是自定义AlertView控件, 比如.

系统的AlertActionSheet是这样的:
仿写微信的AlertActionSheet_第1张图片
WechatIMG3.jpeg
但比如微信, 自定义的AlertActionSheet是这样的:
仿写微信的AlertActionSheet_第2张图片
WechatIMG4.jpeg

那么我们如何来仿写一个类似于微信这样的AlertActionSheet呢?

仿写微信的AlertActionSheet_第3张图片
自定义AlertActionSheet的分析

如上图所示, 红色部分是整个的AlertActionSheet,它和屏幕一样大, 当我点击某个按钮弹出AlertActionSheet的时候, 会出现蒙版的效果, 绿色的部分是AlertActionSheet的contentView, 蓝色部分是各个按钮. 它们的frame值大小也决定了contentView的frame值.

基本思路是先创建各个button(不包括cancelButton),然后将这些button组成一个数组, 作为参数传入到AlertActionSheet的初始化方法中, 然后在layoutSubviews 方法中对contentView, 以及contentView的子控件进行布局

typedef void(^YFActionSheetHandler)(YFActionSheet *actionSheet, YFActionButton *actionButton);
/**
 初始化方法:不带图片,按钮标题颜色黑色

 @param title 按钮标题
 @param handler 按钮点击处理事件
 @return 返回一个自定义的actionButton
 */
- (instancetype)initWithTitle:(NSString *)title handler:(YFActionSheetHandler)handler;

初始化button成功之后, 将这些button作为数组传入AlertActionSheet的初始化方法中

/**
 初始化方法(不包含标题和副标题)

 @param actionButtons ActionSheet的按钮数组
 @return 返回一个自定义的ActionSheet
 */
- (instancetype)initWithActionButtons:(NSArray *)actionButtons;

初始化方法的实现是这样的:

- (instancetype)initWithTitle:(NSString *)title subtitle:(NSString *)subtitle actionButtons:(NSArray *)actionButtons {
    if (self = [super init]) {
        _title = title;
        _subtitle = subtitle;
        self.actionButtons = actionButtons.mutableCopy;
        [self commonInit];
    }
    return self;
}

- (instancetype)initWithActionButtons:(NSArray *)actionButtons {
    return [self initWithTitle:nil subtitle:nil actionButtons:actionButtons];
}

设置UI

- (void)commonInit {
    // 这个步骤相当于设置蒙版
    self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.1];
    [self addSubview:self.contentView];
    [self.contentView addSubview:self.cancelButton];
    [self addGestureRecognizer:self.tapGesture];
    if (!self.actionButtons) {
        return;
    }
    
    // 设置一些基本的属性
    _cancelButtonHeight = 44;
    _cancelButtonTopOrBottomMargin = 6;
    _leftOrRightMargin = 20;
    _seperatorHeight = 0.5;
    [self setupHeadView];
    
    [self.actionButtons enumerateObjectsUsingBlock:^(YFActionButton * _Nonnull actionButton, NSUInteger idx, BOOL * _Nonnull stop) {
        [actionButton addTarget:self action:@selector(actionButtonDidClickAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.contentView addSubview:actionButton];
    }];
}

- (void)setupHeadView {
    CGFloat labelMaxWidth = [UIScreen mainScreen].bounds.size.width - 2 * _leftOrRightMargin;
    if (_title) { // 有标题才设置标题
        self.titleLabel.text = _title;
        [self.headView addSubview:self.titleLabel];
        _titleHeight = [_title boundingRectWithSize:CGSizeMake(labelMaxWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.titleLabel.font} context:nil].size.height;
        _headViewHeight += (YFTopMargin + _titleHeight);
    }
    
    if (_subtitle) {
        self.subtitleLabel.text = _subtitle;
        [self.headView addSubview:self.titleLabel];
        _subtitleHeight = [_subtitle boundingRectWithSize:CGSizeMake(labelMaxWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName :self.subtitleLabel.font} context:nil].size.height;
        _headViewHeight += (YFTopMargin + _subtitleHeight);
    }
    
    if (_headView) {
        [self.contentView addSubview:_headView];
    }
    
    _headViewHeight = MAX(0, _headViewHeight);
}

在layoutSubviews方法中, 我需要设置headView的frame值, 如果有headView的话, 还需要设置各个button的frame值

- (void)layoutSubviews {
    [super layoutSubviews];
    CGFloat contentViewWidth = kYFActionSheetWidth - 2 *_leftOrRightMargin;
    if (_headView) {
        self.headView.frame = CGRectMake(0, 0, contentViewWidth, _headViewHeight);
        if (_titleLabel && _subtitleLabel) {
            self.titleLabel.frame = CGRectMake(0, YFTopMargin, contentViewWidth, _titleHeight);
            self.subtitleLabel.frame = CGRectMake(0, CGRectGetMaxY(_titleLabel.frame) + YFTopMargin / 2, contentViewWidth, _subtitleHeight);
        }else if (_titleLabel) {
            self.titleLabel.frame = self.headView.bounds;
        }else if (_subtitleLabel) {
            self.subtitleLabel.frame = self.headView.bounds;
        }
    }
    
    CGFloat buttonY = _headViewHeight;
    for (NSUInteger i = 0; i < self.actionButtons.count; i++) {
        YFActionButton *actionButton = self.actionButtons[i];
        actionButton.frame = CGRectMake(0, buttonY, contentViewWidth, actionButton.buttonHeight);
        buttonY += _seperatorHeight + actionButton.buttonHeight;
        self.cancelButton.frame = CGRectMake(0, buttonY + _cancelButtonTopOrBottomMargin, contentViewWidth, _cancelButtonHeight);
    }
}

那么在使用中, 我需要设置alertActionSheet的出现和消失, 所以我需要暴露两个接口供外界使用, 其实hide接口不需要暴露, 因为我对整个alertActionSheet添加了手势, 当手势触发时, 自动隐藏contentView.

- (void)switchToHideState {
    self.alpha = 0;
    self.contentView.frame = CGRectMake(_leftOrRightMargin, kYFActionSheetHeight, kYFActionSheetWidth - 2 * _leftOrRightMargin, _contentViewHeight);
}

- (void)switchToShowState {
    self.alpha = 1;
    self.contentView.frame = CGRectMake(_leftOrRightMargin, (kYFActionSheetHeight - _contentViewHeight), kYFActionSheetWidth - 2 * _leftOrRightMargin, _contentViewHeight);
}

- (void)show {
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    self.frame = window.bounds;
    [window addSubview:self];
    [self getContentViewHeight];
    [self switchToHideState];
    WEAK_SELF
    [UIView animateWithDuration:0.25 animations:^{
        [weakSelf switchToShowState];
    } completion:nil];
}

- (void)hide {
    WEAK_SELF
    [UIView animateWithDuration:0.25 animations:^{
        [weakSelf switchToHideState];
    } completion:^(BOOL finished) {
        if (finished) {
            [weakSelf removeFromSuperview];
        }
    }];
}

看一下实现效果, 是不是和微信的很像呢?

实现效果

源码链接

PS. 本人有若干成套学习视频, 包含Java, 数据结构与算法, iOS, 安卓, python, flutter等等, 如有需要, 联系微信tsaievan.

你可能感兴趣的:(仿写微信的AlertActionSheet)