SVGAVectorLayer.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. //
  2. // SVGAVectorLayer.m
  3. // SVGAPlayer
  4. //
  5. // Created by 崔明辉 on 2017/2/20.
  6. // Copyright © 2017年 UED Center. All rights reserved.
  7. //
  8. #import "SVGAVectorLayer.h"
  9. #import "SVGABezierPath.h"
  10. #import "SVGAVideoSpriteFrameEntity.h"
  11. #import "Svga.pbobjc.h"
  12. @interface SVGAVectorLayer ()
  13. @property (nonatomic, strong) NSArray<SVGAVideoSpriteFrameEntity *> *frames;
  14. @property (nonatomic, assign) NSInteger drawedFrame;
  15. @property (nonatomic, strong) NSDictionary *keepFrameCache;
  16. @end
  17. @implementation SVGAVectorLayer
  18. - (instancetype)initWithFrames:(NSArray *)frames {
  19. self = [super init];
  20. if (self) {
  21. self.backgroundColor = [UIColor clearColor].CGColor;
  22. self.masksToBounds = NO;
  23. _frames = frames;
  24. _keepFrameCache = [NSMutableDictionary dictionary];
  25. [self resetKeepFrameCache];
  26. [self stepToFrame:0];
  27. }
  28. return self;
  29. }
  30. - (void)resetKeepFrameCache {
  31. __block NSInteger lastKeep = 0;
  32. __block NSMutableDictionary *keepFrameCache = [NSMutableDictionary dictionary];
  33. [self.frames enumerateObjectsUsingBlock:^(SVGAVideoSpriteFrameEntity * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  34. if (![self isKeepFrame:obj]) {
  35. lastKeep = idx;
  36. }
  37. else {
  38. [keepFrameCache setObject:@(lastKeep) forKey:@(idx)];
  39. }
  40. }];
  41. self.keepFrameCache = [keepFrameCache copy];
  42. }
  43. - (void)stepToFrame:(NSInteger)frame {
  44. if (frame < self.frames.count) {
  45. [self drawFrame:frame];
  46. }
  47. }
  48. - (BOOL)isKeepFrame:(SVGAVideoSpriteFrameEntity *)frameItem {
  49. if ([frameItem.shapes.firstObject isKindOfClass:[NSDictionary class]]) {
  50. return [frameItem.shapes.firstObject[@"type"] isKindOfClass:[NSString class]] &&
  51. [frameItem.shapes.firstObject[@"type"] isEqualToString:@"keep"];
  52. }
  53. else if ([frameItem.shapes.firstObject isKindOfClass:[SVGAProtoShapeEntity class]]) {
  54. return [(SVGAProtoShapeEntity *)frameItem.shapes.firstObject type] == SVGAProtoShapeEntity_ShapeType_Keep;
  55. }
  56. else {
  57. return NO;
  58. }
  59. }
  60. - (NSInteger)requestKeepFrame:(NSInteger)frame {
  61. if ([self.keepFrameCache objectForKey:@(frame)] != nil) {
  62. return [[self.keepFrameCache objectForKey:@(frame)] integerValue];
  63. }
  64. return NSNotFound;
  65. }
  66. - (void)drawFrame:(NSInteger)frame {
  67. if (frame < self.frames.count) {
  68. SVGAVideoSpriteFrameEntity *frameItem = self.frames[frame];
  69. if ([self isKeepFrame:frameItem]) {
  70. if (self.drawedFrame == [self requestKeepFrame:frame]) {
  71. return;
  72. }
  73. }
  74. [self.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
  75. for (NSDictionary *shape in frameItem.shapes) {
  76. if ([shape isKindOfClass:[NSDictionary class]]) {
  77. if ([shape[@"type"] isKindOfClass:[NSString class]]) {
  78. if ([shape[@"type"] isEqualToString:@"shape"]) {
  79. [self addSublayer:[self createCurveLayer:shape]];
  80. }
  81. else if ([shape[@"type"] isEqualToString:@"ellipse"]) {
  82. [self addSublayer:[self createEllipseLayer:shape]];
  83. }
  84. else if ([shape[@"type"] isEqualToString:@"rect"]) {
  85. [self addSublayer:[self createRectLayer:shape]];
  86. }
  87. }
  88. }
  89. else if ([shape isKindOfClass:[SVGAProtoShapeEntity class]]) {
  90. SVGAProtoShapeEntity *shapeItem = (id)shape;
  91. if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Shape) {
  92. [self addSublayer:[self createCurveLayerWithProto:shapeItem]];
  93. }
  94. else if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Ellipse) {
  95. [self addSublayer:[self createEllipseLayerWithProto:shapeItem]];
  96. }
  97. else if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Rect) {
  98. [self addSublayer:[self createRectLayerWithProto:shapeItem]];
  99. }
  100. }
  101. }
  102. self.drawedFrame = frame;
  103. }
  104. }
  105. - (CALayer *)createCurveLayer:(NSDictionary *)shape {
  106. SVGABezierPath *bezierPath = [SVGABezierPath new];
  107. if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
  108. if ([shape[@"args"][@"d"] isKindOfClass:[NSString class]]) {
  109. [bezierPath setValues:shape[@"args"][@"d"]];
  110. }
  111. }
  112. CAShapeLayer *shapeLayer = [bezierPath createLayer];
  113. [self resetStyles:shapeLayer shape:shape];
  114. [self resetTransform:shapeLayer shape:shape];
  115. return shapeLayer;
  116. }
  117. - (CALayer *)createCurveLayerWithProto:(SVGAProtoShapeEntity *)shape {
  118. SVGABezierPath *bezierPath = [SVGABezierPath new];
  119. if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Shape) {
  120. if ([shape.shape.d isKindOfClass:[NSString class]] && shape.shape.d.length > 0) {
  121. [bezierPath setValues:shape.shape.d];
  122. }
  123. }
  124. CAShapeLayer *shapeLayer = [bezierPath createLayer];
  125. [self resetStyles:shapeLayer protoShape:shape];
  126. [self resetTransform:shapeLayer protoShape:shape];
  127. return shapeLayer;
  128. }
  129. - (CALayer *)createEllipseLayer:(NSDictionary *)shape {
  130. UIBezierPath *bezierPath;
  131. if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
  132. if ([shape[@"args"][@"x"] isKindOfClass:[NSNumber class]] &&
  133. [shape[@"args"][@"y"] isKindOfClass:[NSNumber class]] &&
  134. [shape[@"args"][@"radiusX"] isKindOfClass:[NSNumber class]] &&
  135. [shape[@"args"][@"radiusY"] isKindOfClass:[NSNumber class]]) {
  136. CGFloat x = [shape[@"args"][@"x"] floatValue];
  137. CGFloat y = [shape[@"args"][@"y"] floatValue];
  138. CGFloat rx = [shape[@"args"][@"radiusX"] floatValue];
  139. CGFloat ry = [shape[@"args"][@"radiusY"] floatValue];
  140. bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x - rx, y - ry, rx * 2, ry * 2)];
  141. }
  142. }
  143. if (bezierPath != nil) {
  144. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  145. [shapeLayer setPath:[bezierPath CGPath]];
  146. [self resetStyles:shapeLayer shape:shape];
  147. [self resetTransform:shapeLayer shape:shape];
  148. return shapeLayer;
  149. }
  150. else {
  151. return [CALayer layer];
  152. }
  153. }
  154. - (CALayer *)createEllipseLayerWithProto:(SVGAProtoShapeEntity *)shape {
  155. UIBezierPath *bezierPath;
  156. if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Ellipse) {
  157. bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(shape.ellipse.x - shape.ellipse.radiusX,
  158. shape.ellipse.y - shape.ellipse.radiusY,
  159. shape.ellipse.radiusX * 2,
  160. shape.ellipse.radiusY * 2)];
  161. }
  162. if (bezierPath != nil) {
  163. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  164. [shapeLayer setPath:[bezierPath CGPath]];
  165. [self resetStyles:shapeLayer protoShape:shape];
  166. [self resetTransform:shapeLayer protoShape:shape];
  167. return shapeLayer;
  168. }
  169. else {
  170. return [CALayer layer];
  171. }
  172. }
  173. - (CALayer *)createRectLayer:(NSDictionary *)shape {
  174. UIBezierPath *bezierPath;
  175. if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
  176. if ([shape[@"args"][@"x"] isKindOfClass:[NSNumber class]] &&
  177. [shape[@"args"][@"y"] isKindOfClass:[NSNumber class]] &&
  178. [shape[@"args"][@"width"] isKindOfClass:[NSNumber class]] &&
  179. [shape[@"args"][@"height"] isKindOfClass:[NSNumber class]] &&
  180. [shape[@"args"][@"cornerRadius"] isKindOfClass:[NSNumber class]]) {
  181. CGFloat x = [shape[@"args"][@"x"] floatValue];
  182. CGFloat y = [shape[@"args"][@"y"] floatValue];
  183. CGFloat width = [shape[@"args"][@"width"] floatValue];
  184. CGFloat height = [shape[@"args"][@"height"] floatValue];
  185. CGFloat cornerRadius = [shape[@"args"][@"cornerRadius"] floatValue];
  186. bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x, y, width, height) cornerRadius:cornerRadius];
  187. }
  188. }
  189. if (bezierPath != nil) {
  190. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  191. [shapeLayer setPath:[bezierPath CGPath]];
  192. [self resetStyles:shapeLayer shape:shape];
  193. [self resetTransform:shapeLayer shape:shape];
  194. return shapeLayer;
  195. }
  196. else {
  197. return [CALayer layer];
  198. }
  199. }
  200. - (CALayer *)createRectLayerWithProto:(SVGAProtoShapeEntity *)shape {
  201. UIBezierPath *bezierPath;
  202. if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Rect) {
  203. bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(shape.rect.x, shape.rect.y, shape.rect.width, shape.rect.height)
  204. cornerRadius:shape.rect.cornerRadius];
  205. }
  206. if (bezierPath != nil) {
  207. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  208. [shapeLayer setPath:[bezierPath CGPath]];
  209. [self resetStyles:shapeLayer protoShape:shape];
  210. [self resetTransform:shapeLayer protoShape:shape];
  211. return shapeLayer;
  212. }
  213. else {
  214. return [CALayer layer];
  215. }
  216. }
  217. - (void)resetStyles:(CAShapeLayer *)shapeLayer shape:(NSDictionary *)shape {
  218. shapeLayer.masksToBounds = NO;
  219. shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
  220. if ([shape[@"styles"] isKindOfClass:[NSDictionary class]]) {
  221. if ([shape[@"styles"][@"fill"] isKindOfClass:[NSArray class]]) {
  222. NSArray *colorArray = shape[@"styles"][@"fill"];
  223. if ([colorArray count] == 4 &&
  224. [colorArray[0] isKindOfClass:[NSNumber class]] &&
  225. [colorArray[1] isKindOfClass:[NSNumber class]] &&
  226. [colorArray[2] isKindOfClass:[NSNumber class]] &&
  227. [colorArray[3] isKindOfClass:[NSNumber class]]) {
  228. shapeLayer.fillColor = [UIColor colorWithRed:[colorArray[0] floatValue]
  229. green:[colorArray[1] floatValue]
  230. blue:[colorArray[2] floatValue]
  231. alpha:[colorArray[3] floatValue]].CGColor;
  232. }
  233. }
  234. else {
  235. shapeLayer.fillColor = [UIColor clearColor].CGColor;
  236. }
  237. if ([shape[@"styles"][@"stroke"] isKindOfClass:[NSArray class]]) {
  238. NSArray *colorArray = shape[@"styles"][@"stroke"];
  239. if ([colorArray count] == 4 &&
  240. [colorArray[0] isKindOfClass:[NSNumber class]] &&
  241. [colorArray[1] isKindOfClass:[NSNumber class]] &&
  242. [colorArray[2] isKindOfClass:[NSNumber class]] &&
  243. [colorArray[3] isKindOfClass:[NSNumber class]]) {
  244. shapeLayer.strokeColor = [UIColor colorWithRed:[colorArray[0] floatValue]
  245. green:[colorArray[1] floatValue]
  246. blue:[colorArray[2] floatValue]
  247. alpha:[colorArray[3] floatValue]].CGColor;
  248. }
  249. }
  250. if ([shape[@"styles"][@"strokeWidth"] isKindOfClass:[NSNumber class]]) {
  251. shapeLayer.lineWidth = [shape[@"styles"][@"strokeWidth"] floatValue];
  252. }
  253. if ([shape[@"styles"][@"lineCap"] isKindOfClass:[NSString class]]) {
  254. shapeLayer.lineCap = shape[@"styles"][@"lineCap"];
  255. }
  256. if ([shape[@"styles"][@"lineJoin"] isKindOfClass:[NSString class]]) {
  257. shapeLayer.lineJoin = shape[@"styles"][@"lineJoin"];
  258. }
  259. if ([shape[@"styles"][@"lineDash"] isKindOfClass:[NSArray class]]) {
  260. BOOL accept = YES;
  261. for (id obj in shape[@"styles"][@"lineDash"]) {
  262. if (![obj isKindOfClass:[NSNumber class]]) {
  263. accept = NO;
  264. }
  265. }
  266. if (accept) {
  267. if ([shape[@"styles"][@"lineDash"] count] == 3) {
  268. shapeLayer.lineDashPhase = [shape[@"styles"][@"lineDash"][2] floatValue];
  269. shapeLayer.lineDashPattern = @[
  270. ([shape[@"styles"][@"lineDash"][0] floatValue] < 1.0 ? @(1.0) : shape[@"styles"][@"lineDash"][0]),
  271. ([shape[@"styles"][@"lineDash"][1] floatValue] < 0.1 ? @(0.1) : shape[@"styles"][@"lineDash"][1])
  272. ];
  273. }
  274. }
  275. }
  276. if ([shape[@"styles"][@"miterLimit"] isKindOfClass:[NSNumber class]]) {
  277. shapeLayer.miterLimit = [shape[@"styles"][@"miterLimit"] floatValue];
  278. }
  279. }
  280. }
  281. - (void)resetStyles:(CAShapeLayer *)shapeLayer protoShape:(SVGAProtoShapeEntity *)protoShape {
  282. shapeLayer.masksToBounds = NO;
  283. shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
  284. if (protoShape.hasStyles) {
  285. if (protoShape.styles.hasFill) {
  286. shapeLayer.fillColor = [UIColor colorWithRed:protoShape.styles.fill.r
  287. green:protoShape.styles.fill.g
  288. blue:protoShape.styles.fill.b
  289. alpha:protoShape.styles.fill.a].CGColor;
  290. }
  291. else {
  292. shapeLayer.fillColor = [UIColor clearColor].CGColor;
  293. }
  294. if (protoShape.styles.hasStroke) {
  295. shapeLayer.strokeColor = [UIColor colorWithRed:protoShape.styles.stroke.r
  296. green:protoShape.styles.stroke.g
  297. blue:protoShape.styles.stroke.b
  298. alpha:protoShape.styles.stroke.a].CGColor;
  299. }
  300. shapeLayer.lineWidth = protoShape.styles.strokeWidth;
  301. switch (protoShape.styles.lineCap) {
  302. case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapButt:
  303. shapeLayer.lineCap = @"butt";
  304. break;
  305. case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapRound:
  306. shapeLayer.lineCap = @"round";
  307. break;
  308. case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapSquare:
  309. shapeLayer.lineCap = @"square";
  310. break;
  311. default:
  312. break;
  313. }
  314. switch (protoShape.styles.lineJoin) {
  315. case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinRound:
  316. shapeLayer.lineJoin = @"round";
  317. break;
  318. case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinMiter:
  319. shapeLayer.lineJoin = @"miter";
  320. break;
  321. case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinBevel:
  322. shapeLayer.lineJoin = @"bevel";
  323. break;
  324. default:
  325. break;
  326. }
  327. shapeLayer.lineDashPhase = protoShape.styles.lineDashIii;
  328. shapeLayer.lineDashPattern = @[
  329. (protoShape.styles.lineDashI < 1.0 ? @(1.0) : @(protoShape.styles.lineDashI)),
  330. (protoShape.styles.lineDashIi < 0.1 ? @(0.1) : @(protoShape.styles.lineDashIi))
  331. ];
  332. shapeLayer.miterLimit = protoShape.styles.miterLimit;
  333. }
  334. }
  335. - (void)resetTransform:(CAShapeLayer *)shapeLayer shape:(NSDictionary *)shape {
  336. if ([shape[@"transform"] isKindOfClass:[NSDictionary class]]) {
  337. if ([shape[@"transform"][@"a"] isKindOfClass:[NSNumber class]] &&
  338. [shape[@"transform"][@"b"] isKindOfClass:[NSNumber class]] &&
  339. [shape[@"transform"][@"c"] isKindOfClass:[NSNumber class]] &&
  340. [shape[@"transform"][@"d"] isKindOfClass:[NSNumber class]] &&
  341. [shape[@"transform"][@"tx"] isKindOfClass:[NSNumber class]] &&
  342. [shape[@"transform"][@"ty"] isKindOfClass:[NSNumber class]]) {
  343. shapeLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMake([shape[@"transform"][@"a"] floatValue],
  344. [shape[@"transform"][@"b"] floatValue],
  345. [shape[@"transform"][@"c"] floatValue],
  346. [shape[@"transform"][@"d"] floatValue],
  347. [shape[@"transform"][@"tx"] floatValue],
  348. [shape[@"transform"][@"ty"] floatValue])
  349. );
  350. }
  351. }
  352. }
  353. - (void)resetTransform:(CAShapeLayer *)shapeLayer protoShape:(SVGAProtoShapeEntity *)protoShape {
  354. if (protoShape.hasTransform) {
  355. shapeLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMake((CGFloat)protoShape.transform.a,
  356. (CGFloat)protoShape.transform.b,
  357. (CGFloat)protoShape.transform.c,
  358. (CGFloat)protoShape.transform.d,
  359. (CGFloat)protoShape.transform.tx,
  360. (CGFloat)protoShape.transform.ty)
  361. );
  362. }
  363. }
  364. @end