讀者需知
最近和同事討論如何快速提升自己的開發(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;