MBProgressHUD1.0.0源碼解析

MBProgressHUD是一個(gè)顯示提示窗口的三方庫(kù),常用于用戶交互、后臺(tái)耗時(shí)操作等的提示。通過(guò)顯示一個(gè)提示框,通知用戶操作或任務(wù)的執(zhí)行狀態(tài);同時(shí),利用動(dòng)畫效果,降低用戶等待的焦慮心理,增強(qiáng)用戶體驗(yàn)。
??本篇文章從源碼角度來(lái)看一下MBProgressHUD是如何實(shí)現(xiàn)的,所用的知識(shí)都是比較基礎(chǔ)的,不過(guò)還是值得我們學(xué)習(xí)一下。詳解如下:

1. 類介紹
  • MBProgressHUD
    ?? 這是MBProgressHUD的主要類,提供豐富的屬性來(lái)調(diào)整視圖的樣式。
  • MBRoundProgressView
    ?? 這是提供Determinate視圖顯示的類,有非圓環(huán)和圓環(huán)視圖兩種方式。
  • MBBarProgressView
    ?? 這是提供進(jìn)度條的視圖類。
  • MBBackgroundView
    ?? 這是MBProgressHUD的背景視圖類,利用UIVisualEffectView提供毛玻璃效果
2. MBProgressHUD類的顯示模式
  • MBProgressHUDModeIndeterminate
    Indeterminate
  • MBProgressHUDModeDeterminate
    Determinate
  • MBProgressHUDModeDeterminateHorizontalBar
    DeterminateHorizontalBar
  • MBProgressHUDModeAnnularDeterminate
    AnnularDeterminate
  • MBProgressHUDModeCustomView
    這是自定義視圖
  • MBProgressHUDModeText
    Text
3.動(dòng)畫模式
  • MBProgressHUDAnimationFade : 漸變模式
  • MBProgressHUDAnimationZoom : Zoom In & Zoom Out
  • MBProgressHUDAnimationZoomOut : 消失時(shí)帶變小動(dòng)畫
  • MBProgressHUDAnimationZoomIn : 出現(xiàn)時(shí)帶變大動(dòng)畫
4. 背景樣式
  • MBProgressHUDBackgroundStyleSolidColor : 正常顏色
  • MBProgressHUDBackgroundStyleBlur : 毛玻璃效果
5. 視圖內(nèi)容
  • @property (strong, nonatomic, readonly) UILabel *label; : 標(biāo)題
  • @property (strong, nonatomic, readonly) UILabel *detailsLabel; :詳情
  • @property (strong, nonatomic, readonly) UIButton *button : 按鈕(顯示在標(biāo)題下方)
  • @property (strong, nonatomic, nullable) UIView *customView; :用戶自定義視圖
  • @property (strong, nonatomic, readonly) MBBackgroundView *backgroundView; : 整個(gè)背景視圖
  • @property (strong, nonatomic, readonly) MBBackgroundView *bezelView; :提示框背景視圖
  • @property (strong, nonatomic, nullable) UIColor *contentColor UI_APPEARANCE_SELECTOR; : 提示框的內(nèi)容顏色
  • @property (assign, nonatomic) CGPoint offset UI_APPEARANCE_SELECTOR; :提示框相對(duì)父視圖中心點(diǎn)的偏移量
  • @property (assign, nonatomic) CGFloat margin UI_APPEARANCE_SELECTOR; :提示框內(nèi)的內(nèi)容視圖的邊距
  • @property (assign, nonatomic) CGSize minSize UI_APPEARANCE_SELECTOR; :提示框最小尺寸
  • @property (assign, nonatomic) BOOL removeFromSuperViewOnHide; :隱藏時(shí)從父視圖中刪除
  • @property (assign, nonatomic) NSTimeInterval graceTime; :延遲多久后顯示提示框,避免快速執(zhí)行的任務(wù)也顯示提示框,給用戶造成視覺(jué)干擾。
  • @property (assign, nonatomic) NSTimeInterval minShowTime; :提示框視圖最少展示的時(shí)間
6. 創(chuàng)建和隱藏視圖
  • 創(chuàng)建流程
    ?? 通過(guò) + (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated 類方法創(chuàng)建視圖,也可以通過(guò)對(duì)象方法創(chuàng)建,不過(guò)建議用類方法,不僅創(chuàng)建方便,而且會(huì)自動(dòng)的添加到父視圖,然后進(jìn)行顯示。其中,創(chuàng)建過(guò)程如下:
- (void)commonInit {
    // Set default values for properties
    _animationType = MBProgressHUDAnimationFade;
    _mode = MBProgressHUDModeIndeterminate;
    _margin = 20.0f;
    _opacity = 1.f;
    _defaultMotionEffectsEnabled = YES;

    // Default color, depending on the current iOS version
    BOOL isLegacy = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0;
    _contentColor = isLegacy ? [UIColor whiteColor] : [UIColor colorWithWhite:0.f alpha:0.7f];
    // Transparent background
    self.opaque = NO;
    self.backgroundColor = [UIColor clearColor];
    // Make it invisible for now
    self.alpha = 0.0f;
    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    self.layer.allowsGroupOpacity = NO;

    [self setupViews];
    [self updateIndicators];
    [self registerForNotifications];
}

我們可以發(fā)現(xiàn),通過(guò)添加子空間后,根據(jù)視圖模式調(diào)用updateIndicators方法來(lái)創(chuàng)建不同的視圖,最后添加了一個(gè)狀態(tài)欄的通知,用來(lái)在橫豎屏?xí)r跳轉(zhuǎn)視圖。其中,在顯示提示框時(shí),會(huì)首先判斷graceTime,如過(guò)不為0,那么就創(chuàng)建一個(gè)定時(shí)器倒計(jì)時(shí),時(shí)間到之后再判斷任務(wù)是否結(jié)束,如果finished 不為空,就開(kāi)始顯示提示框。

- (void)showAnimated:(BOOL)animated {
    MBMainThreadAssert();
    [self.minShowTimer invalidate];
    self.useAnimation = animated;
    self.finished = NO;
    // If the grace time is set, postpone the HUD display
    if (self.graceTime > 0.0) {
        NSTimer *timer = [NSTimer timerWithTimeInterval:self.graceTime target:self selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        self.graceTimer = timer;
    } 
    // ... otherwise show the HUD immediately
    else {
        [self showUsingAnimation:self.useAnimation];
    }
}
- (void)handleGraceTimer:(NSTimer *)theTimer {
    // Show the HUD only if the task is still running
    if (!self.hasFinished) {
        [self showUsingAnimation:self.useAnimation];
    }
}
  • 隱藏視圖
    ?? 通過(guò) + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated 隱藏視圖,其中會(huì)根據(jù)minShowTime來(lái)判斷是否立即隱藏提示框。如果,minShowTime 不為0,那么會(huì)創(chuàng)建一個(gè)定時(shí)器,并把定時(shí)器加入到common模式的runloop里,等時(shí)間到后再把提示框隱藏。
- (void)hideAnimated:(BOOL)animated {
    MBMainThreadAssert();
    [self.graceTimer invalidate];
    self.useAnimation = animated;
    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];
}
7. MBRoundProgressView 和 MBBarProgressView

這兩個(gè)類,分別創(chuàng)建了 Determinate 和 進(jìn)度條 的提示框視圖,具體實(shí)現(xiàn)方法是在 - (void)drawRect:(CGRect)rect 方法里通過(guò) UIBezierPath 或者 Quarts2D 畫出,設(shè)計(jì)思想算是常規(guī),請(qǐng)參考代碼細(xì)讀。

8. MBProgressHUD應(yīng)用

對(duì)于三方框架,使用之前,最好先封裝一層(繼承或分類),方便以后的調(diào)試和新框架替換。封裝時(shí),盡量用類方法,使用時(shí)比較簡(jiǎn)潔。

  • 添加提示框
+ (void)showHUDWithText:(NSString *)text inView:(UIView *)view deley:(NSTimeInterval)time
{
    if (text == nil || text.length <= 0) {
        return;
    }
    
    if (view == nil) {
        view = [[UIApplication sharedApplication].windows lastObject];
    }
    
    MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:view animated:YES];
    HUD.mode = MBProgressHUDModeText;
    
    [HUD hideAnimated:YES afterDelay:1.5];
}
  • 隱藏提示框 (改方法調(diào)用時(shí),最好在主線程,異步線程可能會(huì)出現(xiàn)問(wèn)題)
+ (void)hideHUDForView:(UIView *)view
{
    if (view == nil) view = [[UIApplication sharedApplication].windows lastObject];
    [self hideHUDForView:view animated:YES];
}

參考資料
https://github.com/jdg/MBProgressHUD

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容