最近項目需要添加提示控件(HUD),想著參考一下別人的源碼再封裝,然后就找了MBProgressHUD,然后記錄下。
框架使用起來很簡單:
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[MBProgressHUD hideHUDForView:self.view animated:YES];
源碼
-
MBProgressHUD就是展示一個封裝的UIView,大小根據(jù)傳入的view鋪滿(由于背景鋪滿,所以可控制展示時不能點擊其他視圖),于是想要什么提示效果便可以自己實現(xiàn)(MBProgressHUD可以修改customView和label):
@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];//注冊通知
}
- 然后進行展示:
- (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;
}
}
- 隱藏時循環(huán)獲?。?/li>
+ (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];
}
- 最終調(diào)用
done進行移除并進行相應回調(diào):
- (void)done {
[self setNSProgressDisplayLinkEnabled:NO];
if (self.hasFinished) {
self.alpha = 0.0f;
if (self.removeFromSuperViewOnHide) {
[self removeFromSuperview];//移除
}
}
//進行回調(diào)
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類對外提供的都是類方法,其內(nèi)部實現(xiàn)為一個單例對象。
SVProgressHUD主要包含三部分:loading視圖、提示文本框和背景框,沒有詳情文本框。
SVProgressHUD默認提供了正確、錯誤和信息三種狀態(tài)視圖。
SVProgressHUD為我們提供了更多的交互操作,包括點擊事件、顯示事件及隱藏事件。不過這些都是通過通知的形式向外發(fā)送,所以我們需要自己去監(jiān)聽這些事件。
SVProgressHUD中一些loading動畫是以Layer動畫的形式來實現(xiàn)的。
-
自己封裝
如果自己封裝一個簡單的HUD,就是添加一個自定義UIView控件到頁面上方,自己可以在實現(xiàn)對應效果,然后展示或隱藏。
我直接添加到
UIWindow上全局使用,然后用hiden控制展示和隱藏.可能計算自適應
label會有點麻煩,因為沒有用約束.然后自己用
UIActivityIndicatorView作為加載提示器,發(fā)現(xiàn)太小,使用transform變大后通過Debug View Hierarchy發(fā)現(xiàn)菊花圖案有右/下邊距,沒法居中,于是自己使用CAShapeLayer、UIBezierPath和CABasicAnimation寫了簡陋的提示效果:

- 注意處理同時顯示隱藏操作的沖突問題。