YBIBLoadingView.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. //
  2. // YBIBLoadingView.m
  3. // YBImageBrowserDemo
  4. //
  5. // Created by 波儿菜 on 2018/9/1.
  6. // Copyright © 2018年 波儿菜. All rights reserved.
  7. //
  8. #import "YBIBLoadingView.h"
  9. #import "YBIBIconManager.h"
  10. #import <objc/runtime.h>
  11. @interface UIView ()
  12. @property (nonatomic, strong, readonly) YBIBLoadingView *ybib_loading;
  13. @end
  14. @implementation UIView (YBIBLoading)
  15. - (void)ybib_showLoadingWithProgress:(CGFloat)progress {
  16. [self ybib_addLoadingView];
  17. [self.ybib_loading showProgress:progress];
  18. }
  19. - (void)ybib_showLoading {
  20. [self ybib_addLoadingView];
  21. [self.ybib_loading show];
  22. }
  23. - (void)ybib_showLoadingWithText:(NSString *)text click:(void (^)(void))click {
  24. [self ybib_addLoadingView];
  25. [self.ybib_loading showText:text click:click];
  26. }
  27. - (void)ybib_addLoadingView {
  28. YBIBLoadingView *loading = self.ybib_loading;
  29. if (!loading.superview) {
  30. [self addSubview:loading];
  31. loading.translatesAutoresizingMaskIntoConstraints = NO;
  32. NSLayoutConstraint *layA = [NSLayoutConstraint constraintWithItem:loading attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:0];
  33. NSLayoutConstraint *layB = [NSLayoutConstraint constraintWithItem:loading attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:0];
  34. NSLayoutConstraint *layC = [NSLayoutConstraint constraintWithItem:loading attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
  35. NSLayoutConstraint *layD = [NSLayoutConstraint constraintWithItem:loading attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1 constant:0];
  36. [self addConstraints:@[layA, layB, layC, layD]];
  37. }
  38. }
  39. - (void)ybib_hideLoading {
  40. YBIBLoadingView *loading = self.ybib_loading;
  41. if (loading && loading.superview) {
  42. [loading removeFromSuperview];
  43. }
  44. }
  45. static void *YBIBLoadingKey = &YBIBLoadingKey;
  46. - (void)setYbib_loading:(YBIBLoadingView *)ybib_loading {
  47. objc_setAssociatedObject(self, YBIBLoadingKey, ybib_loading, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  48. }
  49. - (YBIBLoadingView *)ybib_loading {
  50. YBIBLoadingView *loading = objc_getAssociatedObject(self, YBIBLoadingKey);
  51. if (!loading) {
  52. loading = [YBIBLoadingView new];
  53. self.ybib_loading = loading;
  54. }
  55. return loading;
  56. }
  57. @end
  58. @interface YBIBProgressDrawView : UIView
  59. @property (nonatomic, assign) CGFloat progress;
  60. @end
  61. @implementation YBIBProgressDrawView
  62. - (void)drawRect:(CGRect)rect {
  63. if (self.isHidden) return;
  64. CGFloat progress = (isnan(_progress) || isinf(_progress) || _progress < 0) ? 0 : _progress;
  65. CGFloat radius = 17;
  66. CGFloat strokeWidth = 3;
  67. CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
  68. [[UIColor lightGrayColor] setStroke];
  69. UIBezierPath *bottomPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
  70. bottomPath.lineWidth = 4.0;
  71. bottomPath.lineCapStyle = kCGLineCapRound;
  72. bottomPath.lineJoinStyle = kCGLineCapRound;
  73. [bottomPath stroke];
  74. [[UIColor whiteColor] setStroke];
  75. UIBezierPath *activePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:-M_PI / 2.0 endAngle:M_PI * 2 * progress - M_PI / 2.0 clockwise:true];
  76. activePath.lineWidth = strokeWidth;
  77. activePath.lineCapStyle = kCGLineCapRound;
  78. activePath.lineJoinStyle = kCGLineCapRound;
  79. [activePath stroke];
  80. NSShadow *shadow = [NSShadow new];
  81. shadow.shadowBlurRadius = 4;
  82. shadow.shadowOffset = CGSizeMake(0, 1);
  83. shadow.shadowColor = UIColor.darkGrayColor;
  84. NSString *string = [NSString stringWithFormat:@"%.0lf%@", progress * 100, @"%"];
  85. NSMutableAttributedString *atts = [[NSMutableAttributedString alloc] initWithString:string attributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:10], NSForegroundColorAttributeName:[UIColor whiteColor], NSShadowAttributeName:shadow}];
  86. CGSize size = atts.size;
  87. [atts drawAtPoint:CGPointMake(center.x - size.width / 2.0, center.y - size.height / 2.0)];
  88. }
  89. @end
  90. typedef NS_ENUM(NSUInteger, YBImageBrowserProgressType) {
  91. YBImageBrowserProgressTypeProgress,
  92. YBImageBrowserProgressTypeLoad,
  93. YBImageBrowserProgressTypeText
  94. };
  95. @interface YBIBLoadingView () {
  96. YBImageBrowserProgressType _type;
  97. }
  98. @property (nonatomic, strong) UILabel *textLabel;
  99. @property (nonatomic, strong) UIImageView *imageView;
  100. @property (nonatomic, strong) YBIBProgressDrawView *drawView;
  101. @property (nonatomic, copy) void(^clickTextLabelBlock)(void);
  102. @end
  103. @implementation YBIBLoadingView
  104. #pragma mark life cycle
  105. - (instancetype)initWithFrame:(CGRect)frame {
  106. self = [super initWithFrame:frame];
  107. if (self) {
  108. self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0];
  109. self.userInteractionEnabled = NO;
  110. [self addSubview:self.drawView];
  111. [self addSubview:self.textLabel];
  112. [self addSubview:self.imageView];
  113. }
  114. return self;
  115. }
  116. - (void)updateConstraints {
  117. self.textLabel.translatesAutoresizingMaskIntoConstraints = NO;
  118. NSLayoutConstraint *layA = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:20];
  119. NSLayoutConstraint *layB = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:-20];
  120. NSLayoutConstraint *layC = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
  121. self.imageView.translatesAutoresizingMaskIntoConstraints = NO;
  122. NSLayoutConstraint *layE = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
  123. NSLayoutConstraint *layF = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
  124. self.drawView.translatesAutoresizingMaskIntoConstraints = NO;
  125. NSLayoutConstraint *layG = [NSLayoutConstraint constraintWithItem:self.drawView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
  126. NSLayoutConstraint *layH = [NSLayoutConstraint constraintWithItem:self.drawView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
  127. NSLayoutConstraint *layI = [NSLayoutConstraint constraintWithItem:self.drawView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50];
  128. NSLayoutConstraint *layJ = [NSLayoutConstraint constraintWithItem:self.drawView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50];
  129. [self addConstraints:@[layA, layB, layC, layE, layF, layG, layH, layI, layJ]];
  130. [super updateConstraints];
  131. }
  132. #pragma mark public
  133. - (void)showProgress:(CGFloat)progress {
  134. self.userInteractionEnabled = NO;
  135. _type = YBImageBrowserProgressTypeProgress;
  136. self.drawView.hidden = NO;
  137. self.textLabel.hidden = YES;
  138. self.imageView.hidden = YES;
  139. [self stopImageViewAnimation];
  140. self.drawView.progress = progress;
  141. [self.drawView setNeedsDisplay];
  142. }
  143. - (void)show {
  144. self.userInteractionEnabled = NO;
  145. _type = YBImageBrowserProgressTypeLoad;
  146. self.drawView.hidden = YES;
  147. self.textLabel.hidden = YES;
  148. self.imageView.hidden = NO;
  149. [self startImageViewAnimation];
  150. [self.drawView setNeedsDisplay];
  151. }
  152. - (void)startImageViewAnimation {
  153. CABasicAnimation *ra = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
  154. ra.toValue = [NSNumber numberWithFloat:M_PI * 2];
  155. ra.duration = 1;
  156. ra.cumulative = YES;
  157. ra.repeatCount = HUGE_VALF;
  158. ra.removedOnCompletion = NO;
  159. ra.fillMode = kCAFillModeForwards;
  160. [self.imageView.layer addAnimation:ra forKey:@"ra"];
  161. }
  162. - (void)stopImageViewAnimation {
  163. [self.imageView.layer removeAllAnimations];
  164. }
  165. - (void)showText:(NSString *)text click:(void (^)(void))click {
  166. self.userInteractionEnabled = click ? YES : NO;
  167. _type = YBImageBrowserProgressTypeText;
  168. self.drawView.hidden = YES;
  169. self.textLabel.hidden = NO;
  170. self.imageView.hidden = YES;
  171. [self stopImageViewAnimation];
  172. self.textLabel.text = text;
  173. self.clickTextLabelBlock = click;
  174. [self.drawView setNeedsDisplay];
  175. }
  176. #pragma mark - touch event
  177. - (void)respondsToTapTextlabel {
  178. if (self.clickTextLabelBlock) {
  179. self.clickTextLabelBlock();
  180. }
  181. }
  182. #pragma mark - getter
  183. - (YBIBProgressDrawView *)drawView {
  184. if (!_drawView) {
  185. _drawView = [YBIBProgressDrawView new];
  186. _drawView.backgroundColor = [UIColor clearColor];
  187. }
  188. return _drawView;
  189. }
  190. - (UILabel *)textLabel {
  191. if (!_textLabel) {
  192. _textLabel = [UILabel new];
  193. _textLabel.textColor = [UIColor whiteColor];
  194. _textLabel.numberOfLines = 0;
  195. _textLabel.font = [UIFont systemFontOfSize:14];
  196. _textLabel.textAlignment = NSTextAlignmentCenter;
  197. UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToTapTextlabel)];
  198. [_textLabel addGestureRecognizer:tapGesture];
  199. _textLabel.userInteractionEnabled = YES;
  200. }
  201. return _textLabel;
  202. }
  203. - (UIImageView *)imageView {
  204. if (!_imageView) {
  205. _imageView = [UIImageView new];
  206. _imageView.image = [YBIBIconManager sharedManager].loadingImage();
  207. _imageView.layer.shadowColor = UIColor.darkGrayColor.CGColor;
  208. _imageView.layer.shadowOffset = CGSizeMake(0, 1);
  209. _imageView.layer.shadowOpacity = 1;
  210. _imageView.layer.shadowRadius = 4;
  211. }
  212. return _imageView;
  213. }
  214. @end