YBIBToastView.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. //
  2. // YBIBToastView.m
  3. // YBImageBrowserDemo
  4. //
  5. // Created by 波儿菜 on 2019/6/20.
  6. // Copyright © 2019 波儿菜. All rights reserved.
  7. //
  8. #import "YBIBToastView.h"
  9. #import <objc/runtime.h>
  10. @interface UIView ()
  11. @property (nonatomic, strong, readonly) YBIBToastView *ybib_toast;
  12. @end
  13. @implementation UIView (YBIBToast)
  14. - (void)ybib_showHookToast:(NSString *)text {
  15. [self ybib_showToastWithText:text type:YBIBToastTypeHook hideAfterDelay:1.7];
  16. }
  17. - (void)ybib_showForkToast:(NSString *)text {
  18. [self ybib_showToastWithText:text type:YBIBToastTypeFork hideAfterDelay:1.7];
  19. }
  20. - (void)ybib_showToastWithText:(NSString *)text type:(YBIBToastType)type hideAfterDelay:(NSTimeInterval)delay {
  21. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(ybib_hideToast) object:nil];
  22. YBIBToastView *toast = self.ybib_toast;
  23. if (!toast.superview) {
  24. [self addSubview:toast];
  25. toast.translatesAutoresizingMaskIntoConstraints = NO;
  26. NSLayoutConstraint *layA = [NSLayoutConstraint constraintWithItem:toast attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
  27. NSLayoutConstraint *layB = [NSLayoutConstraint constraintWithItem:toast attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
  28. NSLayoutConstraint *layC = [NSLayoutConstraint constraintWithItem:toast attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:40];
  29. NSLayoutConstraint *layD = [NSLayoutConstraint constraintWithItem:toast attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:-40];
  30. [self addConstraints:@[layA, layB, layC, layD]];
  31. }
  32. [toast showWithText:text type:type];
  33. [self performSelector:@selector(ybib_hideToast) withObject:nil afterDelay:delay];
  34. }
  35. - (void)ybib_hideToast {
  36. YBIBToastView *toast = self.ybib_toast;
  37. if (toast && toast.superview) {
  38. [UIView animateWithDuration:0.25 animations:^{
  39. toast.alpha = 0;
  40. } completion:^(BOOL finished) {
  41. [toast removeFromSuperview];
  42. toast.alpha = 1;
  43. }];
  44. }
  45. }
  46. static void *YBIBToastKey = &YBIBToastKey;
  47. - (void)setYbib_toast:(YBIBToastView *)ybib_toast {
  48. objc_setAssociatedObject(self, YBIBToastKey, ybib_toast, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  49. }
  50. - (YBIBToastView *)ybib_toast {
  51. YBIBToastView *toast = objc_getAssociatedObject(self, YBIBToastKey);
  52. if (!toast) {
  53. toast = [YBIBToastView new];
  54. self.ybib_toast = toast;
  55. }
  56. return toast;
  57. }
  58. @end
  59. @interface YBIBToastView () {
  60. YBIBToastType _type;
  61. CAShapeLayer *_shapeLayer;
  62. }
  63. @property (nonatomic, strong) UILabel *textLabel;
  64. @end
  65. @implementation YBIBToastView
  66. #pragma mark - life cycle
  67. - (instancetype)initWithFrame:(CGRect)frame {
  68. self = [super initWithFrame:frame];
  69. if (self) {
  70. self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8];
  71. self.userInteractionEnabled = NO;
  72. self.layer.cornerRadius = 7;
  73. [self addSubview:self.textLabel];
  74. }
  75. return self;
  76. }
  77. - (void)updateConstraints {
  78. self.textLabel.translatesAutoresizingMaskIntoConstraints = NO;
  79. NSLayoutConstraint *layA = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:20];
  80. NSLayoutConstraint *layB = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:-20];
  81. NSLayoutConstraint *layC = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:-15];
  82. NSLayoutConstraint *layD = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1 constant:70];
  83. NSLayoutConstraint *layE = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:60];
  84. [self addConstraints:@[layA, layB, layC, layD, layE]];
  85. [super updateConstraints];
  86. }
  87. - (void)layoutSubviews {
  88. [super layoutSubviews];
  89. [self startAnimation];
  90. }
  91. #pragma mark - animation
  92. - (void)showWithText:(NSString *)text type:(YBIBToastType)type {
  93. self.textLabel.text = text;
  94. _type = type;
  95. [self setNeedsLayout];
  96. }
  97. - (void)startAnimation {
  98. if (_shapeLayer && _shapeLayer.superlayer) {
  99. [_shapeLayer removeFromSuperlayer];
  100. }
  101. _shapeLayer = [CAShapeLayer layer];
  102. _shapeLayer.strokeColor = [UIColor whiteColor].CGColor;
  103. _shapeLayer.fillColor = [UIColor clearColor].CGColor;
  104. _shapeLayer.lineWidth = 5.0;
  105. _shapeLayer.lineCap = @"round";
  106. _shapeLayer.lineJoin = @"round";
  107. _shapeLayer.strokeStart = 0.0;
  108. _shapeLayer.strokeEnd = 0.0;
  109. UIBezierPath *bezierPath = [UIBezierPath bezierPath];
  110. CGFloat r = 13.0;
  111. CGFloat x = self.bounds.size.width / 2.0;
  112. CGFloat y = 38.0;
  113. switch (_type) {
  114. case YBIBToastTypeHook: {
  115. [bezierPath moveToPoint:CGPointMake(x - r - r / 2, y)];
  116. [bezierPath addLineToPoint:CGPointMake(x - r / 2, y + r)];
  117. [bezierPath addLineToPoint:CGPointMake(x + r * 2 - r / 2, y - r)];
  118. }
  119. break;
  120. case YBIBToastTypeFork: {
  121. [bezierPath moveToPoint:CGPointMake(x - r, y - r)];
  122. [bezierPath addLineToPoint:CGPointMake(x + r, y + r)];
  123. [bezierPath moveToPoint:CGPointMake(x - r, y + r)];
  124. [bezierPath addLineToPoint:CGPointMake(x + r, y - r)];
  125. }
  126. break;
  127. default:break;
  128. }
  129. CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
  130. [baseAnimation setFromValue:@0.0];
  131. [baseAnimation setToValue:@1.0];
  132. [baseAnimation setDuration:0.3];
  133. baseAnimation.removedOnCompletion = NO;
  134. baseAnimation.fillMode = kCAFillModeBoth;
  135. _shapeLayer.path = bezierPath.CGPath;
  136. [self.layer addSublayer:_shapeLayer];
  137. [_shapeLayer addAnimation:baseAnimation forKey:@"strokeEnd"];
  138. }
  139. #pragma mark - getter
  140. - (UILabel *)textLabel {
  141. if (!_textLabel) {
  142. _textLabel = [UILabel new];
  143. _textLabel.textColor = [UIColor whiteColor];
  144. _textLabel.font = [UIFont systemFontOfSize:14];
  145. _textLabel.textAlignment = NSTextAlignmentCenter;
  146. _textLabel.numberOfLines = 0;
  147. }
  148. return _textLabel;
  149. }
  150. @end