相信不少人给网络请求添加加载框的Loading效果时都用过MBProgressHUD,但每个页面都在请求前写一个MBProgressHUD show,请求完了再dismiss,着实有些麻烦.
有没有一种思路能统一在网络请求类里写上一个加载框,每个页面的请求就不用加上MBProgressHUD呢?//个别不需要加载框的页面单独处理,其余的都展示加载框呢?
答案是有:
在网络加载统一请求方法里,在post之前直接调用:
[MBProgressHUD showHUDAddedTo:[UIApplication sharedApplication].keyWindow animated:YES];
请求结果出来(无论成功或是超时失败)的回调中:
[MBProgressHUD hideHUDForView:[UIApplication sharedApplication].keyWindow animated:YES];
但这样做有一点不好,就是每个网络请求都有加载框,你无法单独对某个特定的网络请求做单独处理.因为我们在某个特定页面即便在网络请求前设置了:MBProgressHUD hide,但最终进入网络请求统一方法中仍然会MBProgressHUD show.因为MBProgressHUD
并没有提供enableProgress属性.所以并不能在需要加载框的时候设置YES,或者不需要加载框的时候设置NO.当然,我们可以更改它的源代码,这样是行得通的.
综合上面的几点原因,不改MBProgressHUD源码又难以实现需求,改了又怕对后期更新和其它用到MBProgressHUD的页面产生影响.我们可以试着用自己的方式去实现.MBProgressHUD实际上就是一个单例View.我们完全可以自己定义个单例View,这个View可以像MBProgressHUD一样简洁通用,也可以定义的像美团加载页面小人儿跑步那种花里胡哨的效果.
//.h文件
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface LoadingIndicatorManager : UIView
@property (nonatomic, assign) BOOL disableIndicator;//根据传参设置是否启用本次请求的indicator功能
+(instancetype)sharedIndicator;
-(void)destructInstance;
@end
NS_ASSUME_NONNULL_END
//.m文件
#import "LoadingIndicatorManager.h"
#import <AFNetworking.h>
#import <AFNetworkActivityIndicatorManager.h>
#import <objc/runtime.h>
@interface LoadingIndicatorManager()
@property (nonatomic, strong) UIActivityIndicatorView *indicator;
@end
@implementation LoadingIndicatorManager
static id instance = nil;
static dispatch_once_t onceToken = 0;
+(instancetype)sharedIndicator{
if(!instance) {
dispatch_once(&onceToken, ^{
instance = [[super allocWithZone:NULL]init];
});
}
return instance;
}
-(instancetype)initWithFrame:(CGRect)frame{
if(self = [super initWithFrame:frame]){
instance = [self customInitMethod];
}
return instance;
}
-(instancetype)init{
if(self = [super init]){
// instance = [self customInitMethod];
}
return instance;
}
+(instancetype)alloc{
return [LoadingIndicatorManager sharedIndicator];
}
+(instancetype)allocWithZone:(struct _NSZone *)zone{
return [LoadingIndicatorManager sharedIndicator];
}
-(id)copyWithZone:(NSZone *)zone{
return instance;
}
-(id)copy{
return instance;
}
-(id)mutableCopy{
return instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
return instance;
}
#pragma mark - Private
-(instancetype)customInitMethod{
// self.disableIndicator = ![AFNetworkActivityIndicatorManager sharedManager].isEnabled;//根据AFN的indicator是否打开来统一设置
self.backgroundColor = [UIColor blackColor];
self.alpha = 0.4;
self.indicator = ({
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.hidesWhenStopped = YES;
indicator.frame = CGRectMake(SCREENWIDTH/2-40, SCREENHEIGHT/2-40, 80, 80);
[self addSubview:indicator];
indicator;
});
//AFN为activityCount增加了KVO兼容
//监听AFNetworkActivityIndicatorManagerd的activityCount,根据count来处理indicator
[[AFNetworkActivityIndicatorManager sharedManager] addObserver:self forKeyPath:@"activityCount" options:NSKeyValueObservingOptionNew context:nil];
return self;
}
/*
移除以及添加indicatorView的时候,需要根据当前indicatorView的状态判断,已经在显示时就不再添加
**/
//接收到AFN网络状态的通知,根据网络状态进行相应的处理
-(void)networkRequestDidStart:(NSNotification *)notification {
// UIWindow *keyWin = [UIApplication sharedApplication].keyWindow;
//
// [keyWin addSubview:self];
// self.frame = keyWin.bounds;
// self.alpha = 0.4;
// [self.indicator startAnimating];
if(self.disableIndicator){
}else{
UIWindow *keyWin = [UIApplication sharedApplication].keyWindow;
[keyWin addSubview:self];
self.alpha = 0.4;
self.frame = keyWin.bounds;
[self.indicator startAnimating];
}
}
- (void)networkRequestDidFinish:(NSNotification *)notification {
// [self performSelector:@selector(removeIndicator) withObject:nil afterDelay:4];
if(self.disableIndicator){
}else{
[self.indicator stopAnimating];
[self removeIndicator];
}
}
+(void)removeIndicator{
[[LoadingIndicatorManager sharedIndicator]removeIndicator];
}
-(void)removeIndicator{
[UIView animateWithDuration:0.5 animations:^{
self.alpha = 0;
}completion:^(BOOL finished) {
[self.indicator stopAnimating];
[self removeFromSuperview];
}];
}
//监听到AFNetworkActivityIndicatorManager的activityCount属性值,根据该值是否为0控制indicatorView的显示情况
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if([keyPath isEqualToString:@"activityCount"]){
NSLog(@"加载框------%@",change[@"new"]);
NSInteger activeCount = [change[@"new"]integerValue];
if(activeCount>0){
if(_disableIndicator){
}else{
UIWindow *keyWin = [UIApplication sharedApplication].keyWindow;
[keyWin addSubview:self];
self.frame = keyWin.bounds;
self.alpha = 0.4;
[self.indicator startAnimating];
}
}else{
[self removeIndicator];
}
}
}
#pragma =====单例的销毁&下一次重建单例========
-(void)destructInstance{
//必要时销毁单例,重置onceToken为0
instance = nil;
onceToken = 0;
}
- (void)dealloc {
NSLog(@"%sIndicator单例对象被释放",__func__);
[[AFNetworkActivityIndicatorManager sharedManager] removeObserver:self forKeyPath:@"activityCount"];
// [[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end