CCZTrotingView.m 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. //
  2. // CCZTrotingView.m
  3. // CCZTrotView
  4. //
  5. // Created by 金峰 on 16/9/22.
  6. // Copyright © 2016年 金峰. All rights reserved.
  7. //
  8. #import "CCZTrotingView.h"
  9. typedef void(^trotingBlock)();
  10. @interface CCZTrotingView ()<CAAnimationDelegate>
  11. @property (nonatomic, assign) CGSize size;
  12. @property (nonatomic, strong) UIImageView *backgroundImageView;
  13. @property (nonatomic, strong) CAKeyframeAnimation *trotingXAnimation;
  14. @property (nonatomic, strong) CAKeyframeAnimation *trotingYAnimation;
  15. @property (nonatomic, strong) NSMutableArray *trotViewArr; /**< 用于存放待滚动的view的*/
  16. @property (nonatomic, copy) trotingBlock stopBlock;
  17. @property (nonatomic, copy) trotingBlock startBlock;
  18. @property (nonatomic, copy) trotingBlock trotingBlock;
  19. @end
  20. @implementation CCZTrotingView
  21. - (instancetype)initWithFrame:(CGRect)frame {
  22. self = [super initWithFrame:frame];
  23. if (self) {
  24. [self __basicSetting];
  25. [self __pageSetting];
  26. }
  27. return self;
  28. }
  29. - (instancetype)init {
  30. self = [super init];
  31. if (self) {
  32. [self __basicSetting];
  33. [self __pageSetting];
  34. }
  35. return self;
  36. }
  37. - (void)__basicSetting {
  38. self.backgroundColor = [UIColor whiteColor];
  39. _direction = CCZTrotDirectionLeft; // 从最右侧滚入,左侧滑出
  40. _duration = 10;
  41. _pause = 0.0;
  42. _autoTrotingRepeat = NO;
  43. _isTroting = NO;
  44. _hideWhenStopTroting = NO;
  45. _trotViewArr = [NSMutableArray arrayWithCapacity:1];
  46. }
  47. - (void)__pageSetting {
  48. _backgroundImageView = [[UIImageView alloc] init];
  49. _backgroundImageView.userInteractionEnabled = YES;
  50. [self addSubview:_backgroundImageView];
  51. _trotContaierView = [[UIView alloc] init];
  52. _trotContaierView.clipsToBounds = YES;
  53. [self addSubview:_trotContaierView];
  54. }
  55. - (void)layoutSubviews {
  56. _size = self.frame.size;
  57. _backgroundImageView.frame = self.bounds;
  58. if (self.leftView) {
  59. CGSize leftSize = self.leftView.frame.size;
  60. self.leftView.frame = CGRectMake(10, (_size.height - leftSize.height) / 2, leftSize.width, leftSize.height);
  61. }
  62. if (self.rightView) {
  63. CGSize rightSize = self.rightView.frame.size;
  64. self.rightView.frame = CGRectMake(_size.width - rightSize.width, (_size.height - rightSize.height) / 2, rightSize.width, rightSize.height);
  65. }
  66. self.trotContaierView.frame = CGRectMake(CGRectGetMaxX(self.leftView.frame), 0, _size.width - CGRectGetWidth(self.leftView.frame) - CGRectGetWidth(self.rightView.frame), _size.height);
  67. // initialize trot frame
  68. CGSize trotContainerSize = self.trotContaierView.frame.size;
  69. UIView *trotView = [self.trotViewArr firstObject];
  70. self.currentTrotView = trotView;
  71. CGSize trotSize = trotView.frame.size;
  72. if (!trotView) {
  73. return;
  74. }
  75. self.hidden = NO;
  76. if (self.trotingBlock) {
  77. self.trotingBlock();
  78. }
  79. if (_direction == CCZTrotDirectionLeft) {
  80. trotView.frame = CGRectMake(trotContainerSize.width, (_size.height - trotSize.height) / 2, trotSize.width, trotSize.height);
  81. CGFloat l = (trotContainerSize.width + trotSize.width);
  82. CGFloat v = l / _duration;
  83. self.trotingXAnimation.values = @[@(0), @(- trotContainerSize.width), @(- trotContainerSize.width), @(- l)];
  84. self.trotingXAnimation.keyTimes = @[@0, @(trotContainerSize.width / v / (_duration + _pause)), @(_pause / (_duration + _pause) + trotContainerSize.width / v / (_duration + _pause)), @(1)];
  85. } else if (_direction == CCZTrotDirectionRight) {
  86. trotView.frame = CGRectMake(- trotSize.width, (_size.height - trotSize.height) / 2, trotSize.width, trotSize.height);
  87. CGFloat l = (trotContainerSize.width + trotSize.width);
  88. CGFloat v = l / _duration;
  89. self.trotingXAnimation.values = @[@(0), @(trotContainerSize.width), @(trotContainerSize.width), @(l)];
  90. self.trotingXAnimation.keyTimes = @[@0, @(trotContainerSize.width / v / (_duration + _pause)), @(_pause / (_duration + _pause) + trotContainerSize.width / v / (_duration + _pause)), @(1)];
  91. } else if (_direction == CCZTrotDirectionTop) {
  92. trotView.frame = CGRectMake(0, trotContainerSize.height, trotSize.width, trotSize.height);
  93. CGFloat l = (trotContainerSize.height + trotSize.height);
  94. CGFloat v = l / _duration;
  95. self.trotingYAnimation.values = @[@(0), @(- ((trotContainerSize.height - trotSize.height) / 2 + trotSize.height)), @(- ((trotContainerSize.height - trotSize.height) / 2 + trotSize.height)), @(- l)];
  96. self.trotingYAnimation.keyTimes = @[@0, @(trotContainerSize.height / v / (_duration + _pause)), @(_pause / (_duration + _pause) + trotContainerSize.height / v / (_duration + _pause)), @(1)];
  97. } else {
  98. trotView.frame = CGRectMake(0, - trotSize.height, trotSize.width, trotSize.height);
  99. CGFloat l = (trotContainerSize.height + trotSize.height);
  100. CGFloat v = l / _duration;
  101. self.trotingYAnimation.values = @[@(0), @((trotContainerSize.height - trotSize.height) / 2 + trotSize.height), @((trotContainerSize.height - trotSize.height) / 2 + trotSize.height), @(l)];
  102. self.trotingYAnimation.keyTimes = @[@0, @(trotContainerSize.height / v / (_duration + _pause)), @(_pause / (_duration + _pause) + trotContainerSize.height / v / (_duration + _pause)), @(1)];
  103. }
  104. if ([trotView.layer animationForKey:@"trotingX"]) {
  105. [trotView.layer removeAnimationForKey:@"trotingX"];
  106. }
  107. if ([trotView.layer animationForKey:@"trotingY"]) {
  108. [trotView.layer removeAnimationForKey:@"trotingY"];
  109. }
  110. if (_direction == CCZTrotDirectionLeft || _direction == CCZTrotDirectionRight) {
  111. self.trotingXAnimation.removedOnCompletion = _autoTrotingRepeat;
  112. self.trotingXAnimation.repeatCount = _autoTrotingRepeat? CGFLOAT_MAX : 0;
  113. [trotView.layer addAnimation:self.trotingXAnimation forKey:@"trotingX"];
  114. } else {
  115. self.trotingYAnimation.removedOnCompletion = _autoTrotingRepeat;
  116. self.trotingYAnimation.repeatCount = _autoTrotingRepeat? CGFLOAT_MAX : 0;
  117. [trotView.layer addAnimation:self.trotingYAnimation forKey:@"trotingY"];
  118. }
  119. }
  120. - (CAKeyframeAnimation *)trotingXAnimation {
  121. if (!_trotingXAnimation) {
  122. _trotingXAnimation = [CAKeyframeAnimation animation];
  123. _trotingXAnimation.keyPath = @"transform.translation.x";
  124. _trotingXAnimation.delegate = self;
  125. _trotingXAnimation.duration = _duration;
  126. _trotingXAnimation.fillMode = kCAFillModeForwards;
  127. _trotingXAnimation.removedOnCompletion = NO;
  128. }
  129. return _trotingXAnimation;
  130. }
  131. - (CAKeyframeAnimation *)trotingYAnimation {
  132. if (!_trotingYAnimation) {
  133. _trotingYAnimation = [CAKeyframeAnimation animation];
  134. _trotingYAnimation.keyPath = @"transform.translation.y";
  135. _trotingYAnimation.delegate = self;
  136. _trotingYAnimation.duration = _duration;
  137. _trotingYAnimation.fillMode = kCAFillModeForwards;
  138. _trotingYAnimation.removedOnCompletion = NO;
  139. }
  140. return _trotingYAnimation;
  141. }
  142. #pragma mark -- public
  143. - (void)addTrotView:(UIView *)trotView {
  144. if (self.currentTrotView) {
  145. [self.trotViewArr removeObject:self.trotViewArr.firstObject];
  146. [self.currentTrotView removeFromSuperview];
  147. }
  148. [self.trotViewArr addObject:trotView];
  149. [self.trotContaierView addSubview:trotView];
  150. if (!_isTroting) {
  151. [self setNeedsLayout];
  152. }
  153. }
  154. - (void)trotingStop:(void (^)())stopBlock {
  155. if (stopBlock) {
  156. self.stopBlock = stopBlock;
  157. }
  158. }
  159. - (void)trotingStart:(void (^)())startBlcok {
  160. if (startBlcok) {
  161. self.startBlock = startBlcok;
  162. }
  163. }
  164. - (void)troting:(void (^)())trotingBlock {
  165. if (trotingBlock) {
  166. self.trotingBlock = trotingBlock;
  167. }
  168. }
  169. - (void)updateTroting {
  170. [self setNeedsLayout];
  171. }
  172. #pragma mark -- Set
  173. - (void)setBackgroundImage:(UIImage *)backgroundImage {
  174. _backgroundImage = backgroundImage;
  175. self.backgroundImageView.image = backgroundImage;
  176. }
  177. - (void)setLeftView:(UIView *)leftView {
  178. _leftView = leftView;
  179. [self addSubview:leftView];
  180. }
  181. - (void)setRightView:(UIView *)rightView {
  182. _rightView = rightView;
  183. [self addSubview:_rightView];
  184. }
  185. - (void)setDuration:(NSTimeInterval)duration {
  186. _duration = duration;
  187. self.trotingXAnimation.duration = duration;
  188. }
  189. - (void)setHideWhenStopTroting:(BOOL)hideWhenStopTroting {
  190. _hideWhenStopTroting = hideWhenStopTroting;
  191. self.hidden = hideWhenStopTroting;
  192. }
  193. #pragma mark -- Animation delegate
  194. - (void)animationDidStart:(CAAnimation *)anim {
  195. _isTroting = YES;
  196. if (self.startBlock) {
  197. self.startBlock();
  198. }
  199. }
  200. - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
  201. _isTroting = NO;
  202. self.hidden = self.hideWhenStopTroting;
  203. if (self.stopBlock) {
  204. self.stopBlock();
  205. }
  206. }
  207. @end