SVGABezierPath.m 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. //
  2. // SVGABezierPath.m
  3. // SVGAPlayer
  4. //
  5. // Created by 崔明辉 on 16/6/28.
  6. // Copyright © 2016年 UED Center. All rights reserved.
  7. //
  8. #import "SVGABezierPath.h"
  9. @interface SVGABezierPath ()
  10. @property (nonatomic, assign) BOOL displaying;
  11. @property (nonatomic, copy) NSString *backValues;
  12. @end
  13. @implementation SVGABezierPath
  14. - (void)setValues:(nonnull NSString *)values {
  15. if (!self.displaying) {
  16. self.backValues = values;
  17. return;
  18. }
  19. static NSSet *validMethods;
  20. static dispatch_once_t onceToken;
  21. dispatch_once(&onceToken, ^{
  22. validMethods = [NSSet setWithArray:@[@"M",@"L",@"H",@"V",@"C",@"S",@"Q",@"R",@"A",@"Z",@"m",@"l",@"h",@"v",@"c",@"s",@"q",@"r",@"a",@"z"]];
  23. });
  24. values = [values stringByReplacingOccurrencesOfString:@"([a-zA-Z])" withString:@"|||$1 " options:NSRegularExpressionSearch range:NSMakeRange(0, values.length)];
  25. values = [values stringByReplacingOccurrencesOfString:@"," withString:@" "];
  26. NSArray<NSString *> *segments = [values componentsSeparatedByString:@"|||"];
  27. for (NSString *segment in segments) {
  28. if (segment.length == 0) {
  29. continue;
  30. }
  31. NSString *firstLetter = [segment substringToIndex:1];
  32. if ([validMethods containsObject:firstLetter]) {
  33. NSArray *args = [[[segment substringFromIndex:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsSeparatedByString:@" "];
  34. [self operate:firstLetter args:args];
  35. }
  36. }
  37. }
  38. - (nonnull CAShapeLayer *)createLayer {
  39. if (!self.displaying) {
  40. self.displaying = YES;
  41. [self setValues:self.backValues];
  42. }
  43. CAShapeLayer *layer = [CAShapeLayer layer];
  44. layer.path = self.CGPath;
  45. layer.fillColor = [UIColor blackColor].CGColor;
  46. return layer;
  47. }
  48. - (void)operate:(NSString *)method args:(NSArray<NSString *> *)args {
  49. if (([method isEqualToString:@"M"] || [method isEqualToString:@"m"]) && args.count == 2) {
  50. CGPoint iPoint = [self argPoint:CGPointMake([args[0] floatValue], [args[1] floatValue]) relative:[method isEqualToString:@"m"]];
  51. if (!CGPointEqualToPoint(iPoint, CGPointMake(CGFLOAT_MIN, CGFLOAT_MIN))) {
  52. [self moveToPoint:iPoint];
  53. }
  54. }
  55. else if (([method isEqualToString:@"L"] || [method isEqualToString:@"l"]) && args.count == 2) {
  56. CGPoint iPoint = [self argPoint:CGPointMake([args[0] floatValue], [args[1] floatValue]) relative:[method isEqualToString:@"l"]];
  57. if (!CGPointEqualToPoint(iPoint, CGPointMake(CGFLOAT_MIN, CGFLOAT_MIN))) {
  58. [self addLineToPoint:iPoint];
  59. }
  60. }
  61. else if (([method isEqualToString:@"C"] || [method isEqualToString:@"c"]) && args.count == 6) {
  62. CGPoint iPoint = [self argPoint:CGPointMake([args[0] floatValue], [args[1] floatValue]) relative:[method isEqualToString:@"c"]];
  63. CGPoint iiPoint = [self argPoint:CGPointMake([args[2] floatValue], [args[3] floatValue]) relative:[method isEqualToString:@"c"]];
  64. CGPoint iiiPoint = [self argPoint:CGPointMake([args[4] floatValue], [args[5] floatValue]) relative:[method isEqualToString:@"c"]];
  65. if (!CGPointEqualToPoint(iPoint, CGPointMake(CGFLOAT_MIN, CGFLOAT_MIN)) &&
  66. !CGPointEqualToPoint(iiPoint, CGPointMake(CGFLOAT_MIN, CGFLOAT_MIN)) &&
  67. !CGPointEqualToPoint(iiiPoint, CGPointMake(CGFLOAT_MIN, CGFLOAT_MIN))) {
  68. [self addCurveToPoint:iiiPoint controlPoint1:iPoint controlPoint2:iiPoint];
  69. }
  70. }
  71. else if (([method isEqualToString:@"Q"] || [method isEqualToString:@"q"]) && args.count == 4) {
  72. CGPoint iPoint = [self argPoint:CGPointMake([args[0] floatValue], [args[1] floatValue]) relative:[method isEqualToString:@"q"]];
  73. CGPoint iiPoint = [self argPoint:CGPointMake([args[2] floatValue], [args[3] floatValue]) relative:[method isEqualToString:@"q"]];
  74. if (!CGPointEqualToPoint(iPoint, CGPointMake(CGFLOAT_MIN, CGFLOAT_MIN)) &&
  75. !CGPointEqualToPoint(iiPoint, CGPointMake(CGFLOAT_MIN, CGFLOAT_MIN))) {
  76. [self addQuadCurveToPoint:iiPoint controlPoint:iPoint];
  77. }
  78. }
  79. else if (([method isEqualToString:@"H"] || [method isEqualToString:@"h"]) && args.count == 1) {
  80. CGFloat iValue = [self argFloat:args[0].floatValue relativeValue:([method isEqualToString:@"h"] ? self.currentPoint.x : 0.0)];
  81. if (iValue != CGFLOAT_MIN) {
  82. [self addLineToPoint:CGPointMake(iValue, self.currentPoint.y)];
  83. }
  84. }
  85. else if (([method isEqualToString:@"V"] || [method isEqualToString:@"v"]) && args.count == 1) {
  86. CGFloat iValue = [self argFloat:args[0].floatValue relativeValue:([method isEqualToString:@"v"] ? self.currentPoint.y : 0.0)];
  87. if (iValue != CGFLOAT_MIN) {
  88. [self addLineToPoint:CGPointMake(self.currentPoint.x, iValue)];
  89. }
  90. }
  91. else if (([method isEqualToString:@"Z"] || [method isEqualToString:@"z"])) {
  92. [self closePath];
  93. }
  94. }
  95. - (CGFloat)argFloat:(CGFloat)value relativeValue:(CGFloat)relativeValue {
  96. return value + relativeValue;
  97. }
  98. - (CGPoint)argPoint:(CGPoint)point relative:(BOOL)relative {
  99. if (relative) {
  100. return CGPointMake(point.x + self.currentPoint.x, point.y + self.currentPoint.y);
  101. }
  102. else {
  103. return point;
  104. }
  105. }
  106. @end