你的位置:首页 > 操作系统

[操作系统]开源第三方学习之SVProgressHUD


SVProgressHUD相信在很多项目中都有运用,运用于弹出窗提示效果;

地址:https://github.com/SVProgressHUD/SVProgressHUD

一:插件的运用

1.1 首先SVProgressHUD是一个单例([SVProgressHUD method]),所以可以使用起来也相当方便跟简单,可以写在任意位置;但必须在主线程中进行显示,或则会报闪退;也可以用于显示一个提示信息。所述显示时间取决于给定的字符串的长度( 0.5至5秒)

其中几种展现:+ (void)showInfoWithStatus:(NSString *)string;+ (void)showSuccessWithStatus:(NSString*)string;+ (void)showErrorWithStatus:(NSString *)string;+ (void)showImage:(UIImage*)image status:(NSString*)string;+ (void)showProgress:(float)progress status:(NSString*)status;简单HUD销毁:+ (void)dismiss;+ (void)dismissWithDelay:(NSTimeInterval)delay;+ (void)dismissWithCompletion:(SVProgressHUDDismissCompletion)completion;+ (void)dismissWithDelay:(NSTimeInterval)delay completion:(SVProgressHUDDismissCompletion)completion;批量HUD销毁+ (void)popActivity;

 

1.2  SVProgressHUD可通过下列方法进行个性化定制:

+ (void)setDefaultStyle:(SVProgressHUDStyle)style;         // 默认是SVProgressHUDStyleLight+ (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType;     // 默认是SVProgressHUDMaskTypeNone+ (void)setDefaultAnimationType:(SVProgressHUDAnimationType)type;  // 默认是 SVProgressHUDAnimationTypeFlat+ (void)setRingThickness:(CGFloat)width;              // 默认是 2 pt+ (void)setCornerRadius:(CGFloat)cornerRadius;           // 默认是 14 pt+ (void)setFont:(UIFont*)font;                   // 默认是 [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]+ (void)setForegroundColor:(UIColor*)color;             // 默认是 [UIColor blackColor], 仅对 SVProgressHUDStyleCustom 有效+ (void)setBackgroundColor:(UIColor*)color;             // 默认是 [UIColor whiteColor], 仅对 SVProgressHUDStyleCustom 有效+ (void)setInfoImage:(UIImage*)image;                //默认是bundle文件夹中的提示图片.+ (void)setSuccessImage:(UIImage*)image;              // 默认是bundle文件夹中的成功图片.+ (void)setErrorImage:(UIImage*)image;               // 默认是bundle文件夹中的错误图片.+ (void)setViewForExtension:(UIView*)view;             // 默认是nil,仅当设置了 #define SV_APP_EXTENSIONS 时有效.

所以我们可以对于SVProgressHUD做一些调整,比如图标跟文字的显示,背景色等;已经是相当的灵活;

 

1.3 SVProgressHUD带的四个通知,通过NSNotificationCenter 注册4份通知,以响应正在显示/消失:

SVProgressHUDWillAppearNotification 提示框即将出现

SVProgressHUDDidAppearNotification 提示框已经出现

SVProgressHUDWillDisappearNotification 提示框即将消失

SVProgressHUDDidDisappearNotification 提示框已经消失

 

每个通知传递一个userInfo字典,字典中包含HUD的状态字符串(如果有的话) ,可通过SVProgressHUDStatusUserInfoKey作为键来获取。

SVProgressHUD还发送通知:

SVProgressHUDDidReceiveTouchEventNotification当用户触摸整体屏幕上 和

' SVProgressHUDDidTouchDownInsideNotification当用户直接在HUD接触。这两个通知没有 userInfo参数,但包含了有关的触摸的UIEvent` 参数.

实例:- (void)viewWillAppear:(BOOL)animated {  [super viewWillAppear:animated];    [[NSNotificationCenter defaultCenter] addObserver:self                       selector:@selector(handleNotification:)                         name:SVProgressHUDWillAppearNotification                        object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self                       selector:@selector(handleNotification:)                         name:SVProgressHUDDidAppearNotification                        object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self                       selector:@selector(handleNotification:)                         name:SVProgressHUDWillDisappearNotification                        object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self                       selector:@selector(handleNotification:)                         name:SVProgressHUDDidDisappearNotification                        object:nil];}- (void)handleNotification:(NSNotification *)notification {  NSLog(@"Notification recieved: %@", notification.name);  NSLog(@"Status user info key: %@", notification.userInfo[SVProgressHUDStatusUserInfoKey]);}输出的内容为,其中Useful Information为提示的文本内容:SVProgressHUD[793:34162] Notification recieved: SVProgressHUDWillAppearNotification2016-06-09 21:00:13.285 SVProgressHUD[793:34162] Status user info key: Useful Information.

 

1.4 相关属性介绍

1.4.1  SVProgressHUDAnimationType 动作类型

[SVProgressHUD setDefaultAnimationType:SVProgressHUDAnimationTypeFlat]; 圆圈的转动动作[SVProgressHUD setDefaultAnimationType:SVProgressHUDAnimationTypeNative]; 菊花型的转动动作

1.4.2  SVProgressHUDMaskType 弹出窗后面的背景效果类型:

SVProgressHUDMaskTypeNone : 当提示显示的时间,用户仍然可以做其他操作,比如View 上面的输入等SVProgressHUDMaskTypeClear : 用户不可以做其他操作SVProgressHUDMaskTypeBlack : 用户不可以做其他操作,并且背景色是黑色SVProgressHUDMaskTypeGradient : 用户不可以做其他操作,并且背景色是渐变的除了插件自带的几种效果,还可以自定义背景色的效果[SVProgressHUD setBackgroundLayerColor:[[UIColor redColor] colorWithAlphaComponent:0.4]];[SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeCustom];

1.4.3  SVProgressHUDStyle 弹出窗的样式

 [SVProgressHUD setDefaultStyle:SVProgressHUDStyleLight]; 窗的背景块是白色,字跟圆圈是黑色 [SVProgressHUD setDefaultStyle:SVProgressHUDStyleDark]; 窗的背景块是黑色,字跟圆圈是白色若要自定义必须先设setDefaultStyle为SVProgressHUDStyleCustom,再进行setForegroundColor,setBackgroundColor的配置.

 

1.5:相关代码

1.5.1 SVProgressHUD消息的时间

+ (NSTimeInterval)displayDurationForString:(NSString*)string {  return MAX((float)string.length * 0.06 + 0.5, [self sharedView].minimumDismissTimeInterval);}

设置一个最大值,至少是0.5秒,其它时间按提示的文本字数长度决定;

1.5.2 设定某个效果不影响全局属性

+ (void)showSuccessWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType {  SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType;  [self setDefaultMaskType:maskType];  [self showSuccessWithStatus:status];  [self setDefaultMaskType:existingMaskType];}

首先保存全局的效果值,然后显示当前的效果,完成后又把当前的效果值换成刚才的全局效果,这样就可以兼容全局效果跟本次效果的转换;

1.5.3通知并传递内容

创建消息通知:  [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidReceiveTouchEventNotification                            object:self                           userInfo:[self notificationUserInfo]];传递的内容:- (NSDictionary*)notificationUserInfo{  return (self.statusLabel.text ? @{SVProgressHUDStatusUserInfoKey : self.statusLabel.text} : nil);}

把当前提示的内容传递给通知,方便后面在接收到消息时可以做处理;

 

二:知识点

2.1 使用 __attribute__, deprecated 关键字表示已过时的API

+ (void)showWithMaskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use show and setDefaultMaskType: instead.")));

此方法已经过时了,如果在项目中有运用到此方法编译器就会报出相应的警告;如下面截图,就是用到此方法时报的警告;

知识点扩展(其它可以见__attribute__是GNU C特色之一,在iOS用的比较广泛):

a:unavailable告诉编译器该方法不可用

作用:告诉编译器该方法不可用,如果强行调用编译器会提示错误。比如某个类在构造的时候不想直接通过init来初始化,只能通过特定的初始化方法,就可以将init方法标记为unavailable。用法:__attribute__((unavailable))

例子:#define UNAVAILABLE_ATTRIBUTE __attribute__((unavailable))#define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE#import <Foundation/Foundation.h>@interface Person : NSObject@property(nonatomic,copy) NSString *name;@property(nonatomic,assign) NSUInteger age;- (instancetype)init NS_UNAVAILABLE;- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age;@end

b:属性后面加UI_APPEARANCE_SELECTOR表示这个是影响全局

@property (assign, nonatomic) SVProgressHUDStyle defaultStyle UI_APPEARANCE_SELECTOR;          // default is SVProgressHUDStyleLight@property (assign, nonatomic) SVProgressHUDMaskType defaultMaskType UI_APPEARANCE_SELECTOR;       // default is SVProgressHUDMaskTypeNone@property (assign, nonatomic) SVProgressHUDAnimationType defaultAnimationType UI_APPEARANCE_SELECTOR;  // default is SVProgressHUDAnimationTypeFlat@property (assign, nonatomic) CGSize minimumSize UI_APPEARANCE_SELECTOR;      // default is CGSizeZero, can be used to avoid resizing for a larger message

 

2.2 关键字extern 用于修饰常量可以让外面的引用文件应用

在头文件中使用extern来声明全局常量,并在相关实现文件中定义其值,这种常量要出现在全局符号表中,所以其名称应加以区别,通常用与之相关的类名做前缀;

在SVProgressHUD.h文件中定义的这些const

extern NSString * const SVProgressHUDDidReceiveTouchEventNotification;extern NSString * const SVProgressHUDDidTouchDownInsideNotification;extern NSString * const SVProgressHUDWillDisappearNotification;extern NSString * const SVProgressHUDDidDisappearNotification;extern NSString * const SVProgressHUDWillAppearNotification;extern NSString * const SVProgressHUDDidAppearNotification;extern NSString * const SVProgressHUDStatusUserInfoKey;@interface SVProgressHUD : UIView@end

然后在SVProgressHUD.m

NSString * const SVProgressHUDDidReceiveTouchEventNotification = @"SVProgressHUDDidReceiveTouchEventNotification";NSString * const SVProgressHUDDidTouchDownInsideNotification = @"SVProgressHUDDidTouchDownInsideNotification";NSString * const SVProgressHUDWillDisappearNotification = @"SVProgressHUDWillDisappearNotification";NSString * const SVProgressHUDDidDisappearNotification = @"SVProgressHUDDidDisappearNotification";NSString * const SVProgressHUDWillAppearNotification = @"SVProgressHUDWillAppearNotification";NSString * const SVProgressHUDDidAppearNotification = @"SVProgressHUDDidAppearNotification";NSString * const SVProgressHUDStatusUserInfoKey = @"SVProgressHUDStatusUserInfoKey";@interface SVProgressHUD ()@end

就可以在其它地方进行运用:

- (void)viewWillAppear:(BOOL)animated {  [super viewWillAppear:animated];    [[NSNotificationCenter defaultCenter] addObserver:self                       selector:@selector(handleNotification:)                         name:SVProgressHUDWillAppearNotification                        object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self                       selector:@selector(handleNotification:)                         name:SVProgressHUDDidAppearNotification                        object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self                       selector:@selector(handleNotification:)                         name:SVProgressHUDWillDisappearNotification                        object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self                       selector:@selector(handleNotification:)                         name:SVProgressHUDDidDisappearNotification                        object:nil];}- (void)handleNotification:(NSNotification *)notification {  NSLog(@"Notification recieved: %@", notification.name);  NSLog(@"Status user info key: %@", notification.userInfo[SVProgressHUDStatusUserInfoKey]);}

 

2.3生成Bundle包及运用

Bundle简单理解,就是资源文件包。我们将许多图片、XIB、文本文件组织在一起,打包成一个Bundle文件。方便在其他项目中引用包内的资源。Bundle是静态的,也就是说,我们包含到包中的资源文件作为一个资源包是不参加项目编译的。也就意味着,bundle包中不能包含可执行的文件。它仅仅是作为资源,被解析成为特定的2进制数据。默认生成的配置跟strings文件都是可以删除;将要使用的bundle集成到项目中后,就可以使用了。需要注意的就是,bundle是静态的,不进行编译的资源文件。所以,要使用bundle中的资源,就需要找到相应的资源路径。

    NSBundle *bundle = [NSBundle bundleForClass:[SVProgressHUD class]];    NSURL *url = [bundle URLForResource:@"SVProgressHUD" withExtension:@"bundle"];    NSBundle *imageBundle = [NSBundle bundleWithURL:url];        UIImage* infoImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"info" ofType:@"png"]];    UIImage* successImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"success" ofType:@"png"]];    UIImage* errorImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"error" ofType:@"png"]];

当然也可以定义宏来简化代码:

#define MYBUNDLE_NAME @ "SVProgressHUD.bundle"#define MYBUNDLE_PATH [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: MYBUNDLE_NAME]#define MYBUNDLE [NSBundle bundleWithPath: MYBUNDLE_PATH]

其它一些扩展:

NSString * bundlePath = [[ NSBundle mainBundle] pathForResource: @ "MyBundle" ofType :@ "bundle"];NSBundle *resourceBundle = [NSBundle bundleWithPath:bundlePath];UIViewController *vc = [[UIViewController alloc] initWithNibName:@"vc_name" bundle:resourceBundle];图片获得bundle中的资源UIImageView *imgView=[[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];UIImage *image = [UIImage imageNamed:@"MyBundle.bundle/img_collect_success"];[imgView setImage:image];或者UIImageView *imgView=[[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];NSString *imgPath= [bundlePath stringByAppendingPathComponent :@"img_collect_success.png"];UIImage *image_1=[UIImage imageWithContentsOfFile:imgPath];[imgView setImage:image_1];

 

2.4 UIView的Tint Color属性

在iOS 7后,UIView新增加了一个tintColor属性,这个属性定义了一个非默认的着色颜色值,其值的设置会影响到以视图为根视图的整个视图层次结构。它主要是应用到诸如app图标、导航栏、按钮等一些控件上,以获取一些有意思的视觉效果。

默认情况下,一个视图的tintColor是为nil的,这意味着视图将使用父视图的tint color值。当我们指定了一个视图的tintColor后,这个色值会自动传播到视图层次结构(以当前视图为根视图)中所有的子视图上。如果系统在视图层次结构中没有找到一个非默认的tintColor值,则会使用系统定义的颜色值(蓝色,RGB值为[0,0.478431,1],我们可以在IB中看到这个颜色)。因此,这个值总是会返回一个颜色值,即我们没有指定它。

如果我们想指定整个App的tint color,则可以通过设置window的tint color。这样同一个window下的所有子视图都会继承此tint color。

若想了解关于Tint Color属性可以查看这篇文章

 

2.5 UIImage的渲染模式:UIImage.renderingMode

正如2.4点所介绍那些,在IOS7以后UIImage也会受到Tint Color的影响,着色(Tint Color)是iOS7界面中的一个.设置UIImage的渲染模式:UIImage.renderingMode重大改变,你可以设置一个UIImage在渲染时是否使用当前视图的Tint Color。UIImage新增了一个只读属性:renderingMode,对应的还有一个新增方法:imageWithRenderingMode:,它使用UIImageRenderingMode枚举值来设置图片的renderingMode属性。该枚举中包含下列值:

UIImageRenderingModeAutomatic // 根据图片的使用环境和所处的绘图上下文自动调整渲染模式(默认)。 UIImageRenderingModeAlwaysOriginal  // 始终绘制图片原始状态,不使用Tint Color。 UIImageRenderingModeAlwaysTemplate  // 始终根据Tint Color绘制图片,忽略图片的颜色信息。 

运用:

UIImage *img = [UIImage imageNamed:@ "myimage" ]; img = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; 

当然也可以兼容,是否有imageWithRenderingMode再做处理:

    if ([[UIImage class] instancesRespondToSelector:@selector(imageWithRenderingMode:)]) {      _infoImage = [infoImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];      _successImage = [successImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];      _errorImage = [errorImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];    } else {      _infoImage = infoImage;      _successImage = successImage;      _errorImage = errorImage;    }

 

2.6 UIControl

在开发应用的时候,经常会用到各种各样的控件,诸如按钮(UIButton)、滑块(UISlider)、分页控件(UIPageControl)等。这些控件用来与用户进行交互,响应用户的操作。我们查看这些类的继承体系,可以看到它们都是继承于UIControl类。UIControl是控件类的基类,它是一个抽象基类,我们不能直接使用UIControl类来实例化控件,它只是为控件子类定义一些通用的接口,并提供一些基础实现,以在事件发生时,预处理这些消息并将它们发送到指定目标对象上。UIControl也是UIView的子类;想详细了解UIControl可以查看这文章;下面创建一个控件实例:

#import <UIKit/UIKit.h>@interface ImageControl : UIControl- (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title image:(UIImage *)image;@end

#import "ImageControl.h"@implementation ImageControl {    UILabel   *_label;  UIImageView *_imageView;}- (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title image:(UIImage *)image {    self = [super initWithFrame:frame];    if (self) {        self.backgroundColor = [UIColor clearColor];    self.layer.borderWidth = 1.0f;    self.layer.borderColor = [UIColor grayColor].CGColor;    self.layer.cornerRadius = 5.0f;    self.layer.masksToBounds = YES;        CGFloat width = CGRectGetWidth(self.bounds);    CGFloat height = CGRectGetHeight(self.bounds);        [self addSubview:({            _imageView = [[UIImageView alloc] initWithFrame:self.bounds];      _imageView.image = image;      _imageView;    })];            [self addSubview:({      _label = [[UILabel alloc] initWithFrame:(CGRect){0.0f, height - 30.0f, width, 30.0f}];      _label.textAlignment = NSTextAlignmentCenter;      _label.textColor = [UIColor whiteColor];      _label.text = title;      _label;    })];  }    return self;}- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {    // 由对象本身来处理事件  [super sendAction:@selector(handleAction:) to:self forEvent:event];}- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {  [super beginTrackingWithTouch:touch withEvent:event];    NSLog(@"Begin %d", self.tracking);    return YES;}- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {  [super continueTrackingWithTouch:touch withEvent:event];    NSLog(@"Continue %d %@", self.tracking, (self.touchInside ? @"YES" : @"NO"));    return YES;}- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {  [super endTrackingWithTouch:touch withEvent:event];    CGPoint position = [touch locationInView:self];    if (CGRectContainsPoint(_label.frame, position)) {        // 在此触发一个UIControlEventTouchUpInside事件行为    [self sendActionsForControlEvents:UIControlEventTouchUpInside];  }    NSLog(@"End %d", self.tracking);}- (void)cancelTrackingWithEvent:(UIEvent *)event {  [super cancelTrackingWithEvent:event];    NSLog(@"Cancel");}- (void)handleAction:(id)sender {    NSLog(@"handle Action");    NSLog(@"target-actoin: %@", self.allTargets);}//- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//  [super touchesBegan:touches withEvent:event];//  //  NSLog(@"Touch began");//}////- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//  //  [super touchesMoved:touches withEvent:event];//  //  NSLog(@"Touch Moved");//}////- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//  [super touchesEnded:touches withEvent:event];//  //  NSLog(@"Touch End");//}////- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//  //  [super touchesCancelled:touches withEvent:event];//  //  NSLog(@"Touch Cancel");//}@end

 而在SVProgressHUD中的运用如下:

- (UIControl*)overlayView {  if(!_overlayView) {#if !defined(SV_APP_EXTENSIONS)    CGRect windowBounds = [[[UIApplication sharedApplication] delegate] window].bounds;    _overlayView = [[UIControl alloc] initWithFrame:windowBounds];#else    _overlayView = [[UIControl alloc] initWithFrame:[UIScreen mainScreen].bounds];#endif    _overlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;    _overlayView.backgroundColor = [UIColor clearColor];    [_overlayView addTarget:self action:@selector(overlayViewDidReceiveTouchEvent:forEvent:) forControlEvents:UIControlEventTouchDown];  }  return _overlayView;}