封装iOS系统的弹出对话框

作者: 李贤立 | 来源:发表于2018-01-18 11:31 被阅读274次

实际开发中,软件和用户的对话非常普遍。对话框如何定义,每个开发人员的思路不尽相同,不过它本身的确就很简单,一个View加上几个按钮就行了,想必有不少程序员是自定义的来做,很方便控制。固然是方便展示大体的风格了,但是往往在细节上处理不好,比如轻微的动画效果和阴影效果,边框的圆角的设置,这些细节没有处理好,很容易影响用户的友好体验。当然也有人直接使用第三方框架了。我在这里介绍的是调用苹果系统的那些弹框,本人很喜欢这种效果。根据实际场景需求,我封装了十一种对话框。如下:

/**
 *  系统弹框类型
 */
typedef NS_ENUM(NSInteger, TYZSystemDialogType) {
    /**显示确认和取消*/
    SystemDialogType_Default = 0,
    /**显示确认和取消,着重确认*/
    SystemDialogType_Destructive_Left = 1,
    /**显示确认和取消,着重取消*/
    SystemDialogType_Destructive_Right = 2,
    /**只显示确认*/
    SystemDialogType_OneSure = 3,
    /**只显示确认,着重确认*/
    SystemDialogType_Destructive_Center = 4,
    
    /**显示多行(最多支持6个选项)*/
    SystemDialogType_More = 5,
    
    /**自定义选择项(同默认效果)*/
    SystemDialogType_Custem_Default = 6,
    /**自定义选择项(同1,左边着重)*/
    SystemDialogType_Custem_Destructive_Left = 7,
    /**自定义选择项(同2,右边着重)*/
    SystemDialogType_Custem_Destructive_Right = 8,
    /**自定义选择项(同3,只显示一个)*/
    SystemDialogType_Custem_OneSure = 9,
    /**自定义选择项(同4,一个也着重)*/
    SystemDialogType_Custem_Destructive_Center = 10
};

首先新建类,需是继承自原生的对话框控制器。
@interface TYZSystemDialog : UIAlertController
iOS系统的对话框,本质上是moda出来对话框控制器,所以它必须要的参数就是当前的控制器!如果是在控制器内弹出对话框,一切都好说,但是经过MVC处理后以及深层次的网络请求封装,对话框的弹出很可能不在控制器里,甚至都不能确定到底是哪个控制器界面需要调用。所以一开始需要解决获取当前控制器的事。

#pragma mark - 获取当前窗口的控制器
+ (UIViewController *)getCurrentViewController {
    UIViewController *ctrl = nil;
    UIApplication *app = [UIApplication sharedApplication];
    if (!ctrl) {
        ctrl = app.keyWindow.rootViewController;
    }
    if (!ctrl) {
        ctrl = [app.windows.firstObject rootViewController];
    }
    if (!ctrl) {
        ctrl = [self viewController];
    }
    if (!ctrl) {
        return nil;
    }
    
    while (!ctrl.view.window && ctrl.presentedViewController) {
        ctrl = ctrl.presentedViewController;
    }
    if (!ctrl.view.window) {
        return nil;
    }
    return ctrl;
}
+ (UIViewController *)viewController {
    UIViewController *currentViewController = nil;
    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    if ([window subviews].count == 0) return nil;
    if (window.windowLevel != UIWindowLevelNormal) {
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for (UIWindow * subWindow in windows) {
            if (subWindow.windowLevel == UIWindowLevelNormal) {
                window = subWindow;
                break;
            }
        }
    }
    UIView *frontView = [[window subviews] objectAtIndex:0];
    id nextResponder = [frontView nextResponder];
    if ([nextResponder isKindOfClass:[UIViewController class]]) {
        currentViewController = nextResponder;
    } else {
        currentViewController = window.rootViewController;
    }
    return currentViewController;
}

然后针对十一种对话框在不同需求下进行封装,每种情况分别对应了两个方法,一个是直接传入当前控制器的,一个是通过上述方法自动获取当前控制器的。均采用类方法直接调用,一行代码实现效果,非常方便。

/**
 *  创建系统弹框
 *  默认悬浮中间,显示确认和取消
 *  @pram title      标题
 *  @pram complement 点击确认的回调
 */
+ (instancetype)dialogWithTitle:(NSString *)title complement:(void(^)(void))complement {
    return [self dialogWithViewController:[self getCurrentViewController] title:title complement:complement];
}
+ (instancetype)dialogWithViewController:(UIViewController *)viewController title:(NSString *)title complement:(void(^)(void))complement {
    return [self dialogWithViewController:viewController title:title dialogType:SystemDialogType_Default complement:complement];
}
/**
 *  创建中间悬浮的系统弹框的类型
 *
 *  @pram title      标题
 *  @pram dialogType 弹框类型(只对前五种有效)
 *  @pram complement 点击确认的回调
 */
+ (instancetype)dialogWithTitle:(NSString *)title dialogType:(TYZSystemDialogType)dialogType complement:(void(^)(void))complement {
    return [self dialogWithViewController:[self getCurrentViewController] title:title dialogType:dialogType complement:complement];
}
+ (instancetype)dialogWithViewController:(UIViewController *)viewController title:(NSString *)title dialogType:(TYZSystemDialogType)dialogType complement:(void(^)(void))complement {
    TYZSystemDialog *dialog = [TYZSystemDialog alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
    if (dialogType == SystemDialogType_Default) {
        [dialog addAction:[self creatActionWithTitle:[@"确认" S] complement:complement]];
        [dialog addAction:[self creatActionWithTitle:[@"取消" S] complement:nil]];
    } else if (dialogType == SystemDialogType_OneSure) {
        [dialog addAction:[self creatActionWithTitle:[@"确认" S] complement:complement]];
    } else if (dialogType == SystemDialogType_Destructive_Center) {
        [dialog addAction:[self creatActionWithTitle:[@"确认" S] style:UIAlertActionStyleDestructive complement:complement]];
    } else if (dialogType == SystemDialogType_Destructive_Left) {
        [dialog addAction:[self creatActionWithTitle:[@"确认" S] style:UIAlertActionStyleDestructive complement:complement]];
        [dialog addAction:[self creatActionWithTitle:[@"取消" S] complement:nil]];
    } else if (dialogType == SystemDialogType_Destructive_Left) {
        [dialog addAction:[self creatActionWithTitle:[@"确认" S] complement:complement]];
        [dialog addAction:[self creatActionWithTitle:[@"取消" S] style:UIAlertActionStyleDestructive complement:nil]];
    }
    [viewController presentViewController:dialog animated:YES completion:nil];
    return dialog;
}
/**
 *  根据传入的数据创建底部弹出的系统弹框的类型 点击选择第几个选项的回调
 *
 *  @pram title      标题
 *  @pram showData   显示的数据,弹框类型只是第六种,从底部弹出
 *  @pram complement 点击确认的回调
 */
+ (instancetype)dialogWithTitle:(NSString *)title showData:(NSArray<NSString *> *)showData complement:(void(^)(NSInteger index))complement {
    return [self dialogWithViewController:[self getCurrentViewController] title:title showData:showData complement:complement];
}
+ (instancetype)dialogWithViewController:(UIViewController *)viewController title:(NSString *)title showData:(NSArray<NSString *> *)showData complement:(void(^)(NSInteger index))complement {
    TYZSystemDialog *dialog = [TYZSystemDialog alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet];
    NSInteger number = showData.count > MostSystemDialogNumber ? MostSystemDialogNumber : showData.count;
    for (NSInteger i = 0; i < number; i ++) {
        [dialog addAction:[self creatActionWithTitle:showData[i] complement:^{
            if (complement) {
                complement(i);
            }
        }]];
    }
    [dialog addAction:[self creatActionWithTitle:[@"取消" S] style:UIAlertActionStyleCancel complement:nil]];
    [viewController presentViewController:dialog animated:YES completion:nil];
    return dialog;
}
/**
 *  根据自定义传入的中间弹框选择的数据创建系统弹框的类型 点击选择第几个选项的回调
 *
 *  @pram title      标题
 *  @pram showData   显示的数据
 *  @pram dialogType 弹框类型(只对后五种有效)
 *  @pram complement 点击确认的回调
 */
+ (instancetype)dialogWithTitle:(NSString *)title showData:(NSArray<NSString *> *)showData dialogType:(TYZSystemDialogType)dialogType complement:(void(^)(NSInteger index))complement {
    return [self dialogWithViewController:[self getCurrentViewController] title:title showData:showData dialogType:dialogType complement:complement];
}
+ (instancetype)dialogWithViewController:(UIViewController *)viewController title:(NSString *)title showData:(NSArray<NSString *> *)showData dialogType:(TYZSystemDialogType)dialogType complement:(void(^)(NSInteger index))complement {
    TYZSystemDialog *dialog = [TYZSystemDialog alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
    if (showData.count == 1) {
        if (dialogType == SystemDialogType_Custem_OneSure) {
            [dialog addAction:[self creatActionWithTitle:showData.firstObject complement:^{
                if (complement) {
                    complement(0);
                }
            }]];
        } else if (dialogType == SystemDialogType_Custem_Destructive_Center) {
            [dialog addAction:[self creatActionWithTitle:showData.firstObject style:UIAlertActionStyleDestructive complement:^{
                if (complement) {
                    complement(0);
                }
            }]];
        }
    } else if (showData.count == 2) {
        if (dialogType == SystemDialogType_Custem_Default) {
            [dialog addAction:[self creatActionWithTitle:showData.firstObject complement:^{
                if (complement) {
                    complement(0);
                }
            }]];
            [dialog addAction:[self creatActionWithTitle:showData.lastObject complement:^{
                if (complement) {
                    complement(1);
                }
            }]];
        } else if (dialogType == SystemDialogType_Custem_Destructive_Left) {
            [dialog addAction:[self creatActionWithTitle:showData.firstObject style:UIAlertActionStyleDestructive complement:^{
                if (complement) {
                    complement(0);
                }
            }]];
            [dialog addAction:[self creatActionWithTitle:showData.lastObject style:UIAlertActionStyleCancel complement:^{
                if (complement) {
                    complement(1);
                }
            }]];
        } else if (dialogType == SystemDialogType_Custem_Destructive_Right) {
            [dialog addAction:[self creatActionWithTitle:showData.firstObject style:UIAlertActionStyleCancel complement:^{
                if (complement) {
                    complement(0);
                }
            }]];
            [dialog addAction:[self creatActionWithTitle:showData.lastObject style:UIAlertActionStyleDestructive complement:^{
                if (complement) {
                    complement(1);
                }
            }]];
        }
    }
    [viewController presentViewController:dialog animated:YES completion:nil];
    return dialog;
}
/**
 *  创建带输入框的非密码形式的弹框
 *
 *  @pram title         标题
 *  @pram placeholder   占位文本
 *  @pram textLength    输入字数上限
 *  @pram complement    点击确认的回调
 */
+ (instancetype)dialogWithTitle:(NSString *)title placeholder:(NSString *)placeholder textLenth:(NSInteger)textLength complement:(void(^)(NSString *text))complement {
    return [self dialogWithViewController:[self getCurrentViewController] title:title placeholder:placeholder textLenth:textLength complement:complement];
}
+ (instancetype)dialogWithViewController:(UIViewController *)viewController title:(NSString *)title placeholder:(NSString *)placeholder textLenth:(NSInteger)textLength complement:(void(^)(NSString *text))complement {
    return [self dialogWithViewController:viewController title:title placeholder:placeholder textLenth:textLength secureTextEntry:NO complement:complement];
}
/**
 *  创建带输入框的弹框
 *
 *  @pram title             标题
 *  @pram placeholder       占位文本
 *  @pram textLength        输入字数上限
 *  @pram secureTextEntry   是否是密码模式
 *  @pram complement        点击确认的回调
 */
+ (instancetype)dialogWithTitle:(NSString *)title placeholder:(NSString *)placeholder textLenth:(NSInteger)textLength secureTextEntry:(BOOL)secureTextEntry complement:(void(^)(NSString *text))complement {
    return [self dialogWithViewController:[self getCurrentViewController] title:title placeholder:placeholder textLenth:textLength secureTextEntry:secureTextEntry complement:complement];
}
+ (instancetype)dialogWithViewController:(UIViewController *)viewController title:(NSString *)title placeholder:(NSString *)placeholder textLenth:(NSInteger)textLength secureTextEntry:(BOOL)secureTextEntry complement:(void(^)(NSString *text))complement {
    TYZSystemDialog *dialog = [TYZSystemDialog alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
    [dialog addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = placeholder;
        textField.secureTextEntry = secureTextEntry;
        textField.clearButtonMode = UITextFieldViewModeWhileEditing;
    }];
    UIAlertAction *action = [UIAlertAction actionWithTitle:[@"确认" S] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        if (complement) {
            complement(dialog.textFields.firstObject.text);
        }
    }];
    [dialog addAction:action];
    [dialog addAction:[self creatActionWithTitle:[@"取消" S] complement:nil]];
    [viewController presentViewController:dialog animated:YES completion:nil];
    return dialog;
}
/**
 *  创建默认的按钮
 *
 *  @pram title        按钮标题
 *  @pram complement   点击确认的回调
 */
+ (UIAlertAction *)creatActionWithTitle:(NSString *)title complement:(void(^)(void))complement {
    return [self creatActionWithTitle:title style:UIAlertActionStyleDefault complement:complement];
}
/**
 *  创建默认的按钮
 *
 *  @pram title        按钮标题
 *  @pram style        按钮类型
 *  @pram complement   点击确认的回调
 */
+ (UIAlertAction *)creatActionWithTitle:(NSString *)title style:(UIAlertActionStyle)style complement:(void(^)(void))complement {
    UIAlertAction *action = [UIAlertAction actionWithTitle:title style:style handler:^(UIAlertAction * _Nonnull action) {
        if (complement) {
            complement();
        }
    }];
    return action;
}

注意:如果有重新获取了window,在上面添加了一层,那么这个对话框不会出现在最前面了。我试着将moda出来的对话框控制器的View提到最前面,但是失败。这种矛盾的出现只好规避之。

相关文章

网友评论

    本文标题:封装iOS系统的弹出对话框

    本文链接:https://www.haomeiwen.com/subject/ygwioxtx.html