话说,MBProgressHUD 是我接触iOS的第一个第三方的轮子,感觉还是很有感情的,一直一来也没好好看看里面,下面是大致看完后记录的几个点。
- 利用KVO 刷新
- 各种宏的巧用
- 永远保证UIView 在主线程中进行动作
同时在想,MBProgressHUD 也有一个使用上的不方便是,弹出短时间内的提示框的时候,不能点击其他操作,这个很多时候是很不方便的。
一、利用 KVO 刷新
#pragma mark - KVO
- (void)registerForKVO {
for (NSString *keyPath in [self observableKeypaths]) {
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
}
}
- (void)unregisterFromKVO {
for (NSString *keyPath in [self observableKeypaths]) {
[self removeObserver:self forKeyPath:keyPath];
}
}
- (NSArray *)observableKeypaths {
return [NSArray arrayWithObjects:@"mode", @"customView", @"labelText", @"labelFont", @"labelColor",
@"detailsLabelText", @"detailsLabelFont", @"detailsLabelColor", @"progress", @"activityIndicatorColor", nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO];
} else {
[self updateUIForKeypath:keyPath];
}
}
- (void)updateUIForKeypath:(NSString *)keyPath {
if ([keyPath isEqualToString:@"mode"] || [keyPath isEqualToString:@"customView"] ||
[keyPath isEqualToString:@"activityIndicatorColor"]) {
[self updateIndicators];
} else if ([keyPath isEqualToString:@"labelText"]) {
label.text = self.labelText;
} else if ([keyPath isEqualToString:@"labelFont"]) {
label.font = self.labelFont;
} else if ([keyPath isEqualToString:@"labelColor"]) {
label.textColor = self.labelColor;
} else if ([keyPath isEqualToString:@"detailsLabelText"]) {
detailsLabel.text = self.detailsLabelText;
} else if ([keyPath isEqualToString:@"detailsLabelFont"]) {
detailsLabel.font = self.detailsLabelFont;
} else if ([keyPath isEqualToString:@"detailsLabelColor"]) {
detailsLabel.textColor = self.detailsLabelColor;
} else if ([keyPath isEqualToString:@"progress"]) {
if ([indicator respondsToSelector:@selector(setProgress:)]) {
[(id)indicator setValue:@(progress) forKey:@"progress"];
}
return;
}
[self setNeedsLayout];
[self setNeedsDisplay];
}
获取属性,用KVO刷新,很巧妙,很直接,这个可以学习。
- (NSArray *)observableKeypaths;
二、 各种宏的巧用
区分ARC 的情况
#ifndef MB_INSTANCETYPE
#if __has_feature(objc_instancetype)
#define MB_INSTANCETYPE instancetype
#else
#define MB_INSTANCETYPE id
#endif
#endif
#ifndef MB_STRONG
#if __has_feature(objc_arc)
#define MB_STRONG strong
#else
#define MB_STRONG retain
#endif
#endif
#ifndef MB_WEAK
#if __has_feature(objc_arc_weak)
#define MB_WEAK weak
#elif __has_feature(objc_arc)
#define MB_WEAK unsafe_unretained
#else
#define MB_WEAK assign
#endif
#endif
区分不同版本的
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000
#define MBLabelAlignmentCenter NSTextAlignmentCenter
#else
#define MBLabelAlignmentCenter UITextAlignmentCenter
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#define MB_TEXTSIZE(text, font) [text length] > 0 ? [text \
sizeWithAttributes:@{NSFontAttributeName:font}] : CGSizeZero;
#else
#define MB_TEXTSIZE(text, font) [text length] > 0 ? [text sizeWithFont:font] : CGSizeZero;
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \
boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin) \
attributes:@{NSFontAttributeName:font} context:nil].size : CGSizeZero;
#else
#define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \
sizeWithFont:font constrainedToSize:maxSize lineBreakMode:mode] : CGSizeZero;
#endif
哎,想想还是顺便放到我另一个笔记中iOS 中常用宏,判断文字宽度不同版本的两者还是很实用的。
三、 永远保证UIView 在主线程中进行动作
- show 时的判断
NSAssert([NSThread isMainThread], @"MBProgressHUD needs to be accessed on the main thread.");
- KVO 刷新时的判断
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO];
} else {
[self updateUIForKeypath:keyPath];
}
另外注意, 直接取消一个对象在当前Run Loop中的所有未执行的performSelector:withObject:afterDelay:
方法所产生的Selector Sources
。
[NSObject cancelPreviousPerformRequestsWithTarget:self];
总的来说,其实在里面还是有多细节可以挖掘的,看我们的关注点吧
- (void)layoutSubviews;
- (void)drawRect:(CGRect)rect;
像上述两个方法中有很多可以去发现,同时要进行一些额外的操作也可以在这里面进行添加或修改。
像之前想的问题,弹出短时间内的提示框的时候,不能点击其他操作, 也许一个简单的交互就可以实现:
hud.userInteractionEnabled = NO;
又或是通过设置添加一个取消按钮也可以,当然这样更好。
而真正使用MBProgressHUD 还是很简单的,直接看一个github中的源码的Demo 基本都会啦。