MORingCountdownView.m 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. //
  2. // MORingCountdownView.m
  3. // MiMoLive
  4. //
  5. // Created by MiMo on 2025/7/27.
  6. //
  7. #import "MORingCountdownView.h"
  8. @interface MORingCountdownView ()<CAAnimationDelegate>
  9. @property (nonatomic, strong) CAShapeLayer *backgroundLayer;
  10. @property (nonatomic, strong) CAShapeLayer *progressLayer;
  11. @property (nonatomic, strong) CAGradientLayer *gradientLayer;
  12. @property (nonatomic, assign) CFTimeInterval animationStartTime;
  13. @property (nonatomic, assign) NSTimeInterval animationDuration;
  14. @end
  15. @implementation MORingCountdownView
  16. - (instancetype)initWithFrame:(CGRect)frame {
  17. if (self = [super initWithFrame:frame]) {
  18. _lineWidth = 2.0;
  19. _ringColor = [MOTools colorWithHexString:@"#FFD74A"];
  20. _backgroundRingColor = [UIColor whiteColor];
  21. [self setupLayers];
  22. }
  23. return self;
  24. }
  25. - (void)setupLayers {
  26. CGFloat lineWidth = self.lineWidth;
  27. CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
  28. CGFloat radius = (MIN(self.bounds.size.width, self.bounds.size.height) - lineWidth) / 2.0;
  29. UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center
  30. radius:radius
  31. startAngle:-M_PI_2
  32. endAngle:(3 * M_PI_2)
  33. clockwise:YES];
  34. // 背景渐变遮罩层路径
  35. self.backgroundLayer = [CAShapeLayer layer];
  36. self.backgroundLayer.path = circlePath.CGPath;
  37. self.backgroundLayer.strokeColor = self.backgroundRingColor.CGColor;
  38. self.backgroundLayer.fillColor = UIColor.clearColor.CGColor;
  39. self.backgroundLayer.lineWidth = lineWidth;
  40. // 创建渐变背景图层
  41. self.gradientLayer = [CAGradientLayer layer];
  42. self.gradientLayer.frame = self.bounds;
  43. self.gradientLayer.colors = @[
  44. (__bridge id)[MOTools colorWithHexString:@"#FFF0C7" alpha:0.0].CGColor,
  45. (__bridge id)[MOTools colorWithHexString:@"#FFF0C7" alpha:0.0].CGColor
  46. ];
  47. self.gradientLayer.startPoint = CGPointMake(0.5, 0.13);
  48. self.gradientLayer.endPoint = CGPointMake(0.5, 1.0);
  49. self.gradientLayer.locations = @[@(0), @(1.0)];
  50. self.gradientLayer.mask = self.backgroundLayer;
  51. [self.layer addSublayer:self.gradientLayer];
  52. // 进度图层
  53. self.progressLayer = [CAShapeLayer layer];
  54. self.progressLayer.path = circlePath.CGPath;
  55. // self.progressLayer.strokeColor = [MOTools colorWithHexString:@"#FFD74A"].CGColor; // #FFD74A
  56. self.progressLayer.strokeColor = self.ringColor.CGColor;
  57. self.progressLayer.fillColor = UIColor.clearColor.CGColor;
  58. self.progressLayer.lineWidth = lineWidth;
  59. self.progressLayer.lineCap = kCALineCapRound;
  60. self.progressLayer.strokeStart = 0;
  61. self.progressLayer.strokeEnd = 1;
  62. [self.layer addSublayer:self.progressLayer];
  63. }
  64. - (void)reloadAppearance {
  65. [self.backgroundLayer removeFromSuperlayer];
  66. [self.progressLayer removeFromSuperlayer];
  67. [self.gradientLayer removeFromSuperlayer];
  68. [self setupLayers];
  69. }
  70. - (void)startCountdownWithDuration:(NSTimeInterval)duration {
  71. [self.progressLayer removeAllAnimations];
  72. self.animationStartTime = CACurrentMediaTime(); // 记录开始时间
  73. self.animationDuration = duration;
  74. self.progressLayer.strokeStart = 0;
  75. self.progressLayer.strokeEnd = 1;
  76. CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
  77. anim.duration = duration;
  78. anim.fromValue = @(0.0);
  79. anim.toValue = @(1.0);
  80. anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
  81. anim.fillMode = kCAFillModeForwards;
  82. anim.removedOnCompletion = NO;
  83. anim.delegate = self;
  84. [self.progressLayer addAnimation:anim forKey:@"ringCountdown"];
  85. }
  86. - (NSTimeInterval)elapsedAnimationTime {
  87. return CACurrentMediaTime() - self.animationStartTime;
  88. }
  89. // 遵守 <CAAnimationDelegate>
  90. - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
  91. if (flag) {
  92. MOLogV(@"动画完成");
  93. [self stopCountdown];
  94. }
  95. }
  96. - (void)stopCountdown {
  97. [_progressLayer removeAnimationForKey:@"ringCountdown"];
  98. if (self.stopBlock) {
  99. self.stopBlock();
  100. }
  101. }
  102. @end