单军华
2018-07-31 21d3023a9b7b6aff68c1170e345951396b1c6cfd
screendisplay/screendisplay/Classes/Helpers/JXTAlertController.h
New file
@@ -0,0 +1,535 @@
//
//  JXTAlertController.h
//  JXTAlertManager
//
//  Created by JXT on 2016/12/22.
//  Copyright © 2016年 JXT. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
#pragma mark - I.JXTAlertController构造
@class JXTAlertController;
/**
 JXTAlertController: alertAction配置链
 @param title 标题
 @return      JXTAlertController对象
 */
typedef JXTAlertController * _Nonnull (^JXTAlertActionTitle)(NSString *title);
/**
 JXTAlertController: alert按钮执行回调
 @param buttonIndex 按钮index(根据添加action的顺序)
 @param action      UIAlertAction对象
 @param alertSelf   本类对象
 */
typedef void (^JXTAlertActionBlock)(NSInteger buttonIndex, UIAlertAction *action, JXTAlertController *alertSelf);
/**
 JXTAlertController 简介:
 1.针对系统UIAlertController封装,支持iOS8及以上
 2.关于iOS9之后的`preferredAction`属性用法:
 `alertController.preferredAction = alertController.actions[0];`
 效果为将已存在的某个action字体加粗,原cancel样式的加粗字体成为deafult样式,cancel样式的action仍然排列在最下
 总体意义不大,且仅限于`UIAlertControllerStyleAlert`,actionSheet无效,功能略微鸡肋,不再单独封装
 3.关于`addTextFieldWithConfigurationHandler:`方法:
 该方法同样仅限于`UIAlertControllerStyleAlert`使用,使用场景较为局限,推荐直接调用,不再针对封装
 4.关于自定义按钮字体或者颜色,可以利用kvc间接访问这些私有属性,但是不推荐
 `[alertAction setValue:[UIColor grayColor] forKey:@"titleTextColor"]`
 */
NS_CLASS_AVAILABLE_IOS(8_0) @interface JXTAlertController : UIAlertController
/**
 JXTAlertController: 禁用alert弹出动画,默认执行系统的默认弹出动画
 */
- (void)alertAnimateDisabled;
/**
 JXTAlertController: alert弹出后,可配置的回调
 */
@property (nullable, nonatomic, copy) void (^alertDidShown)(void);
/**
 JXTAlertController: alert关闭后,可配置的回调
 */
@property (nullable, nonatomic, copy) void (^alertDidDismiss)(void);
/**
 JXTAlertController: 设置toast模式展示时间:如果alert未添加任何按钮,将会以toast样式展示,这里设置展示时间,默认1s
 */
@property (nonatomic, assign) NSTimeInterval toastStyleDuration; //deafult jxt_alertShowDurationDefault = 1s
/**
 JXTAlertController: 链式构造alert视图按钮,添加一个alertAction按钮,默认样式,参数为标题
 @return JXTAlertController对象
 */
- (JXTAlertActionTitle)addActionDefaultTitle;
/**
 JXTAlertController: 链式构造alert视图按钮,添加一个alertAction按钮,取消样式,参数为标题(warning:一个alert该样式只能添加一次!!!)
 @return JXTAlertController对象
 */
- (JXTAlertActionTitle)addActionCancelTitle;
/**
 JXTAlertController: 链式构造alert视图按钮,添加一个alertAction按钮,警告样式,参数为标题
 @return JXTAlertController对象
 */
- (JXTAlertActionTitle)addActionDestructiveTitle;
@end
#pragma mark - II.UIViewController扩展使用JXTAlertController
/**
 JXTAlertController: alert构造块
 @param alertMaker JXTAlertController配置对象
 */
typedef void(^JXTAlertAppearanceProcess)(JXTAlertController *alertMaker);
@interface UIViewController (JXTAlertController)
/**
 JXTAlertController: show-alert(iOS8)
 @param title             title
 @param message           message
 @param appearanceProcess alert配置过程
 @param actionBlock       alert点击响应回调
 */
- (void)jxt_showAlertWithTitle:(nullable NSString *)title
                       message:(nullable NSString *)message
             appearanceProcess:(JXTAlertAppearanceProcess)appearanceProcess
                  actionsBlock:(nullable JXTAlertActionBlock)actionBlock NS_AVAILABLE_IOS(8_0);
/**
 JXTAlertController: show-actionSheet(iOS8)
 @param title             title
 @param message           message
 @param appearanceProcess actionSheet配置过程
 @param actionBlock       actionSheet点击响应回调
 */
- (void)jxt_showActionSheetWithTitle:(nullable NSString *)title
                             message:(nullable NSString *)message
                   appearanceProcess:(JXTAlertAppearanceProcess)appearanceProcess
                        actionsBlock:(nullable JXTAlertActionBlock)actionBlock NS_AVAILABLE_IOS(8_0);
@end
@interface UIAlertController (LMJ)
/**
 JXTAlertController: show-alert(iOS8)
 @param title             title
 @param message           message
 @param appearanceProcess alert配置过程
 @param actionBlock       alert点击响应回调
 */
+ (void)mj_showAlertWithTitle:(nullable NSString *)title
                       message:(nullable NSString *)message
             appearanceProcess:(JXTAlertAppearanceProcess)appearanceProcess
                  actionsBlock:(nullable JXTAlertActionBlock)actionBlock NS_AVAILABLE_IOS(8_0);
/**
 JXTAlertController: show-actionSheet(iOS8)
 @param title             title
 @param message           message
 @param appearanceProcess actionSheet配置过程
 @param actionBlock       actionSheet点击响应回调
 */
+ (void)mj_showActionSheetWithTitle:(nullable NSString *)title
                             message:(nullable NSString *)message
                   appearanceProcess:(JXTAlertAppearanceProcess)appearanceProcess
                        actionsBlock:(nullable JXTAlertActionBlock)actionBlock NS_AVAILABLE_IOS(8_0);
@end
NS_ASSUME_NONNULL_END
/*
 //
 //  ShowViewController.m
 //  JXTAlertManagerDemo
 //
 //  Created by JXT on 2016/12/21.
 //  Copyright © 2016年 JXT. All rights reserved.
 //
 #import "ShowViewController.h"
 #import "JXTAlertManagerHeader.h"
 static NSString *const cellId = @"CELLID";
 @interface ShowViewController () <UITableViewDataSource, UITableViewDelegate>
 @property (nonatomic, strong) UITableView * tableView;
 @property (nonatomic, strong) NSArray * sectionViewArray;
 @property (nonatomic, strong) NSArray * dataArray;
 @end
 @implementation ShowViewController
 #pragma mark - LifeCycle
 - (void)viewDidLoad
 {
 [super viewDidLoad];
 self.navigationItem.title = @"JXTAlertManager";
 self.dataArray = @[
 @[
 @"1.1.常规两个按钮alert",
 @"1.2.简易调试使用alert,单按钮,标题默认为“确定”",
 @"1.3.不定数量按钮alert",
 @"1.4.无按钮toast样式",
 @"1.5.单文字HUD",
 @"1.6.带indicatorView的HUD",
 @"1.7.带进度条的HUD,成功!",
 @"1.8.带进度条的HUD,失败!",
 ],
 @[
 @"2.1.常规alertController-Alert",
 @"2.2.常规alertController-ActionSheet",
 @"2.3.无按钮alert-toast",
 @"2.4.无按钮actionSheet-toast",
 @"2.5.带输入框的alertController-Alert",
 ]
 ];
 self.sectionViewArray = @[
 [self labelWithText:@"1.AlertView-推荐日常调试使用"],
 [self labelWithText:@"2.AlertController-iOS8"]
 ];
 [self.view addSubview:self.tableView];
 }
 - (void)didReceiveMemoryWarning {
 [super didReceiveMemoryWarning];
 }
 #pragma mark - UI
 - (UILabel *)labelWithText:(NSString *)text
 {
 UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)];
 label.text = text;
 label.font = [UIFont boldSystemFontOfSize:20];
 label.backgroundColor = [[self randomColor] colorWithAlphaComponent:0.5];
 label.textAlignment = NSTextAlignmentCenter;
 return label;
 }
 - (UITableView *)tableView
 {
 if (!_tableView) {
 if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
 self.automaticallyAdjustsScrollViewInsets = NO;
 }
 _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
 _tableView.delegate = self;
 _tableView.dataSource = self;
 _tableView.backgroundColor = [UIColor whiteColor];
 _tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
 _tableView.scrollIndicatorInsets = UIEdgeInsetsMake(64, 0, 0, 0);
 }
 return _tableView;
 }
 #pragma mark - UITableViewDataSource
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
 return self.dataArray.count;
 }
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
 NSArray *sectionArray = self.dataArray[section];
 return sectionArray.count;
 }
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellId];
 if (!cell) {
 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
 }
 cell.backgroundColor = [self randomColor];
 cell.textLabel.text = self.dataArray[indexPath.section][indexPath.row];
 cell.textLabel.numberOfLines = 0;
 return cell;
 }
 //- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
 //{
 //    return @"title";
 //}
 #pragma mark - UITableViewDelegate
 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
 return 70;
 }
 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
 {
 return 25;
 }
 - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
 {
 return 0.01;
 }
 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
 {
 return self.sectionViewArray[section];
 }
 #pragma mark alert使用示例
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
 if (indexPath.section == 0)
 {
 if (indexPath.row == 0)
 {
 //1.
 //            [JXTAlertView showAlertViewWithTitle:@"title" message:@"message" cancelButtonTitle:@"cancel" otherButtonTitle:@"other" cancelButtonBlock:^(NSInteger buttonIndex) {
 //                NSLog(@"cancel");
 //            } otherButtonBlock:^(NSInteger buttonIndex) {
 //                NSLog(@"other");
 //            }];
 //2.
 jxt_showAlertTwoButton(@"常规两个按钮alert", @"支持按钮点击回调,支持C函数快速调用", @"cancel", ^(NSInteger buttonIndex) {
 NSLog(@"cancel");
 }, @"other", ^(NSInteger buttonIndex) {
 NSLog(@"other");
 });
 }
 else if (indexPath.row == 1)
 {
 jxt_showAlertTitle(@"简易调试使用alert,单按钮,标题默认为“确定”");
 }
 else if (indexPath.row == 2)
 {
 [JXTAlertView showAlertViewWithTitle:@"不定数量按钮alert" message:@"支持按钮点击回调,根据按钮index区分响应,有cancel按钮时,cancel的index默认0,无cancel时,按钮index根据添加顺序计算" cancelButtonTitle:@"cancel" buttonIndexBlock:^(NSInteger buttonIndex) {
 if (buttonIndex == 0) {
 NSLog(@"cancel");
 }
 else if (buttonIndex == 1) {
 NSLog(@"按钮1");
 }
 else if (buttonIndex == 2) {
 NSLog(@"按钮2");
 }
 else if (buttonIndex == 3) {
 NSLog(@"按钮3");
 }
 else if (buttonIndex == 4) {
 NSLog(@"按钮4");
 }
 else if (buttonIndex == 5) {
 NSLog(@"按钮5");
 }
 } otherButtonTitles:@"按钮1", @"按钮2", @"按钮3", @"按钮4", @"按钮5", nil];
 }
 else if (indexPath.row == 3)
 {
 //1.
 [JXTAlertView showToastViewWithTitle:@"无按钮toast样式" message:@"可自定义展示延时时间,支持关闭回调" duration:2 dismissCompletion:^(NSInteger buttonIndex) {
 NSLog(@"关闭");
 }];
 //2.
 //            jxt_showToastTitleDismiss(@"无按钮toast样式", 2, ^(NSInteger buttonIndex) {
 //                NSLog(@"关闭");
 //            });
 //3.
 //            jxt_showToastMessage(@"无按钮toast样式", 0);
 }
 else if (indexPath.row == 4)
 {
 //1.
 //            jxt_showTextHUDTitle(@"单文字HUD");
 //2.
 jxt_showTextHUDTitleMessage(@"单文字HUD", @"支持子标题,手动执行关闭,可改变显示状态");
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 jxt_dismissHUD();
 });
 }
 else if (indexPath.row == 5)
 {
 jxt_showLoadingHUDTitleMessage(@"带indicatorView的HUD", @"支持子标题,手动执行关闭,可改变显示状态");
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 jxt_dismissHUD();
 });
 }
 else if (indexPath.row == 6)
 {
 jxt_showProgressHUDTitleMessage(@"带进度条的HUD", @"支持子标题,手动执行关闭,可改变显示状态");
 __block float count = 0;
 #warning timer block ios10 only
 [NSTimer scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer * _Nonnull timer) {
 count += 0.05;
 jxt_setHUDProgress(count);
 if (count > 1) {
 [timer invalidate];
 jxt_setHUDSuccessTitle(@"加载成功!");
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 jxt_dismissHUD();
 });
 }
 }];
 }
 else if (indexPath.row == 7)
 {
 jxt_showProgressHUDTitleMessage(@"带进度条的HUD", @"支持子标题,手动执行关闭,可改变显示状态");
 __block float count = 0;
 #warning timer block ios10 only
 [NSTimer scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer * _Nonnull timer) {
 count += 0.05;
 jxt_setHUDProgress(count);
 if (count > 1) {
 [timer invalidate];
 jxt_setHUDFailMessage(@"加载失败!");
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 jxt_dismissHUD();
 });
 }
 }];
 }
 }
 else if (indexPath.section == 1)
 {
 if (indexPath.row == 0)
 {
 [self jxt_showAlertWithTitle:@"常规alertController-Alert" message:@"基于系统UIAlertController封装,按钮以链式语法模式快捷添加,可根据按钮index区分响应,可根据action区分响应,支持配置弹出、关闭回调,可关闭弹出动画" appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
 alertMaker.
 addActionCancelTitle(@"cancel").
 addActionDestructiveTitle(@"按钮1");
 } actionsBlock:^(NSInteger buttonIndex, UIAlertAction * _Nonnull action, JXTAlertController * _Nonnull alertSelf) {
 if (buttonIndex == 0) {
 NSLog(@"cancel");
 }
 else if (buttonIndex == 1) {
 NSLog(@"按钮1");
 }
 NSLog(@"%@--%@", action.title, action);
 }];
 }
 else if (indexPath.row == 1)
 {
 [self jxt_showActionSheetWithTitle:@"常规alertController-ActionSheet" message:@"基于系统UIAlertController封装,按钮以链式语法模式快捷添加,可根据按钮index区分响应,可根据action区分响应,支持配置弹出、关闭回调,可关闭弹出动画" appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
 alertMaker.
 addActionCancelTitle(@"cancel").
 addActionDestructiveTitle(@"按钮1").
 addActionDefaultTitle(@"按钮2").
 addActionDefaultTitle(@"按钮3").
 addActionDestructiveTitle(@"按钮4");
 } actionsBlock:^(NSInteger buttonIndex, UIAlertAction * _Nonnull action, JXTAlertController * _Nonnull alertSelf) {
 if ([action.title isEqualToString:@"cancel"]) {
 NSLog(@"cancel");
 }
 else if ([action.title isEqualToString:@"按钮1"]) {
 NSLog(@"按钮1");
 }
 else if ([action.title isEqualToString:@"按钮2"]) {
 NSLog(@"按钮2");
 }
 else if ([action.title isEqualToString:@"按钮3"]) {
 NSLog(@"按钮3");
 }
 else if ([action.title isEqualToString:@"按钮4"]) {
 NSLog(@"按钮4");
 }
 }];
 }
 else if (indexPath.row == 2)
 {
 [self jxt_showAlertWithTitle:@"无按钮alert-toast" message:@"toast样式,可自定义展示延时时间,支持配置弹出、关闭回调,可关闭弹出动画" appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
 alertMaker.toastStyleDuration = 2;
 [alertMaker setAlertDidShown:^{
 [self logMsg:@"alertDidShown"];//不用担心循环引用
 }];
 alertMaker.alertDidDismiss = ^{
 [self logMsg:@"alertDidDismiss"];
 };
 } actionsBlock:NULL];
 }
 else if (indexPath.row == 3)
 {
 [self jxt_showActionSheetWithTitle:@"无按钮actionSheet-toast" message:@"toast样式,可自定义展示延时时间,支持配置弹出、关闭回调,可关闭弹出动画" appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
 alertMaker.toastStyleDuration = 3;
 //关闭动画效果
 [alertMaker alertAnimateDisabled];
 [alertMaker setAlertDidShown:^{
 NSLog(@"alertDidShown");
 }];
 alertMaker.alertDidDismiss = ^{
 NSLog(@"alertDidDismiss");
 };
 } actionsBlock:NULL];
 }
 else if (indexPath.row == 4)
 {
 [self jxt_showAlertWithTitle:@"带输入框的alertController-Alert" message:@"点击按钮,控制台打印对应输入框的内容" appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
 alertMaker.
 addActionDestructiveTitle(@"获取输入框1").
 addActionDestructiveTitle(@"获取输入框2");
 [alertMaker addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
 textField.placeholder = @"输入框1-请输入";
 }];
 [alertMaker addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
 textField.placeholder = @"输入框2-请输入";
 }];
 } actionsBlock:^(NSInteger buttonIndex, UIAlertAction * _Nonnull action, JXTAlertController * _Nonnull alertSelf) {
 if (buttonIndex == 0) {
 UITextField *textField = alertSelf.textFields.firstObject;
 [self logMsg:textField.text];//不用担心循环引用
 }
 else if (buttonIndex == 1) {
 UITextField *textField = alertSelf.textFields.lastObject;
 [self logMsg:textField.text];
 }
 }];
 }
 }
 }
 #pragma mark - Methods
 - (void)logMsg:(NSString *)msg
 {
 NSLog(@"%@", msg);
 }
 - (UIColor *)randomColor
 {
 CGFloat r = arc4random_uniform(255);
 CGFloat g = arc4random_uniform(255);
 CGFloat b = arc4random_uniform(255);
 return [UIColor colorWithRed:(r / 255.0) green:(g / 255.0) blue:(b / 255.0) alpha:0.3f];
 }
 @end
 */