美文网首页
IOS框架:使用UI控件类框架

IOS框架:使用UI控件类框架

作者: 时光啊混蛋_97boy | 来源:发表于2020-11-05 09:46 被阅读0次

    原创:知识点总结性文章
    创作不易,请珍惜,之后会持续更新,不断完善
    个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
    温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容

    目录

    • 一、MBProgressHUD
    • 二、EmptyDataSet
    • 三、MGSwipeTableCell
    • 四、FSCalendar
    • 五、Toast
    • 六、MBProgress
    • 七、zhPopupController
    • Demo
    • 参考文献

    一、MBProgressHUD

    .m文件实现MBProgressHUDDelegate协议,并声明HUD变量:

    @interface ViewController () <MBProgressHUDDelegate>
    {
        MBProgressHUD *HUD;
    }
    #pragma mark - MBProgressHUDDelegate
    
    - (void)hudWasHidden:(MBProgressHUD *)hud
    {
        [HUD removeFromSuperview];
        HUD = nil;
    }
    

    在执行某个异步请求时开始调用:

    HUD = [MBProgressHUD showHUDAddedTo:self.webView animated:YES];
    HUD.labelText = @"正在请求...";
    HUD.mode = MBProgressHUDModeText;// mode参数可以控制显示的模式
    HUD.delegate = self;
    

    请求完成时隐藏提示效果:

    [HUD hide:YES];
    

    对于同步方法一般都是用showWhileExecuting方法,方法执行完成之后会自动隐藏:

    [HUD showWhileExecuting:@selector(myTask) onTarget:self withObject:nil animated:YES];
    

    二、EmptyDataSet

    a、运行效果
    EmptyDataSet
    a、引入头文件
    #import <UIScrollView+EmptyDataSet.h>
    
    @interface EmptyDetailViewController ()<DZNEmptyDataSetSource, DZNEmptyDataSetDelegate>
    
    @property (nonatomic, strong) ApplicationModel *application;// APP应用
    @property (nonatomic, getter=isLoading) BOOL loading;// 是否在加载中
    
    @end
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.tableView.emptyDataSetSource = self;
        self.tableView.emptyDataSetDelegate = self;
    }
    
    b、洗牌

    洗牌按钮

    - (void)setAllowShuffling:(BOOL)allowShuffling
    {
        _allowShuffling = allowShuffling;
        
        UIBarButtonItem *rightItem = nil;
        if (allowShuffling)
        {
            rightItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(shuffle:)];
        }
        
        self.navigationItem.rightBarButtonItem = rightItem;
    }
    

    重洗事件

    - (void)shuffle:(id)sender
    {
        ApplicationModel *randomApp = [self randomApplication];
        
        // 重洗
        while ([randomApp.identifier isEqualToString:self.application.identifier] || randomApp.type == ApplicationTypeUndefined)
        {
            randomApp = [self randomApplication];
        }
        
        // 刷新
        self.application = randomApp;
        [self configureNavigationBar];
        [self configureHeaderAndFooter];
        [self.tableView reloadEmptyDataSet];
    }
    

    随机跳转到应用

    - (ApplicationModel *)randomApplication
    {
        ApplicationType randomType = arc4random() % ApplicationCount;
        NSPredicate *query = [NSPredicate predicateWithFormat:@"type == %d", randomType];
        return [self.applications filteredArrayUsingPredicate:query].firstObject;
    }
    
    c、DZNEmptyDataSetSource

    根据APP类型来设置空图的带属性标题

    - (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView
    {
        NSString *text = nil;
        UIFont *font = nil;
        UIColor *textColor = nil;
        NSMutableDictionary *attributes = [NSMutableDictionary new];
        
        switch (self.application.type)
        {
            case ApplicationType500px:
            {
                text = @"No Photos";
                font = [UIFont boldSystemFontOfSize:17.0];
                textColor = [UIColor colorWithHex:@"545454"];
                break;
            }
    ......
        if (!text)
        {
            return nil;
        }
        
        if (font)
        {
            [attributes setObject:font forKey:NSFontAttributeName];
        }
        
        if (textColor)
        {
            [attributes setObject:textColor forKey:NSForegroundColorAttributeName];
        }
        
        return [[NSAttributedString alloc] initWithString:text attributes:attributes];
    }
    

    根据APP类型来设置空图的带属性描述

    - (NSAttributedString *)descriptionForEmptyDataSet:(UIScrollView *)scrollView
    {
        NSString *text = nil;
        UIFont *font = nil;
        UIColor *textColor = nil;
        
        NSMutableDictionary *attributes = [NSMutableDictionary new];
        NSMutableParagraphStyle *paragraph = [NSMutableParagraphStyle new];
        paragraph.lineBreakMode = NSLineBreakByWordWrapping;
        paragraph.alignment = NSTextAlignmentCenter;
        
        switch (self.application.type)
        {
            case ApplicationType500px:
            {
                text = @"Get started by uploading a photo.";
                font = [UIFont boldSystemFontOfSize:15.0];
                textColor = [UIColor colorWithHex:@"545454"];
                break;
            }
    ......
        if (!text)
        {
            return nil;
        }
        
        if (font) [attributes setObject:font forKey:NSFontAttributeName];
        if (textColor) [attributes setObject:textColor forKey:NSForegroundColorAttributeName];
        if (paragraph) [attributes setObject:paragraph forKey:NSParagraphStyleAttributeName];
    
        NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text attributes:attributes];
        
        switch (self.application.type)
        {
            case ApplicationTypeSkype:
                [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithHex:@"00adf1"] range:[attributedString.string rangeOfString:@"add favorites"]];
                break;
            default:
                break;
        }
        
        return attributedString;
    }
    

    获取到占位图

    - (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView
    {
        if (self.isLoading)
        {
            return [UIImage imageNamed:@"loading_imgBlue_78x78" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
        }
        else
        {
            NSString *imageName = [[[NSString stringWithFormat:@"placeholder_%@", self.application.displayName] lowercaseString] stringByReplacingOccurrencesOfString:@" " withString:@"_"];
            
            UIImage *image = [UIImage imageNamed:imageName inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
            
            return image;
        }
    }
    

    生成占位动画

    - (CAAnimation *)imageAnimationForEmptyDataSet:(UIScrollView *)scrollView
    {
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
        animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
        animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0.0, 0.0, 0.0)];
        animation.duration = 0.25;
        animation.cumulative = YES;
        animation.repeatCount = MAXFLOAT;
        
        return animation;
    }
    

    根据APP类型配置空图的按钮属性文本

    - (NSAttributedString *)buttonTitleForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state
    {
        NSString *text = nil;
        UIFont *font = nil;
        UIColor *textColor = nil;
        
        switch (self.application.type)
        {
            case ApplicationTypeAirbnb:
            {
                text = @"Start Browsing";
                font = [UIFont boldSystemFontOfSize:16.0];
                textColor = [UIColor colorWithHex:(state == UIControlStateNormal) ? @"05adff" : @"6bceff"];
                break;
            }
    .....
        if (!text)
        {
            return nil;
        }
        
        NSMutableDictionary *attributes = [NSMutableDictionary new];
        if (font) [attributes setObject:font forKey:NSFontAttributeName];
        if (textColor) [attributes setObject:textColor forKey:NSForegroundColorAttributeName];
        
        return [[NSAttributedString alloc] initWithString:text attributes:attributes];
    }
    

    根据APP类型配置空图的按钮属性文本

    - (UIImage *)buttonBackgroundImageForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state
    {
        NSString *imageName = [[NSString stringWithFormat:@"button_background_%@", self.application.displayName] lowercaseString];
        UIImage *image = [UIImage imageNamed:imageName inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
        if (state == UIControlStateNormal) imageName = [imageName stringByAppendingString:@"_normal"];
        if (state == UIControlStateHighlighted) imageName = [imageName stringByAppendingString:@"_highlight"];
        
        // Insets
        UIEdgeInsets capInsets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
        UIEdgeInsets rectInsets = UIEdgeInsetsZero;
        switch (self.application.type)
        {
            case ApplicationTypeFoursquare:
                capInsets = UIEdgeInsetsMake(25.0, 25.0, 25.0, 25.0);
                rectInsets = UIEdgeInsetsMake(0.0, 10, 0.0, 10);
                break;
    .....
        return [[image resizableImageWithCapInsets:capInsets resizingMode:UIImageResizingModeStretch] imageWithAlignmentRectInsets:rectInsets];
    }
    

    背景颜色

    - (UIColor *)backgroundColorForEmptyDataSet:(UIScrollView *)scrollView
    {
        switch (self.application.type)
        {
            case ApplicationType500px:      return [UIColor blackColor];
            case ApplicationTypeAirbnb:     return [UIColor whiteColor];
    .....
    }
    

    垂直偏移量

    - (CGFloat)verticalOffsetForEmptyDataSet:(UIScrollView *)scrollView
    {
        if (self.application.type == ApplicationTypeKickstarter)
        {
            CGFloat offset = CGRectGetHeight([UIApplication sharedApplication].statusBarFrame);
            offset += CGRectGetHeight(self.navigationController.navigationBar.frame);
            return -offset;
        }
        if (self.application.type == ApplicationTypeTwitter)
        {
            return -roundf(self.tableView.frame.size.height/2.5);
        }
        return 0.0;
    }
    

    空白高度

    - (CGFloat)spaceHeightForEmptyDataSet:(UIScrollView *)scrollView
    {
        switch (self.application.type)
        {
            case ApplicationType500px:          return 9.0;
            case ApplicationTypeAirbnb:         return 24.0;
    ......
    }
    
    d、DZNEmptyDataSetDelegate

    允许展示

    - (BOOL)emptyDataSetShouldDisplay:(UIScrollView *)scrollView
    {
        return YES;
    }
    

    允许触摸

    - (BOOL)emptyDataSetShouldAllowTouch:(UIScrollView *)scrollView
    {
        return YES;
    }
    

    允许滚动

    - (BOOL)emptyDataSetShouldAllowScroll:(UIScrollView *)scrollView
    {
        return YES;
    }
    

    是否允许展示加载动画

    - (BOOL)emptyDataSetShouldAnimateImageView:(UIScrollView *)scrollView
    {
        return self.isLoading;
    }
    

    点击View的事件

    - (void)emptyDataSet:(UIScrollView *)scrollView didTapView:(UIView *)view
    {
        self.loading = YES;
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.loading = NO;
        });
    }
    

    点击Button的事件

    - (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button
    {
        self.loading = YES;
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.loading = NO;
        });
    }
    

    三、MGSwipeTableCell

    a、运行效果
    MGSwipeTableCell
    b、引入头文件
    #import <MGSwipeTableCell.h>
    
    @interface MailViewController ()<MGSwipeTableCellDelegate>
    
    @end
    
    c、MGSwipeTableCellDelegate

    配置按钮

    - (NSArray *)swipeTableCell:(MGSwipeTableCell*)cell swipeButtonsForDirection:(MGSwipeDirection)direction swipeSettings:(MGSwipeSettings*)swipeSettings expansionSettings:(MGSwipeExpansionSettings *)expansionSettings
    {
        swipeSettings.transition = MGSwipeTransitionBorder;
        expansionSettings.buttonIndex = 0;
        
        
        __weak MailViewController *weakSelf = self;
        MailData *mail = [weakSelf mailForIndexPath:[self.tableView indexPathForCell:cell]];
        
        if (direction == MGSwipeDirectionLeftToRight)// 从左向右滑{}
        else{}// 从右向左滑
        return nil;
        
    }
    

    从左向右滑

    expansionSettings.fillOnTrigger = NO;
    expansionSettings.threshold = 2;
    
    return @[[MGSwipeButton buttonWithTitle:[weakSelf readButtonText:mail.read] backgroundColor:[UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0] padding:5 callback:^BOOL(MGSwipeTableCell *sender) {
        
        MailData *mail = [weakSelf mailForIndexPath:[weakSelf.tableView indexPathForCell:sender]];
        mail.read = !mail.read;
        
        // 刷新单元格内容时需要刷新
        [weakSelf updateCellIndicactor:mail cell:(MailTableCell*)sender];
        [cell refreshContentView];
        [(UIButton *)[cell.leftButtons objectAtIndex:0] setTitle:[weakSelf readButtonText:mail.read] forState:UIControlStateNormal];
        
        return YES;
    }]];
    

    从右向左滑

    expansionSettings.fillOnTrigger = YES;
    expansionSettings.threshold = 1.1;
    CGFloat padding = 15;
    
    MGSwipeButton *trash = [MGSwipeButton buttonWithTitle:@"Trash" backgroundColor:[UIColor colorWithRed:1.0 green:59/255.0 blue:50/255.0 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
        
        NSIndexPath *indexPath = [weakSelf.tableView indexPathForCell:sender];
        [weakSelf deleteMail:indexPath];
        
        // 不自动隐藏以改进删除动画
        return NO;
    }];
    
    MGSwipeButton *flag = [MGSwipeButton buttonWithTitle:@"Flag" backgroundColor:[UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
        
        MailData *mail = [weakSelf mailForIndexPath:[weakSelf.tableView indexPathForCell:sender]];
        mail.flag = !mail.flag;
        
        // 刷新单元格内容时需要刷新
        [weakSelf updateCellIndicactor:mail cell:(MailTableCell*)sender];
        [cell refreshContentView];
        
        return YES;
    }];
    
    MGSwipeButton *more = [MGSwipeButton buttonWithTitle:@"More" backgroundColor:[UIColor colorWithRed:200/255.0 green:200/255.0 blue:205/255.0 alpha:1.0] padding:padding callback:^BOOL(MGSwipeTableCell *sender) {
        
        return NO;
    }];
    
    return @[trash, flag, more];
    

    监听滑动方向和按钮状态

    - (void)swipeTableCell:(MGSwipeTableCell*) cell didChangeSwipeState:(MGSwipeState)state gestureIsActive:(BOOL)gestureIsActive
    {
        NSString *string;
        switch (state)
        {
            case MGSwipeStateNone: string = @"None"; break;
            case MGSwipeStateSwippingLeftToRight: string = @"SwippingLeftToRight"; break;
            case MGSwipeStateSwippingRightToLeft: string = @"SwippingRightToLeft"; break;
            case MGSwipeStateExpandingLeftToRight: string = @"ExpandingLeftToRight"; break;
            case MGSwipeStateExpandingRightToLeft: string = @"ExpandingRightToLeft"; break;
        }
        NSLog(@"Swipe state: %@ ::: Gesture: %@", string, gestureIsActive ? @"Active" : @"Ended");
    }
    
    c、辅助方法
    - (NSString *)readButtonText:(BOOL) read
    {
        return read ? @"Mark as\nunread" :@"Mark as\nread";
    }
    
    - (MailData *)mailForIndexPath:(NSIndexPath*) path
    {
        return [self.demoData objectAtIndex:path.row];
    }
    
    - (void)deleteMail:(NSIndexPath *)indexPath
    {
        [self.demoData removeObjectAtIndex:indexPath.row];
        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
    }
    

    更新指示器的颜色

    - (void)updateCellIndicactor:(MailData *)mail cell:(MailTableCell *)cell
    {
        UIColor *color;
        UIColor *innerColor;
        
        if (!mail.read && mail.flag)
        {
            color = [UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0];
            innerColor = [UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0];
        }
        else if (mail.flag)
        {
            color = [UIColor colorWithRed:1.0 green:149/255.0 blue:0.05 alpha:1.0];
        }
        else if (mail.read)
        {
            color = [UIColor clearColor];
        }
        else
        {
            color = [UIColor colorWithRed:0 green:122/255.0 blue:1.0 alpha:1.0];
        }
        
        cell.indicatorView.indicatorColor = color;
        cell.indicatorView.innerColor = innerColor;
    }
    

    四、FSCalendar

    1、Range Picker

    a、运行效果
    Range Picker
    b、导入头文件
    #import <FSCalendar/FSCalendar.h>
    
    @interface RangePickerCell : FSCalendarCell
    
    // 范围的开始/结束
    @property (weak, nonatomic) CALayer *selectionLayer;
    
    // 范围的中间
    @property (weak, nonatomic) CALayer *middleLayer;
    
    @end
    
    @interface RangePickerViewController ()<FSCalendarDataSource,FSCalendarDelegate,FSCalendarDelegateAppearance>
    
    @end
    
    c、创建日历视图
    - (void)createSubview
    {
        // 初始化属性
        self.gregorian = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
        self.dateFormatter = [[NSDateFormatter alloc] init];
        self.dateFormatter.dateFormat = @"yyyy-MM-dd";
    
        // 创建calendar
        FSCalendar *calendar = [[FSCalendar alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame), self.view.frame.size.width, self.view.frame.size.height - CGRectGetMaxY(self.navigationController.navigationBar.frame))];
        calendar.dataSource = self;
        calendar.delegate = self;
        calendar.pagingEnabled = NO;
        calendar.allowsMultipleSelection = YES;
        calendar.rowHeight = 60;
        calendar.placeholderType = FSCalendarPlaceholderTypeNone;
        [self.view addSubview:calendar];
        self.calendar = calendar;
        
        calendar.appearance.titleDefaultColor = [UIColor blackColor];
        calendar.appearance.headerTitleColor = [UIColor blackColor];
        calendar.appearance.titleFont = [UIFont systemFontOfSize:16];
        
        calendar.scope = FSCalendarScopeWeek;
        calendar.weekdayHeight = 20;
    
        calendar.swipeToChooseGesture.enabled = YES;
        
        // Hide the today circle
        // calendar.today = nil;
        [calendar registerClass:[RangePickerCell class] forCellReuseIdentifier:@"RangePickerCell"];
    }
    
    d、FSCalendarDataSource

    最小日期

    - (NSDate *)minimumDateForCalendar:(FSCalendar *)calendar
    {
        return [self.dateFormatter dateFromString:@"2020-06-08"];
    }
    

    最大日期

    - (NSDate *)maximumDateForCalendar:(FSCalendar *)calendar
    {
        return [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:10 toDate:[NSDate date] options:0];
    }
    

    今日的标题

    - (NSString *)calendar:(FSCalendar *)calendar titleForDate:(NSDate *)date
    {
        if ([self.gregorian isDateInToday:date])
        {
            return @"今";
        }
        return nil;
    }
    

    创建Cell

    - (FSCalendarCell *)calendar:(FSCalendar *)calendar cellForDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        RangePickerCell *cell = [calendar dequeueReusableCellWithIdentifier:@"RangePickerCell" forDate:date atMonthPosition:monthPosition];
        return cell;
    }
    

    配置Cell

    - (void)calendar:(FSCalendar *)calendar willDisplayCell:(FSCalendarCell *)cell forDate:(NSDate *)date atMonthPosition: (FSCalendarMonthPosition)monthPosition
    {
        [self configureCell:cell forDate:date atMonthPosition:monthPosition];
    }
    
    e、FSCalendarDelegate

    是否可以选中日期

    - (BOOL)calendar:(FSCalendar *)calendar shouldSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        return monthPosition == FSCalendarMonthPositionCurrent;
    }
    

    是否支持反选日期

    - (BOOL)calendar:(FSCalendar *)calendar shouldDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        return NO;
    }
    

    选中日期

    - (void)calendar:(FSCalendar *)calendar didSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        // 如果选择是由滑动手势引起的
        if (calendar.swipeToChooseGesture.state == UIGestureRecognizerStateChanged)
        {
            
            if (!self.startDate)
            {
                self.startDate = date;
            }
            else
            {
                if (self.endDate)
                {
                    [calendar deselectDate:self.endDate];
                }
                self.endDate = date;
            }
        }
        else
        {
            if (self.endDate)
            {
                [calendar deselectDate:self.startDate];
                [calendar deselectDate:self.endDate];
                self.startDate = date;
                self.endDate = nil;
            }
            else if (!self.startDate)
            {
                self.startDate = date;
            }
            else
            {
                self.endDate = date;
            }
        }
        
        [self configureVisibleCells];
    }
    

    取消选中

    - (void)calendar:(FSCalendar *)calendar didDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        NSLog(@"取消选中的日期为:%@",[self.dateFormatter stringFromDate:date]);
        [self configureVisibleCells];
    }
    

    日期事件颜色

    - (NSArray<UIColor *> *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance eventDefaultColorsForDate:(NSDate *)date
    {
        if ([self.gregorian isDateInToday:date])
        {
            return @[[UIColor orangeColor]];
        }
        return @[appearance.eventDefaultColor];
    }
    
    f、辅助方法

    配置可见日期的选中状态

    - (void)configureVisibleCells
    {
        [self.calendar.visibleCells enumerateObjectsUsingBlock:^(__kindof FSCalendarCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            NSDate *date = [self.calendar dateForCell:obj];
            FSCalendarMonthPosition position = [self.calendar monthPositionForCell:obj];
            [self configureCell:obj forDate:date atMonthPosition:position];
        }];
    }
    

    配置每一个日期的选中状态

    - (void)configureCell:(__kindof FSCalendarCell *)cell forDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)position
    {
        RangePickerCell *rangeCell = cell;
        if (position != FSCalendarMonthPositionCurrent)
        {
            rangeCell.middleLayer.hidden = YES;
            rangeCell.selectionLayer.hidden = YES;
            return;
        }
        if (self.startDate && self.endDate)
        {
            BOOL isMiddle = [date compare:self.startDate] != [date compare:self.endDate];
            rangeCell.middleLayer.hidden = !isMiddle;
        }
        else
        {
            rangeCell.middleLayer.hidden = YES;
        }
        BOOL isSelected = NO;
        isSelected |= self.startDate && [self.gregorian isDate:date inSameDayAsDate:self.startDate];
        isSelected |= self.endDate && [self.gregorian isDate:date inSameDayAsDate:self.endDate];
        rangeCell.selectionLayer.hidden = !isSelected;
    }
    

    2、DIY

    a、运行效果
    DIY

    选中的是17号,但是打印结果显示选中的是16日,默认选中的3天也各自少了一天,说明这个框架有Bug呀。

    2020-11-05 11:39:11.250332+0800 UseUIControlFramework[22930:4990809] did select date: 2020-11-17
    2020-11-05 11:39:17.708906+0800 UseUIControlFramework[22930:4990809] 不是当前处理的日期月份页面(比如下一个月)则直接隐藏圆圈和选中图层
    2020-11-05 11:39:23.939118+0800 UseUIControlFramework[22930:4990809] 选中的日期包括:(
        "2020-11-03 16:00:00 +0000",
        "2020-11-04 16:00:00 +0000",
        "2020-11-05 16:00:00 +0000",
        "2020-11-16 16:00:00 +0000"
    )
    2020-11-05 11:40:15.690340+0800 UseUIControlFramework[22930:4990809] 选中则显示并更新选中图层
    2020-11-05 13:37:58.433376+0800 UseUIControlFramework[22930:4990809] 未选中
    2020-11-05 13:38:02.752246+0800 UseUIControlFramework[22930:4990809] 未选中则隐藏选中图层
    
    b、创建日历视图
    - (void)createSubview
    {
        UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        view.backgroundColor = [UIColor systemGroupedBackgroundColor];
        self.view = view;
        
        CGFloat height = [[UIDevice currentDevice].model hasPrefix:@"iPad"] ? 450 : 300;
        FSCalendar *calendar = [[FSCalendar alloc] initWithFrame:CGRectMake(0,  CGRectGetMaxY(self.navigationController.navigationBar.frame) + 44, view.frame.size.width, height)];
        calendar.dataSource = self;
        calendar.delegate = self;
        calendar.swipeToChooseGesture.enabled = YES;// 支持滑动选中手势
        calendar.allowsMultipleSelection = YES;// 支持多选
        [view addSubview:calendar];
        self.calendar = calendar;
        
        // 头部视图
        calendar.calendarHeaderView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.1];
        // 周视图
        calendar.calendarWeekdayView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.1];
        // 事件选中的颜色
        calendar.appearance.eventSelectionColor = [UIColor whiteColor];
        // 事件偏移量
        calendar.appearance.eventOffset = CGPointMake(0, -7);
        // 隐藏今天的圆圈
        calendar.today = nil;
        // 注册Cell
        [calendar registerClass:[DIYCalendarCell class] forCellReuseIdentifier:@"cell"];
        
        // 扇动的手势
        UIPanGestureRecognizer *scopeGesture = [[UIPanGestureRecognizer alloc] initWithTarget:calendar action:@selector(handleScopeGesture:)];
        [calendar addGestureRecognizer:scopeGesture];
        
        // 创建事件Label
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(calendar.frame)+10, self.view.frame.size.width, 50)];
        label.textAlignment = NSTextAlignmentCenter;
        label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
        [self.view addSubview:label];
        self.eventLabel = label;
        
        // 配置事件Label的文本属性
        NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:@""];
        NSTextAttachment *attatchment = [[NSTextAttachment alloc] init];
        attatchment.image = [UIImage imageNamed:@"icon_cat"];
        attatchment.bounds = CGRectMake(0, -3, attatchment.image.size.width, attatchment.image.size.height);
        [attributedText appendAttributedString:[NSAttributedString attributedStringWithAttachment:attatchment]];
        [attributedText appendAttributedString:[[NSAttributedString alloc] initWithString:@"  Hey Daily Event  "]];
        [attributedText appendAttributedString:[NSAttributedString attributedStringWithAttachment:attatchment]];
        self.eventLabel.attributedText = attributedText.copy;
    }
    
    c、FSCalendarDataSource

    事件数量

    - (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate *)date
    {
        return 2;
    }
    
    d、FSCalendarDelegate

    调整事件Label的位置

    - (void)calendar:(FSCalendar *)calendar boundingRectWillChange:(CGRect)bounds animated:(BOOL)animated
    {
        calendar.frame = (CGRect){calendar.frame.origin,bounds.size};
        
        self.eventLabel.frame = CGRectMake(0, CGRectGetMaxY(calendar.frame)+10, self.view.frame.size.width, 50);
        
    }
    

    是否支持反选

    - (BOOL)calendar:(FSCalendar *)calendar shouldDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        return monthPosition == FSCalendarMonthPositionCurrent;
    }
    

    选中日期

    - (void)calendar:(FSCalendar *)calendar didSelectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        NSLog(@"did select date: %@",[self.dateFormatter stringFromDate:date]);
        [self configureVisibleCells];
    }
    

    反选日期

    - (void)calendar:(FSCalendar *)calendar didDeselectDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        NSLog(@"did deselect date: %@",[self.dateFormatter stringFromDate:date]);
        [self configureVisibleCells];
    }
    
    e、辅助方法

    配置cell

    - (void)configureCell:(FSCalendarCell *)cell forDate:(NSDate *)date atMonthPosition:(FSCalendarMonthPosition)monthPosition
    {
        
        DIYCalendarCell *diyCell = (DIYCalendarCell *)cell;
        
        // 自定义今日圆圈,如果是今日则显示红色圆圈
        diyCell.circleImageView.hidden = ![self.gregorian isDateInToday:date];
        
        // 配置选择图层即边框位置
        if (monthPosition == FSCalendarMonthPositionCurrent)
        {
            SelectionType selectionType = SelectionTypeNone;
            
            NSLog(@"选中的日期包括:%@",self.calendar.selectedDates);
            if ([self.calendar.selectedDates containsObject:date])
            {
                NSDate *previousDate = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:-1 toDate:date options:0];
                NSDate *nextDate = [self.gregorian dateByAddingUnit:NSCalendarUnitDay value:1 toDate:date options:0];
                
                if ([self.calendar.selectedDates containsObject:date])
                {
                    if ([self.calendar.selectedDates containsObject:previousDate] && [self.calendar.selectedDates containsObject:nextDate])
                    {
                        // 选中日期包含昨天和明天则居中
                        selectionType = SelectionTypeMiddle;
                    }
                    else if ([self.calendar.selectedDates containsObject:previousDate] && [self.calendar.selectedDates containsObject:date])
                    {
                        // 选中日期包含昨天和今天则边框居于右边
                        selectionType = SelectionTypeRightBorder;
                    }
                    else if ([self.calendar.selectedDates containsObject:nextDate])
                    {
                        // 选中日期包含明天和今天则边框居于左边
                        selectionType = SelectionTypeLeftBorder;
                    }
                    else
                    {
                        // 只包含今天则只有一个边框
                        selectionType = SelectionTypeSingle;
                    }
                }
            }
            else
            {
                // 未选中
                selectionType = SelectionTypeNone;
                NSLog(@"未选中");
            }
            
            // 未选中则隐藏选中图层直接返回
            if (selectionType == SelectionTypeNone)
            {
                diyCell.selectionLayer.hidden = YES;
                NSLog(@"未选中则隐藏选中图层");
                return;
            }
            
            // 选中则显示并更新选中图层
            diyCell.selectionLayer.hidden = NO;
            diyCell.selectionType = selectionType;
            
            NSLog(@"选中则显示并更新选中图层");
            
        }
        else
        {
            // 不是当前处理的日期月份页面(比如下一个月)则直接隐藏圆圈和选中图层
            diyCell.circleImageView.hidden = YES;
            diyCell.selectionLayer.hidden = YES;
            
            NSLog(@"不是当前处理的日期月份页面(比如下一个月)则直接隐藏圆圈和选中图层");
        }
    }
    

    3、Prev-Next-Buttons

    a、运行效果
    Prev-Next-Buttons
    b、翻到上一页
    - (void)previousClicked:(id)sender
    {
        NSDate *currentMonth = self.calendar.currentPage;
        NSDate *previousMonth = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:-1 toDate:currentMonth options:0];
        [self.calendar setCurrentPage:previousMonth animated:YES];
    }
    
    c、翻到下一页
    - (void)nextClicked:(id)sender
    {
        NSDate *currentMonth = self.calendar.currentPage;
        NSDate *nextMonth = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:1 toDate:currentMonth options:0];
        [self.calendar setCurrentPage:nextMonth animated:YES];
    }
    

    4、Hide Placeholder

    a、运行效果
    Hide Placeholder
    b、配置日历属性
    calendar.placeholderType = FSCalendarPlaceholderTypeNone;// 隐藏占位日期
    calendar.adjustsBoundingRectWhenChangingMonths = YES;// 当月份改变的时候自动调整矩形宽度
    calendar.currentPage = [self.dateFormatter dateFromString:@"2020-06-01"];
    calendar.firstWeekday = 2;// 以周一开始
    calendar.scrollDirection = FSCalendarScrollDirectionVertical;// 垂直翻转月份
    

    5、Delegate Appearance

    a、运行效果
    Delegate Appearance
    b、初始化颜色
    // 默认颜色
    self.fillDefaultColors = @{@"2020/10/08":[UIColor purpleColor],// 紫色
                                 @"2020/10/06":[UIColor greenColor],// 绿色
    // 选中的颜色
    self.fillSelectionColors = @{@"2020/10/08":[UIColor greenColor],// 选中后变为绿色
                             @"2020/10/06":[UIColor purpleColor],// 选中后变为紫色
    // 边框的颜色
    self.borderDefaultColors = @{@"2020/10/08":[UIColor brownColor],// 棕色
    // 边框选中的颜色
    self.borderSelectionColors = @{@"2020/10/08":[UIColor redColor],// 红色
    // 带有事件的Date
    self.datesWithEvent = @[@"2020-10-03",// 一个点
    // 带有多个事件的Date
    self.datesWithMultipleEvents = @[@"2020-10-08",// 多个点
    
    c、FSCalendarDelegateAppearance

    日期事件的颜色组

    - (NSArray *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance eventDefaultColorsForDate:(NSDate *)date
    {
        NSString *dateString = [self.dateFormatter2 stringFromDate:date];
        if ([_datesWithMultipleEvents containsObject:dateString])
        {
            return @[[UIColor magentaColor],appearance.eventDefaultColor,[UIColor blackColor]];
        }
        return nil;
    }
    

    选中的颜色

    - (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance fillSelectionColorForDate:(NSDate *)date
    {
        NSString *key = [self.dateFormatter1 stringFromDate:date];
        if ([_fillSelectionColors.allKeys containsObject:key])
        {
            return _fillSelectionColors[key];
        }
        return appearance.selectionColor;
    }
    

    默认的颜色

    - (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance fillDefaultColorForDate:(NSDate *)date
    {
        NSString *key = [self.dateFormatter1 stringFromDate:date];
        if ([_fillDefaultColors.allKeys containsObject:key])
        {
            return _fillDefaultColors[key];
        }
        return nil;
    }
    

    边框的颜色

    - (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance borderDefaultColorForDate:(NSDate *)date
    {
        NSString *key = [self.dateFormatter1 stringFromDate:date];
        if ([_borderDefaultColors.allKeys containsObject:key])
        {
            return _borderDefaultColors[key];
        }
        return appearance.borderDefaultColor;
    }
    

    边框选中的颜色

    - (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance borderSelectionColorForDate:(NSDate *)date
    {
        NSString *key = [self.dateFormatter1 stringFromDate:date];
        if ([_borderSelectionColors.allKeys containsObject:key])
        {
            return _borderSelectionColors[key];
        }
        return appearance.borderSelectionColor;
    }
    

    边框的圆角大小

    - (CGFloat)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance borderRadiusForDate:(nonnull NSDate *)date
    {
        if ([@[@8,@17,@21,@25] containsObject:@([self.gregorian component:NSCalendarUnitDay fromDate:date])])
        {
            return 0.0;// 矩形
        }
        return 1.0;// 圆形
    }
    
    c、FSCalendarDataSource

    日期包含的事件个数

    - (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate *)date
    {
        NSString *dateString = [self.dateFormatter2 stringFromDate:date];
        if ([_datesWithEvent containsObject:dateString])
        {
            return 1;
        }
        if ([_datesWithMultipleEvents containsObject:dateString])
        {
            return 3;
        }
        return 0;
    }
    

    6、Full Screen

    a、运行效果
    Full Screen
    b、引入头文件
    #import <EventKit/EventKit.h>// 事件
    
    @property (strong, nonatomic) NSArray<EKEvent *> *events;
    
    Privacy - Calendars Usage Description 需要使用日历权限
    
    c、根据国历日期获得对应农历日期

    创建中国日历

    - (instancetype)init
    {
        self = [super init];
        if (self)
        {
            self.chineseCalendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierChinese];
            self.formatter = [[NSDateFormatter alloc] init];
            self.formatter.calendar = self.chineseCalendar;
            self.formatter.dateFormat = @"M";
            self.lunarDays = @[@"初二",@"初三",@"初四",@"初五",@"初六",@"初七",@"初八",@"初九",@"初十",@"十一",@"十二",@"十三",@"十四",@"十五",@"十六",@"十七",@"十八",@"十九",@"二十",@"二一",@"二二",@"二三",@"二四",@"二五",@"二六",@"二七",@"二八",@"二九",@"三十"];
            self.lunarMonths = @[@"正月",@"二月",@"三月",@"四月",@"五月",@"六月",@"七月",@"八月",@"九月",@"十月",@"冬月",@"腊月"];
        }
        return self;
    }
    

    根据国历日期获得对应农历日期

    - (NSString *)stringFromDate:(NSDate *)date
    {
        NSInteger day = [self.chineseCalendar component:NSCalendarUnitDay fromDate:date];
        if (day != 1)
        {
            return self.lunarDays[day-2];// 不是第一天则返回对应农历Day
        }
        
        // First day of month
        NSString *monthString = [self.formatter stringFromDate:date];
        if ([self.chineseCalendar.veryShortMonthSymbols containsObject:monthString])
        {
            return self.lunarMonths[monthString.integerValue-1];
        }
        
        // 闰月
        NSInteger month = [self.chineseCalendar component:NSCalendarUnitMonth fromDate:date];
        monthString = [NSString stringWithFormat:@"闰%@", self.lunarMonths[month-1]];
        return monthString;
    }
    
    d、从系统日历中获取限定日期范围内的日历事件
    - (void)loadCalendarEvents
    {
        __weak typeof(self) weakSelf = self;
        EKEventStore *store = [[EKEventStore alloc] init];
        [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
            
            if(granted)
            {
                NSDate *startDate = self.minimumDate;
                NSDate *endDate = self.maximumDate;
                
                NSPredicate *fetchCalendarEvents = [store predicateForEventsWithStartDate:startDate endDate:endDate calendars:nil];
                NSArray<EKEvent *> *eventList = [store eventsMatchingPredicate:fetchCalendarEvents];
                NSArray<EKEvent *> *events = [eventList filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(EKEvent * _Nullable event, NSDictionary<NSString *,id> * _Nullable bindings) {
                    return event.calendar.subscribed;
                }]];
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (!weakSelf) return;
                    weakSelf.events = events;
                    [weakSelf.calendar reloadData];
                });
                
            }
            else
            {
                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"权限错误" message:@"获取事件需要日历权限" preferredStyle:UIAlertControllerStyleAlert];
                [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
                [self presentViewController:alertController animated:YES completion:nil];
            }
        }];
        
    }
    
    e、从日期获取对应事件并加入缓存
    - (NSArray<EKEvent *> *)eventsForDate:(NSDate *)date
    {
        NSArray<EKEvent *> *events = [self.cache objectForKey:date];
        if ([events isKindOfClass:[NSNull class]])
        {
            return nil;
        }
        
        // 过滤事件
        NSArray<EKEvent *> *filteredEvents = [self.events filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(EKEvent * _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
            // 判断条件是发生的日期相等
            return [evaluatedObject.occurrenceDate isEqualToDate:date];
        }]];
        
        // 将事件加入缓存
        if (filteredEvents.count)
        {
            [self.cache setObject:filteredEvents forKey:date];
        }
        else
        {
            [self.cache setObject:[NSNull null] forKey:date];
        }
        return filteredEvents;
    }
    
    e、FSCalendarDelegate

    每个日期的事件个数

    - (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate *)date
    {
        if (!self.showsEvents) return 0;
        if (!self.events) return 0;
        
        NSArray<EKEvent *> *events = [self eventsForDate:date];
        return events.count;
    }
    

    每个日期的事件颜色

    - (NSArray<UIColor *> *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance eventDefaultColorsForDate:(NSDate *)date
    {
        if (!self.showsEvents) return nil;
        if (!self.events) return nil;
        
        NSArray<EKEvent *> *events = [self eventsForDate:date];
        NSMutableArray<UIColor *> *colors = [NSMutableArray arrayWithCapacity:events.count];
        [events enumerateObjectsUsingBlock:^(EKEvent * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            [colors addObject:[UIColor colorWithCGColor:obj.calendar.CGColor]];
        }];
        return colors.copy;
    }
    
    f、FSCalendarDataSource

    每个日期的副标题

    - (NSString *)calendar:(FSCalendar *)calendar subtitleForDate:(NSDate *)date
    {
        // 显示事件
        if (self.showsEvents)
        {
            EKEvent *event = [self eventsForDate:date].firstObject;
            if (event)
            {
                return event.title;
            }
        }
        
        // 显示农历
        if (self.showsLunar)
        {
            return [self.lunarFormatter stringFromDate:date];
        }
        return nil;
    }
    

    五、Toast

    1、界面

    Toast

    2、最简单的Toast

    最简单的Toast
    [self.navigationController.view makeToast:@"Toast"];
    

    3、持续指定时间的Toast

    持续指定时间的Toast
    [self.navigationController.view makeToast:@"持续3秒的Toast" duration:3.0 position:CSToastPositionTop];
    

    4、所有Toast共享的风格

    所有Toast共享的风格
    CSToastStyle *style = [[CSToastStyle alloc] initWithDefaultStyle];
    style.messageFont = [UIFont fontWithName:@"Zapfino" size:14.0];
    style.messageColor = [UIColor redColor];
    style.messageAlignment = NSTextAlignmentCenter;
    style.backgroundColor = [UIColor yellowColor];
    style.titleColor = [UIColor blackColor];
    [CSToastManager setSharedStyle:style];
    
    [self.navigationController.view makeToast:@"This is a piece of toast with a title" duration:2.0 position:CSToastPositionTop title:@"文艺复兴运动" image:[UIImage imageNamed:@"luckcoffee.JPG"] style:style completion:^(BOOL didTap) {
        if (didTap)
        {
            NSLog(@"completion from tap");
        }
        else
        {
            NSLog(@"completion without tap");
        }
    }];
    

    5、显示加载中的指示器

    显示加载中的指示器
    if (!self.isShowingActivity)
    {
        [self.navigationController.view makeToastActivity:CSToastPositionCenter];
    }
    else
    {
        [self.navigationController.view hideToastActivity];
    }
    _showingActivity = !self.isShowingActivity;
    [tableView reloadData];
    

    6、隐藏Toast

    [self.navigationController.view hideToast];
    [self.navigationController.view hideAllToasts];
    

    7、Toast是否可消失/可退出

    [_tapToDismissSwitch setOn:[CSToastManager isTapToDismissEnabled]];// !!!Dimiss Toast
    [_queueSwitch setOn:[CSToastManager isQueueEnabled]];// !!!Queue Toast
    
    - (void)handleTapToDismissToggled
    {
        [CSToastManager setTapToDismissEnabled:![CSToastManager isTapToDismissEnabled]];
    }
    
    - (void)handleQueueToggled
    {
        [CSToastManager setQueueEnabled:![CSToastManager isQueueEnabled]];
    }
    

    六、MBProgress

    1、运行效果

    2020-11-06 17:57:17.925684+0800 UseUIControlFramework[68582:6098369] 哈哈哈哈哈哈哈哈哈
    
    MBProgress

    2、配置进度条的属性

    - (void)setUPProgressHUD
    {
        // 只能设置菊花的颜色 全局设置
        [UIActivityIndicatorView appearanceWhenContainedInInstancesOfClasses:@[[MBProgressHUD class]]].color = [UIColor redColor];
        
        // 提示框格式 Determinate-圆形饼图 HorizontalBar- 水平进度条
        // AnnularDeterminate-圆环 CustomView-自定义视图 Text-文本
        self.progressHUD.mode = MBProgressHUDModeIndeterminate;
        
        // 设置进度框中的提示文字
        self.progressHUD.label.text = @"加载中...";
        // 信息详情
        _progressHUD.detailsLabel.text = @"人善如菊,夜凉如水...";
        // 进度指示器  模式是0,取值从0.0————1.0
        _progressHUD.progress = 0.5;
        
        // 设置背景框的透明度,默认0.8
        _progressHUD.bezelView.opaque = 1;
        // 设置背景颜色之后opacity属性的设置将会失效
        _progressHUD.bezelView.color = [[UIColor redColor] colorWithAlphaComponent:1];
        // 背景框的圆角值,默认是10
        _progressHUD.bezelView.layer.cornerRadius = 20;
        
        // 置提示框的相对于父视图中心点位置,正值 向右下偏移,负值左上
        [_progressHUD setOffset:CGPointMake(-80, -100)];
        // 设置各个元素距离矩形边框的距离
        [_progressHUD setMargin:5];
        // 背景框的最小尺寸
        _progressHUD.minSize = CGSizeMake(50, 50);
        // 是否强制背景框宽高相等
        _progressHUD.square = YES;
        
        // ZoomOut:逐渐的后退消失 ZoomIn:前进淡化消失
        // 默认类型的,渐变
        _progressHUD.animationType = MBProgressHUDAnimationFade;
        // 设置最短显示时间,为了避免显示后立刻被隐藏   默认是0
        _progressHUD.minShowTime = 5;
        
        // 被调用方法在宽限期内执行完,则HUD不会被显示
        // 为了避免在执行很短的任务时,去显示一个HUD窗口
        // _progressHUD.graceTime
        
        // 设置隐藏的时候是否从父视图中移除,默认是NO
        _progressHUD.removeFromSuperViewOnHide = NO;
        
        // 显示进度框
        [self.progressHUD showAnimated:YES];
        
        // 两种隐藏的方法
        // [_progressHUD hideAnimated:YES];
        [_progressHUD hideAnimated:YES afterDelay:5];
        
        // 隐藏时候的回调 隐藏动画结束之后
        _progressHUD.completionBlock = ^{
            NSLog(@"哈哈哈哈哈哈哈哈哈");
        };
    }
    

    七、zhPopupController

    1、提示框

    a、运行效果
    2020-11-09 16:16:43.370131+0800 UseUIControlFramework[92556:7149086] 城市切换的提示框
    2020-11-09 16:59:09.136253+0800 UseUIControlFramework[92556:7149086] 点击了取消按钮:取消
    2020-11-09 16:59:09.812307+0800 UseUIControlFramework[92556:7149086] 点击了提交按钮:提交
    
    垂直提示框 水平提示框
    b、创建提示框
    - (zhPopupController *)switchCitiesStyle
    {
        if (!_switchCitiesStyle)
        {
            CustomAlertView *alertView = [self createHorizontalAlertView];
            
            // 展示方式为提示框
            _switchCitiesStyle = [[zhPopupController alloc] initWithView:alertView size:alertView.bounds.size];
            _switchCitiesStyle.presentationStyle = zhPopupSlideStyleTransform;
            _switchCitiesStyle.presentationTransformScale = 1.25;
            _switchCitiesStyle.dismissonTransformScale = 0.85;
        }
        return _switchCitiesStyle;
    }
    
    c、点击按钮呈现提示框
    - (void)test1
    {
        [self.switchCitiesStyle showInView:self.view.window completion:^{
            NSLog(@"城市切换的提示框");
        }];
    }
    

    2、Toast

    a、运行效果
    2020-11-11 11:38:04.418462+0800 UseUIControlFramework[36230:8555649] 询问喜好的Toast
    
    Toast
    b、创建Toast
    - (zhPopupController *)toastStyle
    {
        if (!_toastStyle)
        {
            CustomAlertView *alertView = [self createFavouriteToastView];
            
            // 展示方式为Toast
            _toastStyle = [[zhPopupController alloc] initWithView:alertView size:alertView.bounds.size];
            _toastStyle.presentationStyle = zhPopupSlideStyleTransform;
            _toastStyle.maskType = zhPopupMaskTypeDarkBlur;// 黑色模糊遮罩
            _toastStyle.dismissOnMaskTouched = NO;// 点击黑色模糊遮罩则Toast消失
        }
        return _toastStyle;
    }
    
    c、点击按钮呈现Toast
    - (void)test2
    {
        // 0.75秒后自动消失
        [self.toastStyle showInView:self.view.window duration:0.75 bounced:YES completion:^{
            NSLog(@"询问喜好的Toast");
        }];
    }
    

    3、带图片的提示框

    a、运行效果
    2020-11-11 15:14:44.412847+0800 UseUIControlFramework[39522:8695494] 展示火箭视图
    2020-11-11 15:14:45.804308+0800 UseUIControlFramework[39522:8695494] 点击了查看详情
    
    带图片的Alert View
    b、创建火箭弹出视图
    - (zhPopupController *)overflyStyle
    {
        if (!_overflyStyle)
        {
            OverflyView *overflyView = [self createOverflyView];
            
            _overflyStyle = [[zhPopupController alloc] initWithView:overflyView size:overflyView.bounds.size];
            _overflyStyle.dismissOnMaskTouched = NO;
            // 从底部滑出
            _overflyStyle.presentationStyle = zhPopupSlideStyleFromBottom;
            // 从顶部消失
            _overflyStyle.dismissonStyle = zhPopupSlideStyleFromTop;
            // 控制弹出视图偏离的位置
            _overflyStyle.offsetSpacing = 20;
        }
        return _overflyStyle;
    }
    
    c、点击展示火箭视图
    - (void)test3
    {
        [self.overflyStyle showInView:self.view.window completion:^{
            NSLog(@"展示火箭视图");
        }];
    }
    

    4、窗帘

    a、运行效果
    窗帘
    b、创建窗帘弹出视图
    - (zhPopupController *)qzoneStyle
    {
        if (!_qzoneStyle)
        {
            CurtainView *curtainView = [self createCurtainView];
            
            _qzoneStyle = [[zhPopupController alloc] initWithView:curtainView size:curtainView.bounds.size];
            _qzoneStyle.layoutType = zhPopupLayoutTypeTop;// 位置在顶部
            _qzoneStyle.presentationStyle = zhPopupSlideStyleFromTop;// 从顶部滑入呈现
            _qzoneStyle.offsetSpacing = -30;// 偏移量
            
            __weak typeof(self) weakSelf = self;
            // 窗帘即将呈现的时候状态栏文字变暗
            _qzoneStyle.willPresentBlock = ^(zhPopupController * _Nonnull popupController) {
                weakSelf.isLightStatusBar = NO;
            };
            
            // 窗帘即将消失的时候状态栏文字变亮
            _qzoneStyle.willDismissBlock = ^(zhPopupController * _Nonnull popupController) {
                weakSelf.isLightStatusBar = YES;
            };
        }
        return _qzoneStyle;
    }
    
    c、点击后弹出窗帘视图
    - (void)test4
    {
        [self.qzoneStyle showInView:self.view.window duration:0.75 bounced:YES completion:^{
            NSLog(@"点击后弹出窗帘视图");
        }];
    }
    
    d、提供窗帘视图按钮的点击事件
    - (CurtainView *)createCurtainView
    {
        CurtainView *curtainView = [self curtainView];
        
        __weak typeof(self) weakSelf = self;
        // 点击后窗帘消失
        curtainView.closeClicked = ^(UIButton *closeButton) {
            [weakSelf.qzoneStyle dismiss];
        };
        
        // 点击后弹出提示框
        curtainView.didClickItems = ^(CurtainView *curtainView, NSInteger index) {
            [self showAlert:curtainView.items[index].titleLabel.text];
        };
        
        return curtainView;
    }
    
    e、弹出提示框
    - (void)showAlert:(NSString *)text
    {
        UILabel *label = [UILabel new];
        label.backgroundColor = [UIColor whiteColor];
        label.frame = CGRectMake(0, 0, 270, 70);
        label.numberOfLines = 0;
        label.textAlignment = NSTextAlignmentCenter;
        label.layer.cornerRadius = 3;
        label.layer.masksToBounds = YES;
        label.text = text;
        label.font = [UIFont fontWithName:@"palatino-boldItalic" size:20];
        
        zhPopupController *popupController = [[zhPopupController alloc] initWithView:label size:label.bounds.size];
        popupController.dismissAfterDelay = 1;// 1秒后消失
        popupController.maskType = zhPopupMaskTypeBlackOpacity;// 黑色遮罩
        popupController.presentationStyle = zhPopupSlideStyleTransform;
        popupController.layoutType = zhPopupLayoutTypeTop;// 位置在顶部
        popupController.offsetSpacing = 90;// 偏移量
        
        UIView *window = UIApplication.sharedApplication.keyWindow;
        [popupController showInView:window duration:0.55 delay:0 options:UIViewAnimationOptionCurveLinear bounced:YES completion:nil];
    }
    

    5、侧边栏

    a、运行效果
    侧边栏
    b、创建侧边栏视图
    - (zhPopupController *)sidebarStyle
    {
        if (!_sidebarStyle)
        {
            SidebarView *sidebar = [self createSidebarView];
            _sidebarStyle = [[zhPopupController alloc] initWithView:sidebar size:sidebar.bounds.size];
            _sidebarStyle.layoutType = zhPopupLayoutTypeLeft;// 布局在左边
            _sidebarStyle.presentationStyle = zhPopupSlideStyleFromLeft;// 从左边出现
            _sidebarStyle.panGestureEnabled = YES;// 支持扇动手势
            _sidebarStyle.panDismissRatio = 0.5;// 到Sidebar出现的比例少于自身一半的时候则隐藏
        }
        
        return _sidebarStyle;
    }
    
    c、点击后弹出侧边栏
    - (void)test5
    {
        [self.sidebarStyle showInView:self.view.window completion:^{
            NSLog(@"点击后弹出侧边栏");
        }];
    }
    
    d、实现侧边栏按钮的点击事件
    - (SidebarView *)createSidebarView
    {
        SidebarView *sidebar = [self sidebarView];
        
        __weak typeof(self) weakSelf = self;
        sidebar.didClickItems = ^(SidebarView *sidebarView, NSInteger index) {
            [weakSelf.sidebarStyle dismiss];
            [self showAlert:sidebarView.items[index].titleLabel.text];
        };
        
        return sidebar;
    }
    

    6、全屏视图

    a、运行效果
    全屏视图
    b、创建全屏视图
    - (zhPopupController *)fullStyle
    {
        if (!_fullStyle)
        {
            FullView *fullView = [self createFullView];
            _fullStyle = [[zhPopupController alloc] initWithView:fullView size:fullView.bounds.size];
            _fullStyle.maskType = zhPopupMaskTypeExtraLightBlur;
            _fullStyle.willPresentBlock = ^(zhPopupController * _Nonnull popupController) {
                [fullView startAnimationsWithCompletion:^(BOOL finished) {
                    NSLog(@"弹出全屏视图完成");
                }];
            };
        }
        return _fullStyle;
    }
    
    c、点击弹出全屏视图
    - (void)test6
    {
        [self.fullStyle showInView:self.view.window completion:^{
            NSLog(@"点击弹出全屏视图");
        }];
    }
    

    7、分享视图

    a、运行效果
    分享视图
    b、创建分享视图
    - (zhPopupController *)shareStyle
    {
        if (!_shareStyle)
        {
            WallView *wallView = [self createShareView];
            _shareStyle = [[zhPopupController alloc] initWithView:wallView size:wallView.bounds.size];
            _shareStyle.layoutType = zhPopupLayoutTypeBottom;
            _shareStyle.presentationStyle = zhPopupSlideStyleFromBottom;
        }
        return _shareStyle;
    }
    
    c、点击弹出分享视图
    - (void)test7
    {
        [self.shareStyle showInView:self.view.window duration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseInOut bounced:NO completion:nil];
    }
    

    8、键盘视图

    a、运行效果
    登录键盘 注册键盘 评论键盘
    b、创建登陆注册视图
    - (zhPopupController *)centerKeyboardStyle
    {
        if (!_centerKeyboardStyle)
        {
            UIView *backView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 236)];
            [backView addSubview:self.centerKeyboardView];
    
            _centerKeyboardStyle = [[zhPopupController alloc] initWithView:backView size:backView.bounds.size];
            _centerKeyboardStyle.maskType = zhPopupMaskTypeBlackOpacity;
            _centerKeyboardStyle.layoutType = zhPopupLayoutTypeCenter;
            _centerKeyboardStyle.presentationStyle = zhPopupSlideStyleFromBottom;
            _centerKeyboardStyle.keyboardOffsetSpacing = 50;// 调整键盘间距
            _centerKeyboardStyle.keyboardChangeFollowed = YES;// YES将在键盘更改时调整视图位置
            _centerKeyboardStyle.becomeFirstResponded = YES;
            
            __weak typeof(self) weakSelf = self;
            _centerKeyboardStyle.willPresentBlock = ^(zhPopupController * _Nonnull popupController) {
                [weakSelf.centerKeyboardView.phoneNumberField becomeFirstResponder];
            };
            
            _centerKeyboardStyle.willDismissBlock = ^(zhPopupController * _Nonnull popupController) {
                if (weakSelf.centerKeyboardView.phoneNumberField.isFirstResponder)
                {
                    [weakSelf.centerKeyboardView.phoneNumberField resignFirstResponder];
                }
                
                if (weakSelf.registerKeyboardView.phoneNumberField.isFirstResponder)
                {
                    [weakSelf.registerKeyboardView.phoneNumberField resignFirstResponder];
                }
            };
        }
        return _centerKeyboardStyle;
    }
    
    c、创建评论视图
    - (zhPopupController *)commentKeyboardStyle
    {
        if (!_commentKeyboardStyle)
        {
            CGRect rect = CGRectMake(0, 0, self.view.width, 60);
            CommentKeyboardView *commentKeyboardView = [[CommentKeyboardView alloc] initWithFrame:rect];
            
            __weak typeof(self) weakSelf = self;
            commentKeyboardView.senderClickedBlock = ^(CommentKeyboardView *keyboardView, UIButton *button) {
                [weakSelf.commentKeyboardStyle dismiss];
            };
            
            _commentKeyboardStyle = [[zhPopupController alloc] initWithView:commentKeyboardView size:commentKeyboardView.bounds.size];
            _commentKeyboardStyle.maskType = zhPopupMaskTypeDarkBlur;
            _commentKeyboardStyle.layoutType = zhPopupLayoutTypeBottom;
            _commentKeyboardStyle.presentationStyle = zhPopupSlideStyleFromBottom;
            _commentKeyboardStyle.becomeFirstResponded = YES;
            _commentKeyboardStyle.keyboardChangeFollowed = YES;
            
            _commentKeyboardStyle.willPresentBlock = ^(zhPopupController * _Nonnull popupController) {
                [commentKeyboardView.commentTextField becomeFirstResponder];
            };
            
            _commentKeyboardStyle.willDismissBlock = ^(zhPopupController * _Nonnull popupController) {
                [commentKeyboardView.commentTextField resignFirstResponder];
            };
        }
        return _commentKeyboardStyle;
    }
    

    Demo

    Demo在我的Github上,欢迎下载。
    UseFrameworkDemo

    参考文献

    相关文章

      网友评论

          本文标题:IOS框架:使用UI控件类框架

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