美文网首页
源码解析--MBProgressHUD

源码解析--MBProgressHUD

作者: 东了个尼 | 来源:发表于2017-08-21 14:56 被阅读0次

    读者需知

    最近和同事讨论如何快速提升自己的开发技术,以及一些项目中的设计思维,最后大家得出一个结论,就是阅读优秀的开源框架,因为这些开源框架中,往往包含了很多优秀的设计思维,而且设计又更加的巧妙和规范,所以阅读源码对于一个初学者来说,无疑是一个绝佳的学习途径。建议很多初学者在刚开始学习的时候,可以找一些简单的框架学习,如果一开始就去看功能复杂,设计复杂的框架,往往很难看得懂,这样容易受到打击,丧失继续阅读下去的兴趣,在这里推荐一个开源框架,同时也是经常用到的一个第三方框架,MBProgressHUD。MBProgressHUD是一个非常受欢迎的第三方库,其用法简单,代码朴实易懂,涉及的知识点广而不深奥,是非常适合初学者阅读的一份源码。

    下面开始正题

    //1.设置枚举的类型 MBProgressHUDMode 显示的模式 UIActivityIndicatorView默认是小菊花

    typedef NS_ENUM(NSInteger, MBProgressHUDMode) {
        /// UIActivityIndicatorView
        MBProgressHUDModeIndeterminate,
        /// A round, pie-chart like, progress view.
        MBProgressHUDModeDeterminate,
        /// Horizontal progress bar.
        MBProgressHUDModeDeterminateHorizontalBar,
        /// Ring-shaped progress view.
        MBProgressHUDModeAnnularDeterminate,
        /// Shows a custom view.
        MBProgressHUDModeCustomView,
        /// Shows only labels.
        MBProgressHUDModeText
    };
    

    2.动画类型

    //MBProgressHUDAnimation  枚举表示动画类型 默认是 MBProgressHUDAnimationFade
    typedef NS_ENUM(NSInteger, MBProgressHUDAnimation) {
        /// Opacity animation
        MBProgressHUDAnimationFade,
        /// Opacity + scale animation (zoom in when appearing zoom out when disappearing)
        MBProgressHUDAnimationZoom,
        /// Opacity + scale animation (zoom out style)
        MBProgressHUDAnimationZoomOut,
        /// Opacity + scale animation (zoom in style)
        MBProgressHUDAnimationZoomIn
    };
    

    3.背景View的类型

    //MBProgressHUDBackgroundStyle   枚举表示背景类型  默认是MBProgressHUDBackgroundStyleSolidColor(纯色)
    typedef NS_ENUM(NSInteger, MBProgressHUDBackgroundStyle) {
        /// Solid color background
        MBProgressHUDBackgroundStyleSolidColor,
        /// UIVisualEffectView or UIToolbar.layer background view
        MBProgressHUDBackgroundStyleBlur
    };
    

    2. MBProgressHUD主要API介绍

    //1.创建实例并且添加到对应的view上
    + (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated;
    
    
    + (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
    //创建MBProgressHUD对象
        MBProgressHUD *hud = [[self alloc] initWithView:view];
    //设置 隐藏的时候从父视图删除
        hud.removeFromSuperViewOnHide = YES;
        [view addSubview:hud];
      //设置动画类型
        [hud showAnimated:animated];
        return hud;
    }
    
    2.//隐藏hud
    + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated;
    
    具体实现
    + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
        MBProgressHUD *hud = [self HUDForView:view];
    判断hud是否为空,如果为空返回nil,如果不为空设置隐藏的时候,从父视图移除
        if (hud != nil) {
            hud.removeFromSuperViewOnHide = YES;
            [hud hideAnimated:animated];
            return YES;
        }
        return NO;
    }
    
    + (MBProgressHUD *)HUDForView:(UIView *)view {
        //倒序排列 subviews
        NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator];
    //遍历所有的子视图
        for (UIView *subview in subviewsEnum) {
            //判断是否已经含有MBProgressHUD类型的子控件
            if ([subview isKindOfClass:self]) {
                MBProgressHUD *hud = (MBProgressHUD *)subview;
              //判断动画是否结束
                if (hud.hasFinished == NO) {
                    return hud;
                }
            }
        }
        return nil;
    }
    

    3.显示动画

    #pragma mark - Show & hide
    - (void)showAnimated:(BOOL)animated {
    //主线程宏定义
        MBMainThreadAssert();
      //设置定时器无效
        [self.minShowTimer invalidate];
        self.useAnimation = animated;
      //设置finished为NO表示没有结束
        self.finished = NO;
        // If the grace time is set, postpone the HUD display
        if (self.graceTime > 0.0) {
    //此种方式创建的timer没有添加至runloop中
            NSTimer *timer = [NSTimer timerWithTimeInterval:self.graceTime target:self selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];
    
      //将定时器添加到runloop中(//保持线程为活动状态,才能保证定时器执行)
            [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
            self.graceTimer = timer;
        } 
        // ... otherwise show the HUD immediately
        else {
            [self showUsingAnimation:self.useAnimation];
        }
    }
    
    - (void)showUsingAnimation:(BOOL)animated {
        // Cancel any previous animations
        //移除self.bezelView.layer上的所有动画操作
        [self.bezelView.layer removeAllAnimations];
    
        //移除self.backgroundView.layer上的所有动画操作
        [self.backgroundView.layer removeAllAnimations];
    
        // Cancel any scheduled hideDelayed: calls
        [self.hideDelayTimer invalidate];
    
        self.showStarted = [NSDate date];
        self.alpha = 1.f;
    
        // Needed in case we hide and re-show with the same NSProgress object attached.
        [self setNSProgressDisplayLinkEnabled:YES];
    
        if (animated) {
            [self animateIn:YES withType:self.animationType completion:NULL];
        } else {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
            self.bezelView.alpha = self.opacity;
    #pragma clang diagnostic pop
            self.backgroundView.alpha = 1.f;
        }
    }
    

    4.隐藏动画

    隐藏动画
    - (void)hideAnimated:(BOOL)animated {
        MBMainThreadAssert();
        [self.graceTimer invalidate];
        self.useAnimation = animated;
        //设置结束为yes
        self.finished = YES;
        // If the minShow time is set, calculate how long the HUD was shown,
        // and postpone the hiding operation if necessary
    
        if (self.minShowTime > 0.0 && self.showStarted) {
            //动画开始的时间距离现在的时间间隔
            NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:self.showStarted];
          //判断动画是否已经执行完成
            if (interv < self.minShowTime) {
                 //如果动画没有执行到指定的时间,继续执行下去,计算剩余的时间
                NSTimer *timer = [NSTimer timerWithTimeInterval:(self.minShowTime - interv) target:self selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO];
                [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
                self.minShowTimer = timer;
                return;
            } 
        }
        // ... otherwise hide the HUD immediately
        [self hideUsingAnimation:self.useAnimation];
    }
    
    - (void)hideUsingAnimation:(BOOL)animated {
        //判断是否在执行动画
        if (animated && self.showStarted) {
            self.showStarted = nil;
            [self animateIn:NO withType:self.animationType completion:^(BOOL finished) {
              //设置动画完成
                [self done];
            }];
        } else {
            self.showStarted = nil;
            //隐藏bezelView
            self.bezelView.alpha = 0.f;
            self.backgroundView.alpha = 1.f;
           //设置动画完成
            [self done];
        }
    }
    
    

    5.判断动画类型

    - (void)animateIn:(BOOL)animatingIn withType:(MBProgressHUDAnimation)type completion:(void(^)(BOOL finished))completion {
        // Automatically determine the correct zoom animation type
      //判断动画类型是不是MBProgressHUDAnimationZoom
        if (type == MBProgressHUDAnimationZoom) {
            type = animatingIn ? MBProgressHUDAnimationZoomIn : MBProgressHUDAnimationZoomOut;
        }
        //设置动画缩放比例50%
        CGAffineTransform small = CGAffineTransformMakeScale(0.5f, 0.5f);
        //设置动画缩放比例150%
        CGAffineTransform large = CGAffineTransformMakeScale(1.5f, 1.5f);
    
        // Set starting state
        UIView *bezelView = self.bezelView;
        //当动画开始并且bezelView透明的时候,且动画类型是MBProgressHUDAnimationZoomIn的时候
        if (animatingIn && bezelView.alpha == 0.f && type == MBProgressHUDAnimationZoomIn) {
             bezelView.transform缩小50%
            bezelView.transform = small;
        
        } else if (animatingIn && bezelView.alpha == 0.f && type == MBProgressHUDAnimationZoomOut) {
        //当动画开始并且bezelView透明的时候,且动画类型是MBProgressHUDAnimationZoomOut的时候
             bezelView.transform放大150%
            bezelView.transform = large;
        }
    
        // Perform animations
        dispatch_block_t animations = ^{
            if (animatingIn) {
                bezelView.transform = CGAffineTransformIdentity;
            } else if (!animatingIn && type == MBProgressHUDAnimationZoomIn) {
                bezelView.transform = large;
            } else if (!animatingIn && type == MBProgressHUDAnimationZoomOut) {
                bezelView.transform = small;
            }
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
            bezelView.alpha = animatingIn ? self.opacity : 0.f;
    #pragma clang diagnostic pop
            self.backgroundView.alpha = animatingIn ? 1.f : 0.f;
        };
    
        // Spring animations are nicer, but only available on iOS 7+
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 || TARGET_OS_TV
        if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0) {
            [UIView animateWithDuration:0.3 delay:0. usingSpringWithDamping:1.f initialSpringVelocity:0.f options:UIViewAnimationOptionBeginFromCurrentState animations:animations completion:completion];
            return;
        }
    #endif
        [UIView animateWithDuration:0.3 delay:0. options:UIViewAnimationOptionBeginFromCurrentState animations:animations completion:completion];
    }
    

    6.操作完成

    - (void)done {
        // Cancel any scheduled hideDelayed: calls
         //设置隐藏定时器为空
        [self.hideDelayTimer invalidate];
        [self setNSProgressDisplayLinkEnabled:NO];
        如果已经结束了
        if (self.hasFinished) {
        //设置self.alpha为空
            self.alpha = 0.0f;
              //判断如果self.removeFromSuperViewOnHide属性为YES
            if (self.removeFromSuperViewOnHide) {
                //移除自己
                [self removeFromSuperview];
            }
        }
        MBProgressHUDCompletionBlock completionBlock = self.completionBlock;
    ·//执行block
        if (completionBlock) {
            completionBlock();
        }
        触发代理方法
        id<MBProgressHUDDelegate> delegate = self.delegate;
        if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
            [delegate performSelector:@selector(hudWasHidden:) withObject:self];
        }
    }
    

    有一些好的设计,以后在自己的设计中可以效仿。

    1.使用枚举做类型判断,区分不同的种类(枚举作为API的接口参数)
    - (void)animateIn:(BOOL)animatingIn withType:(MBProgressHUDAnimation)type completion:(void(^)(BOOL finished))completion {
    
    
    2.使用更多的BOOL值在设计中去判断不同的状态
    @property (nonatomic, assign) BOOL useAnimation;
    @property (nonatomic, assign, getter=hasFinished) BOOL finished;
    

    相关文章

      网友评论

          本文标题:源码解析--MBProgressHUD

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