WMProgressView.m 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. //
  2. // WMProgressView.m
  3. // WMPageController
  4. //
  5. // Created by Mark on 15/6/20.
  6. // Copyright (c) 2015年 yq. All rights reserved.
  7. //
  8. #import "WMProgressView.h"
  9. @implementation WMProgressView {
  10. int _sign;
  11. CGFloat _gap;
  12. CGFloat _step;
  13. __weak CADisplayLink *_link;
  14. }
  15. - (CGFloat)speedFactor {
  16. if (_speedFactor <= 0) {
  17. _speedFactor = 15.0;
  18. }
  19. return _speedFactor;
  20. }
  21. - (void)setProgressWithOutAnimate:(CGFloat)progress {
  22. if (self.progress == progress) return;
  23. _progress = progress;
  24. [self setNeedsDisplay];
  25. }
  26. - (void)setNaughty:(BOOL)naughty {
  27. _naughty = naughty;
  28. [self setNeedsDisplay];
  29. }
  30. - (void)setCornerRadius:(CGFloat)cornerRadius {
  31. _cornerRadius = cornerRadius;
  32. [self setNeedsDisplay];
  33. }
  34. - (void)moveToPostion:(NSInteger)pos {
  35. _gap = fabs(self.progress - pos);
  36. _sign = self.progress > pos ? -1 : 1;
  37. _step = _gap / self.speedFactor;
  38. if (_link) {
  39. [_link invalidate];
  40. [_link removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
  41. }
  42. CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(progressChanged)];
  43. [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
  44. _link = link;
  45. }
  46. - (void)setProgress:(CGFloat)progress {
  47. if (self.progress == progress) return;
  48. _progress = progress;
  49. [self setNeedsDisplay];
  50. }
  51. - (void)progressChanged {
  52. if (_gap > 0.000001) {
  53. _gap -= _step;
  54. if (_gap < 0.0) {
  55. self.progress = (int)(self.progress + _sign * _step + 0.5);
  56. return;
  57. }
  58. self.progress += _sign * _step;
  59. } else {
  60. self.progress = (int)(self.progress + 0.5);
  61. [_link invalidate];
  62. _link = nil;
  63. }
  64. }
  65. - (void)drawRect:(CGRect)rect {
  66. // Drawing code
  67. [super drawRect:rect];
  68. CGContextRef ctx = UIGraphicsGetCurrentContext();
  69. CGFloat height = self.frame.size.height;
  70. int index = (int)self.progress;
  71. index = (index <= self.itemFrames.count - 1) ? index : (int)self.itemFrames.count - 1;
  72. CGFloat rate = self.progress - index;
  73. CGRect currentFrame = [self.itemFrames[index] CGRectValue];
  74. CGFloat currentWidth = currentFrame.size.width;
  75. int nextIndex = index + 1 < self.itemFrames.count ? index + 1 : index;
  76. CGFloat nextWidth = [self.itemFrames[nextIndex] CGRectValue].size.width;
  77. CGFloat currentX = currentFrame.origin.x;
  78. CGFloat nextX = [self.itemFrames[nextIndex] CGRectValue].origin.x;
  79. CGFloat startX = currentX + (nextX - currentX) * rate;
  80. CGFloat width = currentWidth + (nextWidth - currentWidth)*rate;
  81. CGFloat endX = startX + width;
  82. if (self.naughty) {
  83. CGFloat currentMidX = currentX + currentWidth / 2.0;
  84. CGFloat nextMidX = nextX + nextWidth / 2.0;
  85. if (rate <= 0.5) {
  86. startX = currentX + (currentMidX - currentX) * rate * 2.0;
  87. CGFloat currentMaxX = currentX + currentWidth;
  88. endX = currentMaxX + (nextMidX - currentMaxX) * rate * 2.0;
  89. } else {
  90. startX = currentMidX + (nextX - currentMidX) * (rate - 0.5) * 2.0;
  91. CGFloat nextMaxX = nextX + nextWidth;
  92. endX = nextMidX + (nextMaxX - nextMidX) * (rate - 0.5) * 2.0;
  93. }
  94. width = endX - startX;
  95. }
  96. CGFloat lineWidth = (self.hollow || self.hasBorder) ? 1.0 : 0.0;
  97. if (self.isTriangle) {
  98. CGContextMoveToPoint(ctx, startX, height);
  99. CGContextAddLineToPoint(ctx, endX, height);
  100. CGContextAddLineToPoint(ctx, startX + width / 2.0, 0);
  101. CGContextClosePath(ctx);
  102. CGContextSetFillColorWithColor(ctx, self.color);
  103. CGContextFillPath(ctx);
  104. return;
  105. }
  106. UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(startX, lineWidth / 2.0, width, height - lineWidth) cornerRadius:self.cornerRadius];
  107. CGContextAddPath(ctx, path.CGPath);
  108. if (self.hollow) {
  109. CGContextSetStrokeColorWithColor(ctx, self.color);
  110. CGContextStrokePath(ctx);
  111. return;
  112. }
  113. CGContextSetFillColorWithColor(ctx, self.color);
  114. CGContextFillPath(ctx);
  115. if (self.hasBorder) {
  116. // 计算点
  117. CGFloat startX = CGRectGetMinX([self.itemFrames.firstObject CGRectValue]);
  118. CGFloat endX = CGRectGetMaxX([self.itemFrames.lastObject CGRectValue]);
  119. UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(startX, lineWidth / 2.0, (endX - startX), height - lineWidth) cornerRadius:self.cornerRadius];
  120. CGContextSetLineWidth(ctx, lineWidth);
  121. CGContextAddPath(ctx, path.CGPath);
  122. // 绘制
  123. CGContextSetStrokeColorWithColor(ctx, self.color);
  124. CGContextStrokePath(ctx);
  125. }
  126. }
  127. @end