MBProgressHUD源码浅析

最近项目需要添加提示控件(HUD),想着参考一下别人的源码再封装,然后就找了MBProgressHUD,然后记录下。

框架使用起来很简单:

[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[MBProgressHUD hideHUDForView:self.view animated:YES];
源码
  1. MBProgressHUD就是展示一个封装的UIView,大小根据传入的view铺满(由于背景铺满,所以可控制展示时不能点击其他视图),于是想要什么提示效果便可以自己实现(MBProgressHUD可以修改customViewlabel):
@interface MBProgressHUD : UIView
@implementation MBProgressHUD

+ (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
    MBProgressHUD *hud = [[self alloc] initWithView:view];
    hud.removeFromSuperViewOnHide = YES;
    [view addSubview:hud];//添加
    [hud showAnimated:animated];
    return hud;
}

- (id)initWithView:(UIView *)view {
    NSAssert(view, @"View must not be nil.");
    return [self initWithFrame:view.bounds];
}

- (instancetype)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        [self commonInit];
    }
    return self;
}

- (void)commonInit {
     ...
    [self setupViews];//设置子视图
    [self updateIndicators];//设置指示器
    [self registerForNotifications];//注册通知
}
  1. 然后进行展示:
- (void)showAnimated:(BOOL)animated {
    ...
    else {
        [self showUsingAnimation:self.useAnimation];
    }
}

- (void)showUsingAnimation:(BOOL)animated {
    ...
    if (animated) {
        [self animateIn:YES withType:self.animationType completion:NULL];
    } else {
        self.bezelView.alpha = 1.f;
        self.backgroundView.alpha = 1.f;
    }
}
  1. 隐藏时循环获取:
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
    MBProgressHUD *hud = [self HUDForView:view];
    if (hud != nil) {
        hud.removeFromSuperViewOnHide = YES;
        [hud hideAnimated:animated];
        return YES;
    }
    return NO;
}

+ (MBProgressHUD *)HUDForView:(UIView *)view {
    NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator];
    for (UIView *subview in subviewsEnum) {
        if ([subview isKindOfClass:self]) {
            MBProgressHUD *hud = (MBProgressHUD *)subview;
            if (hud.hasFinished == NO) {
                return hud;
            }
        }
    }
    return nil;
}

- (void)hideAnimated:(BOOL)animated {
    ...
    [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;
        self.bezelView.alpha = 0.f;
        self.backgroundView.alpha = 1.f;
        [self done];
    }
}

- (void)animateIn:(BOOL)animatingIn withType:(MBProgressHUDAnimation)type completion:(void(^)(BOOL finished))completion {
    ...
    [UIView animateWithDuration:0.3 delay:0. usingSpringWithDamping:1.f initialSpringVelocity:0.f options:UIViewAnimationOptionBeginFromCurrentState animations:animations completion:completion];
}
  1. 最终调用done进行移除并进行相应回调:
- (void)done {
    [self setNSProgressDisplayLinkEnabled:NO];

    if (self.hasFinished) {
        self.alpha = 0.0f;
        if (self.removeFromSuperViewOnHide) {
            [self removeFromSuperview];//移除
        }
    }
    //进行回调
    MBProgressHUDCompletionBlock completionBlock = self.completionBlock;
    if (completionBlock) {
        completionBlock();
    }
    id<MBProgressHUDDelegate> delegate = self.delegate;
    if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
        [delegate performSelector:@selector(hudWasHidden:) withObject:self];
    }
}
流程
  • SVProgressHUD的对比

SVProgressHUD类对外提供的都是类方法,其内部实现为一个单例对象。
SVProgressHUD主要包含三部分:loading视图、提示文本框和背景框,没有详情文本框。
SVProgressHUD默认提供了正确、错误和信息三种状态视图。
SVProgressHUD为我们提供了更多的交互操作,包括点击事件、显示事件及隐藏事件。不过这些都是通过通知的形式向外发送,所以我们需要自己去监听这些事件。
SVProgressHUD中一些loading动画是以Layer动画的形式来实现的。

  • 自己封装

如果自己封装一个简单的HUD,就是添加一个自定义UIView控件到页面上方,自己可以在实现对应效果,然后展示或隐藏。

  1. 我直接添加到UIWindow上全局使用,然后用hiden控制展示和隐藏.

  2. 可能计算自适应label会有点麻烦,因为没有用约束.

  3. 然后自己用UIActivityIndicatorView作为加载提示器,发现太小,使用transform变大后通过Debug View Hierarchy发现菊花图案有右/下边距,没法居中,于是自己使用CAShapeLayerUIBezierPathCABasicAnimation写了简陋的提示效果:

  1. 注意处理同时显示隐藏操作的冲突问题。

推荐阅读更多精彩内容

  • 源码来源:gitHub源码 转载于: CocoaChina 来源:南峰子的技术博客 版本:0.9.1 MBPr...
    李小六_阅读 6,107评论 2 5
  • Substrate的transaction-payment模块分析 transaction-payment模块提供...
    建怀阅读 6,011评论 0 4
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 3,881评论 0 3
  • 公元:2019年11月28日19时42分农历:二零一九年 十一月 初三日 戌时干支:己亥乙亥己巳甲戌当月节气:立冬...
    石放阅读 5,129评论 0 2