源碼解析--MBProgressHUD

讀者需知

最近和同事討論如何快速提升自己的開發(fā)技術淘衙,以及一些項目中的設計思維,最后大家得出一個結(jié)論剔桨,就是閱讀優(yōu)秀的開源框架屉更,因為這些開源框架中,往往包含了很多優(yōu)秀的設計思維洒缀,而且設計又更加的巧妙和規(guī)范瑰谜,所以閱讀源碼對于一個初學者來說,無疑是一個絕佳的學習途徑帝洪。建議很多初學者在剛開始學習的時候似舵,可以找一些簡單的框架學習,如果一開始就去看功能復雜葱峡,設計復雜的框架,往往很難看得懂龙助,這樣容易受到打擊砰奕,喪失繼續(xù)閱讀下去的興趣,在這里推薦一個開源框架提鸟,同時也是經(jīng)常用到的一個第三方框架军援,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.創(chuàng)建實例并且添加到對應的view上
+ (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated;

+ (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
//創(chuàng)建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;
具體實現(xiàn)
+ (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) {
        //判斷是否已經(jīng)含有MBProgressHUD類型的子控件
        if ([subview isKindOfClass:self]) {
            MBProgressHUD *hud = (MBProgressHUD *)subview;
          //判斷動畫是否結(jié)束
            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表示沒有結(jié)束
    self.finished = NO;
    // If the grace time is set, postpone the HUD display
    if (self.graceTime > 0.0) {
//此種方式創(chuàng)建的timer沒有添加至runloop中
        NSTimer *timer = [NSTimer timerWithTimeInterval:self.graceTime target:self selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];

  //將定時器添加到runloop中(//保持線程為活動狀態(tài)空厌,才能保證定時器執(zhí)行)
        [[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;
    //設置結(jié)束為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) {
        //動畫開始的時間距離現(xiàn)在的時間間隔
        NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:self.showStarted];
      //判斷動畫是否已經(jīng)執(zhí)行完成
        if (interv < self.minShowTime) {
             //如果動畫沒有執(zhí)行到指定的時間,繼續(xù)執(zhí)行下去银酬,計算剩余的時間
            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 {
    //判斷是否在執(zhí)行動畫
    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];
    如果已經(jīng)結(jié)束了
    if (self.hasFinished) {
    //設置self.alpha為空
        self.alpha = 0.0f;
          //判斷如果self.removeFromSuperViewOnHide屬性為YES
        if (self.removeFromSuperViewOnHide) {
            //移除自己
            [self removeFromSuperview];
        }
    }
    MBProgressHUDCompletionBlock completionBlock = self.completionBlock;
·//執(zhí)行block
    if (completionBlock) {
        completionBlock();
    }
    觸發(fā)代理方法
    id<MBProgressHUDDelegate> delegate = self.delegate;
    if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
        [delegate performSelector:@selector(hudWasHidden:) withObject:self];
    }
}

有一些好的設計揩瞪,以后在自己的設計中可以效仿赋朦。

1.使用枚舉做類型判斷,區(qū)分不同的種類(枚舉作為API的接口參數(shù))
- (void)animateIn:(BOOL)animatingIn withType:(MBProgressHUDAnimation)type completion:(void(^)(BOOL finished))completion {

2.使用更多的BOOL值在設計中去判斷不同的狀態(tài)
@property (nonatomic, assign) BOOL useAnimation;
@property (nonatomic, assign, getter=hasFinished) BOOL finished;
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市宠哄,隨后出現(xiàn)的幾起案子壹将,更是在濱河造成了極大的恐慌,老刑警劉巖毛嫉,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞭恰,死亡現(xiàn)場離奇詭異,居然都是意外死亡狱庇,警方通過查閱死者的電腦和手機惊畏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來密任,“玉大人颜启,你說我怎么就攤上這事±嘶洌” “怎么了缰盏?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長淹遵。 經(jīng)常有香客問我口猜,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任吹由,我火速辦了婚禮敞映,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘须尚。我一直安慰自己,他們只是感情好侍咱,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布耐床。 她就那樣靜靜地躺著,像睡著了一般楔脯。 火紅的嫁衣襯著肌膚如雪撩轰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天昧廷,我揣著相機與錄音堪嫂,去河邊找鬼。 笑死麸粮,一個胖子當著我的面吹牛溉苛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弄诲,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼愚战,長吁一口氣:“原來是場噩夢啊……” “哼娇唯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寂玲,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤塔插,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拓哟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體想许,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年断序,在試婚紗的時候發(fā)現(xiàn)自己被綠了流纹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡违诗,死狀恐怖漱凝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诸迟,我是刑警寧澤茸炒,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站阵苇,受9級特大地震影響壁公,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绅项,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一紊册、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧趁怔,春花似錦湿硝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽示括。三九已至铺浇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垛膝,已是汗流浹背鳍侣。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吼拥,地道東北人倚聚。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像凿可,于是被迫代替她去往敵國和親惑折。 傳聞我的和親對象是個殘疾皇子授账,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,140評論 25 707
  • 起源 Web的安全模型根植于同一源策略。 跨站點腳本(XSS)攻擊可繞過同源策略惨驶。 內(nèi)容安全策略(Content-...
    從此以后dapeng閱讀 989評論 0 0
  • 雙十一賣了1482億白热,馬云又該笑了。這一天粗卜,不知有多少人徹夜未眠屋确,為它瘋狂:買買買,剁手也要買…… ...
    俞見閱讀 222評論 0 0
  • 春游 三月云開春料峭 桃紅柳綠盡顯妖 紅杏枝頭報春急 玉蘭海棠競嫽俏 蜂勤問花尋蜜意 佳人沈醉花間照 鶯雀鳴...
    柳風月色閱讀 191評論 0 0