XYLabelAnimation.m 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. //
  2. // XYLabelAnimation.m
  3. // Starbuds
  4. //
  5. // Created by 翟玉磊 on 2020/3/11.
  6. // Copyright © 2020 翟玉磊. All rights reserved.
  7. //
  8. #import "XYLabelAnimation.h"
  9. #import "YLSingleText.h"
  10. @interface XYLabelAnimation ()
  11. @property (nonatomic, strong) NSMutableArray <YLSingleText *>*allText;
  12. @property (nonatomic, strong) CADisplayLink *time;
  13. @property (nonatomic, assign) int loopCount;
  14. @property (nonatomic, assign) int steps;
  15. @end
  16. @implementation XYLabelAnimation
  17. @synthesize text = _text;
  18. @synthesize attributedText = _attributedText;
  19. - (instancetype)initWithCoder:(NSCoder *)coder
  20. {
  21. self = [super initWithCoder:coder];
  22. if (self) {
  23. [self prepare];
  24. [self setNeedsDisplay];
  25. }
  26. return self;
  27. }
  28. - (instancetype)initWithFrame:(CGRect)frame attributedText:(NSAttributedString *)attributedText
  29. {
  30. self = [super initWithFrame:frame];
  31. if (self) {
  32. [self prepare];
  33. self.attributedText = attributedText;
  34. }
  35. return self;
  36. }
  37. - (instancetype)initWithFrame:(CGRect)frame text:(NSString *)text
  38. {
  39. self = [super initWithFrame:frame];
  40. if (self) {
  41. [self prepare];
  42. self.text = text;
  43. }
  44. return self;
  45. }
  46. - (void)prepare
  47. {
  48. self.loopCount = -1;
  49. }
  50. - (void)sizeToFit
  51. {
  52. [self setFrame:({
  53. CGFloat x = self.frame.origin.x;
  54. CGFloat y = self.frame.origin.y;
  55. CGFloat width = self.kerning * self.allText.count;
  56. CGFloat height = self.font.ascender - self.font.descender + self.animationHeight;
  57. CGRectMake(x, y, width, height);
  58. })];
  59. }
  60. - (void)start
  61. {
  62. self.steps = 0;
  63. self.steps ++;
  64. if (self.steps % 3 == 0 || self.steps % 3 == 1 ) {
  65. [self setNeedsDisplay];
  66. }
  67. if (self.steps > 1000) {
  68. self.steps = 0;
  69. }
  70. }
  71. - (void)startAnimation
  72. {
  73. [self.time invalidate];
  74. self.time = [CADisplayLink displayLinkWithTarget:self selector:@selector(start)];
  75. [self.time addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
  76. }
  77. - (void)pauseAnimation
  78. {
  79. [self.time invalidate];
  80. self.time = nil;
  81. }
  82. - (void)stopAnimation
  83. {
  84. [self pauseAnimation];
  85. self.loopCount = -1;
  86. [self.allText makeObjectsPerformSelector:@selector(normalReset)];
  87. [self.allText makeObjectsPerformSelector:@selector(waveReset)];
  88. [self setNeedsDisplay];
  89. }
  90. - (void)drawRect:(CGRect)rect {
  91. __block CGFloat x = 0;
  92. __weak typeof(self) weakSelf = self;
  93. [self.allText enumerateObjectsUsingBlock:^(YLSingleText *singleText, NSUInteger idx, BOOL *stop) {
  94. CGFloat location = 0;
  95. // 仅仅在能第一次遍历玩所有的文字的时候调用
  96. if (self.loopCount == idx * weakSelf.rate) {
  97. location = [singleText locationWithFirstEnumerate];
  98. }else{
  99. // 让其他的文字在一开始的时候不要动
  100. location = 0;
  101. }
  102. // 已经被遍历过的标志
  103. if (singleText.enumerated) {
  104. // 判断动画模式
  105. if (weakSelf.type) {
  106. location = [singleText locationWithWaveAnimationCompletion:^{
  107. if (idx == weakSelf.allText.count - 1) {
  108. [weakSelf.allText makeObjectsPerformSelector:@selector(waveReset)];
  109. self.loopCount = -1;
  110. }
  111. }];
  112. } else {
  113. location = [singleText locationWithNormalAnimation];
  114. }
  115. }
  116. CGFloat trueLocation = weakSelf.animationHeight - location;
  117. CGRect trueRect = CGRectMake(x, trueLocation, weakSelf.textSize, weakSelf.textSize);
  118. NSMutableDictionary *attibutes = [NSMutableDictionary dictionary];
  119. attibutes[NSFontAttributeName] = weakSelf.font;
  120. attibutes[NSForegroundColorAttributeName] = singleText.textColor;
  121. [singleText.text drawInRect:trueRect withAttributes:attibutes];
  122. x += weakSelf.kerning;
  123. }];
  124. self.loopCount ++;
  125. }
  126. #pragma mark -
  127. #pragma mark setter && getter
  128. - (CGFloat)textSize
  129. {
  130. return self.font.pointSize + self.animationHeight;
  131. }
  132. - (void)setText:(NSString *)text
  133. {
  134. _text = text;
  135. [self.allText removeAllObjects];
  136. for (int i = 0; i < text.length; ++i) {
  137. YLSingleText *singleText = [YLSingleText singleTextWithAnimationRange: text.length];
  138. singleText.text = [text substringWithRange:NSMakeRange(i, 1)];
  139. singleText.textColor = self.textColor;
  140. [self.allText addObject:singleText];
  141. }
  142. [self sizeToFit];
  143. [self setNeedsDisplay];
  144. }
  145. - (void)setAttributedText:(NSAttributedString *)attributedText
  146. {
  147. [super setAttributedText:attributedText];
  148. [self.allText removeAllObjects];
  149. for (int i = 0; i < attributedText.length; ++i) {
  150. YLSingleText *singleText = [YLSingleText singleTextWithAnimationRange: attributedText.length];
  151. singleText.text = [attributedText.string substringWithRange:NSMakeRange(i, 1)];
  152. NSDictionary *attributed = [attributedText attributesAtIndex:i effectiveRange:nil];
  153. singleText.textColor = attributed[NSForegroundColorAttributeName];
  154. [self.allText addObject:singleText];
  155. }
  156. [self sizeToFit];
  157. [self setNeedsDisplay];
  158. }
  159. - (void)setType:(XYLabelAnimationType)type
  160. {
  161. _type = type;
  162. self.loopCount = -1;
  163. [self.allText makeObjectsPerformSelector:@selector(normalReset)];
  164. [self.allText makeObjectsPerformSelector:@selector(waveReset)];
  165. }
  166. - (CGFloat)kerning
  167. {
  168. return _kerning + self.font.pointSize;
  169. }
  170. - (NSUInteger)rate
  171. {
  172. if (!_rate) {
  173. _rate = 2;
  174. }
  175. if (_rate < 1) {
  176. _rate = 1;
  177. }
  178. if (_rate > 10) {
  179. _rate = 10;
  180. }
  181. return _rate;
  182. }
  183. //- (UIFont *)font
  184. //{
  185. // if (![super font]) {
  186. // return [UIFont systemFontOfSize:15];
  187. // }
  188. // return [super font];
  189. //}
  190. @synthesize animationHeight = _animationHeight;
  191. - (void)setAnimationHeight:(CGFloat)animationHeight
  192. {
  193. _animationHeight = animationHeight + self.font.pointSize;
  194. }
  195. - (CGFloat)animationHeight
  196. {
  197. if (!_animationHeight) {
  198. _animationHeight = self.font.pointSize;
  199. }
  200. return _animationHeight;
  201. }
  202. - (NSMutableArray<YLSingleText *> *)allText
  203. {
  204. if (!_allText) {
  205. _allText = [@[] mutableCopy];
  206. }
  207. return _allText;
  208. }
  209. @end