• MBProgressHUD1.0.0源码解析


    MBProgressHUD是一个显示提示窗口的三方库,常用于用户交互、后台耗时操作等的提示。通过显示一个提示框,通知用户操作或任务的执行状态;同时,利用动画效果,降低用户等待的焦虑心理,增强用户体验。

    本篇文章从源码角度来看一下MBProgressHUD是如何实现的,所用的知识都是比较基础的,不过还是值得我们学习一下。详解如下:

    1. 类介绍

    • MBProgressHUD
      这是MBProgressHUD的主要类,提供丰富的属性来调整视图的样式。
    • MBRoundProgressView
      这是提供Determinate视图显示的类,有非圆环和圆环视图两种方式。
    • MBBarProgressView
      这是提供进度条的视图类。
    • MBBackgroundView
      这是MBProgressHUD的背景视图类,利用UIVisualEffectView提供毛玻璃效果

    2. MBProgressHUD类的显示模式

    • MBProgressHUDModeIndeterminate
    ![Indeterminate](//upload-images.jianshu.io/upload_images/1843940-7d2ced265a958ace.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    • MBProgressHUDModeDeterminate
    ![Determinate](//upload-images.jianshu.io/upload_images/1843940-0729bfea6d1ffb75.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    • MBProgressHUDModeDeterminateHorizontalBar
    ![DeterminateHorizontalBar](//upload-images.jianshu.io/upload_images/1843940-24816377417a2ade.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    • MBProgressHUDModeAnnularDeterminate
    ![AnnularDeterminate](//upload-images.jianshu.io/upload_images/1843940-37b8afa115eb5fe8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    • MBProgressHUDModeCustomView

    这是自定义视图

    • MBProgressHUDModeText
    ![Text](//upload-images.jianshu.io/upload_images/1843940-ca92d0d489e9c287.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    3.动画模式

    • MBProgressHUDAnimationFade : 渐变模式
    • MBProgressHUDAnimationZoom : Zoom In & Zoom Out
    • MBProgressHUDAnimationZoomOut : 消失时带变小动画
    • MBProgressHUDAnimationZoomIn : 出现时带变大动画

    4. 背景样式

    • MBProgressHUDBackgroundStyleSolidColor : 正常颜色
    • MBProgressHUDBackgroundStyleBlur : 毛玻璃效果

    5. 视图内容

    • @property (strong, nonatomic, readonly) UILabel *label; : 标题
    • @property (strong, nonatomic, readonly) UILabel *detailsLabel; :详情
    • @property (strong, nonatomic, readonly) UIButton *button : 按钮(显示在标题下方)
    • @property (strong, nonatomic, nullable) UIView *customView; :用户自定义视图
    • @property (strong, nonatomic, readonly) MBBackgroundView *backgroundView; : 整个背景视图
    • @property (strong, nonatomic, readonly) MBBackgroundView *bezelView; :提示框背景视图
    • @property (strong, nonatomic, nullable) UIColor *contentColor UI_APPEARANCE_SELECTOR; : 提示框的内容颜色
    • @property (assign, nonatomic) CGPoint offset UI_APPEARANCE_SELECTOR; :提示框相对父视图中心点的偏移量
    • @property (assign, nonatomic) CGFloat margin UI_APPEARANCE_SELECTOR; :提示框内的内容视图的边距
    • @property (assign, nonatomic) CGSize minSize UI_APPEARANCE_SELECTOR; :提示框最小尺寸
    • @property (assign, nonatomic) BOOL removeFromSuperViewOnHide; :隐藏时从父视图中删除
    • @property (assign, nonatomic) NSTimeInterval graceTime; :延迟多久后显示提示框,避免快速执行的任务也显示提示框,给用户造成视觉干扰。
    • @property (assign, nonatomic) NSTimeInterval minShowTime; :提示框视图最少展示的时间

    6. 创建和隐藏视图

    • 创建流程
      通过 + (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated 类方法创建视图,也可以通过对象方法创建,不过建议用类方法,不仅创建方便,而且会自动的添加到父视图,然后进行显示。其中,创建过程如下:
    - (void)commonInit {
    	// Set default values for properties
    	_animationType = MBProgressHUDAnimationFade;
    	_mode = MBProgressHUDModeIndeterminate;
    	_margin = 20.0f;
    	_opacity = 1.f;
    	_defaultMotionEffectsEnabled = YES;
    	
    	// Default color, depending on the current iOS version
    	BOOL isLegacy = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0; 
    	_contentColor = isLegacy ? [UIColor whiteColor] : [UIColor colorWithWhite:0.f alpha:0.7f]; 
    	// Transparent background self.opaque = NO; 
    	self.backgroundColor = [UIColor clearColor]; 
    	// Make it invisible for now self.alpha = 0.0f; 
    	self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.layer.allowsGroupOpacity = NO; 
    	[self setupViews]; [self updateIndicators]; 
    	[self registerForNotifications]; 
    } 
    

    我们可以发现,通过添加子空间后,根据视图模式调用updateIndicators 方法来创建不同的视图,最后添加了一个状态栏的通知,用来在横竖屏时跳转视图。其中,在显示提示框时,会首先判断graceTime,如过不为0,那么就创建一个定时器倒计时,时间到之后再判断任务是否结束,如果finished 不为空,就开始显示提示框。

    - (void)showAnimated:(BOOL)animated {
        MBMainThreadAssert();
        [self.minShowTimer invalidate];
        self.useAnimation = animated;
        self.finished = NO;
        // If the grace time is set, postpone the HUD display
        if (self.graceTime > 0.0) {
            NSTimer *timer = [NSTimer timerWithTimeInterval:self.graceTime target:self selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];
            [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
            self.graceTimer = timer;
        } 
        // ... otherwise show the HUD immediately
        else {
            [self showUsingAnimation:self.useAnimation];
        }
    }
    
    - (void)handleGraceTimer:(NSTimer *)theTimer 
    { 
    	// Show the HUD only if the task is still running 
    	if (!self.hasFinished) { 
    		[self showUsingAnimation:self.useAnimation]; 
    	} 
    } 
    
    • 隐藏视图 通过 + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated 隐藏视图,其中会根据minShowTime来判断是否立即隐藏提示框。如果,minShowTime 不为0,那么会创建一个定时器,并把定时器加入到common模式的runloop里,等时间到后再把提示框隐藏。
    - (void)hideAnimated:(BOOL)animated 
    {    
    	MBMainThreadAssert();
        [self.graceTimer invalidate];
        self.useAnimation = animated;
        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) {
            NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:self.showStarted];
            if (interv < self.minShowTime) {
                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];
    }
    

    7. MBRoundProgressView 和 MBBarProgressView

    这两个类,分别创建了 Determinate 和 进度条 的提示框视图,具体实现方法是在 - (void)drawRect:(CGRect)rect 方法里通过 UIBezierPath 或者 Quarts2D 画出,设计思想算是常规,请参考代码细读。

    8. MBProgressHUD应用

    对于三方框架,使用之前,最好先封装一层(继承或分类),方便以后的调试和新框架替换。封装时,尽量用类方法,使用时比较简洁。

    • 添加提示框
    + (void)showHUDWithText:(NSString *)text inView:(UIView *)view deley:(NSTimeInterval)time
    {
    	if (text == nil || text.length <= 0) {
    		return;
    	}
    	
    	if (view == nil) {
    		view = [[UIApplication sharedApplication].windows lastObject];
    	}
    	
    	MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:view animated:YES];
    	HUD.mode = MBProgressHUDModeText;
    	
    	[HUD hideAnimated:YES afterDelay:1.5];
    }
    
    • 隐藏提示框 (改方法调用时,最好在主线程,异步线程可能会出现问题)
    + (void)hideHUDForView:(UIView *)view
    {
    	if (view == nil) view = [[UIApplication sharedApplication].windows lastObject];
    	[self hideHUDForView:view animated:YES];
    }
    

    参考资料

    https://github.com/jdg/MBProgressHUD

  • 相关阅读:
    PHP数组
    java中线程池的几种实现方式
    JAVA是是如何处理字符的。
    byte范围及8种常见数据类型
    对Spring 及SpringMVC的理解
    Nginx+Tomcat搭建负载均衡
    nginx + tomcat配置负载均衡
    Java并发编程:Lock
    Java内部类详解
    奇怪的Java题:为什么1000 == 1000返回为False,而100 == 100会返回为True?
  • 原文地址:https://www.cnblogs.com/fishbay/p/7198749.html
Copyright © 2020-2023  润新知