From e3eea2a12fd76d44d52a1936e5d1334770c0f901 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 4 Dec 2019 19:02:15 +0800 Subject: [PATCH] feat:sync lost commits --- Doric.podspec | 24 +++- Example/Example.xcodeproj/project.pbxproj | 4 +- .../xcschemes/xcschememanagement.plist | 5 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 -- Example/Example/ViewController.m | 5 + Example/Example/demo/.gitignore | 2 +- Pod/Classes/Dev/DoricLocalServer.h | 31 ----- Pod/Classes/Dev/DoricLocalServer.m | 130 ------------------ Pod/Classes/Shader/DoricLayouts.h | 5 + Pod/Classes/Shader/DoricLayouts.m | 120 +++++++++------- Pod/Classes/Shader/DoricViewNode.m | 17 ++- 11 files changed, 125 insertions(+), 226 deletions(-) delete mode 100644 Example/Example.xcodeproj/xcuserdata/pengfei.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Pod/Classes/Dev/DoricLocalServer.h delete mode 100644 Pod/Classes/Dev/DoricLocalServer.m diff --git a/Doric.podspec b/Doric.podspec index 2b927846..228d8c45 100644 --- a/Doric.podspec +++ b/Doric.podspec @@ -1,25 +1,45 @@ +# +# Be sure to run `pod lib lint Doric.podspec' to ensure this is a +# valid spec before submitting. +# +# Any lines starting with a # are optional, but their use is encouraged +# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html +# + Pod::Spec.new do |s| s.name = 'Doric' s.version = '0.1.0' s.summary = 'A short description of Doric.' +# This description is used to generate tags and improve search results. +# * Think: What does it do? Why did you write it? What is the focus? +# * Try to keep it short, snappy and to the point. +# * Write the description between the DESC delimiters below. +# * Finally, don't worry about the indent, CocoaPods strips it! + s.description = <<-DESC -Doric SDK for iOS +TODO: Add long description of the pod here. DESC s.homepage = 'https://github.com/doric-pub/doric' + # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' s.license = { :type => 'Apache-2.0', :file => 'LICENSE' } s.author = { 'pengfei.zhou' => 'pengfeizhou@foxmail.com' } - s.source = { :git => 'git@code.aliyun.com:Doric/doric-iOS.git', :tag => s.version.to_s } + s.source = { :git => 'git@github.com:penfeizhou/doric.git', :tag => s.version.to_s } + # s.social_media_url = 'https://twitter.com/' s.ios.deployment_target = '8.0' s.source_files = 'Pod/Classes/**/*' + s.resource = "Pod/Assets/*.js" s.resource_bundles = { 'Doric' => ['Pod/Assets/**/*'] } s.public_header_files = 'Pod/Classes/**/*.h' + # s.frameworks = 'UIKit', 'MapKit' + # s.dependency 'AFNetworking', '~> 2.3' + # s.dependency 'SDWebImage', '~> 5.0' s.dependency 'YYWebImage', '~>1.0.5' s.dependency 'YYImage/WebP' s.dependency 'SocketRocket', '~> 0.5.1' diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index ce65bed3..30a17906 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -20,7 +20,7 @@ E2334AFE22E9D2070098A085 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334AFD22E9D2070098A085 /* main.m */; }; E2334B0822E9D2070098A085 /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334B0722E9D2070098A085 /* ExampleTests.m */; }; E2334B1322E9D2070098A085 /* ExampleUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334B1222E9D2070098A085 /* ExampleUITests.m */; }; - E247204923979232002D9E6E /* demo in Resources */ = {isa = PBXBuildFile; fileRef = E2F4481623839AC500073C7F /* demo */; }; + E2F4481723839AC500073C7F /* demo in Resources */ = {isa = PBXBuildFile; fileRef = E2F4481623839AC500073C7F /* demo */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -293,8 +293,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - E247204923979232002D9E6E /* demo in Resources */, E2334AFB22E9D2070098A085 /* LaunchScreen.storyboard in Resources */, + E2F4481723839AC500073C7F /* demo in Resources */, E2334AF822E9D2070098A085 /* Assets.xcassets in Resources */, E2334AF622E9D2060098A085 /* Main.storyboard in Resources */, ); diff --git a/Example/Example.xcodeproj/xcuserdata/pengfei.xcuserdatad/xcschemes/xcschememanagement.plist b/Example/Example.xcodeproj/xcuserdata/pengfei.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index ee3458dd..00000000 --- a/Example/Example.xcodeproj/xcuserdata/pengfei.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Example/Example/ViewController.m b/Example/Example/ViewController.m index 8acb2e3e..43bf753d 100644 --- a/Example/Example/ViewController.m +++ b/Example/Example/ViewController.m @@ -27,6 +27,11 @@ - (void)viewDidLoad { return ![obj containsString:@".map"]; }]; NSMutableArray *tmp = [self.demoFilePaths mutableCopy]; + NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch; + [tmp sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) { + NSRange range = NSMakeRange(0, obj1.length); + return [obj1 compare:obj2 options:comparisonOptions range:range]; + }]; [tmp insertObject:@"Dev Kit" atIndex:0]; self.demoFilePaths = tmp; [self.view addSubview:[[UITableView new] also:^(UITableView *it) { diff --git a/Example/Example/demo/.gitignore b/Example/Example/demo/.gitignore index a6c7c285..4c43fe68 100644 --- a/Example/Example/demo/.gitignore +++ b/Example/Example/demo/.gitignore @@ -1 +1 @@ -*.js +*.js \ No newline at end of file diff --git a/Pod/Classes/Dev/DoricLocalServer.h b/Pod/Classes/Dev/DoricLocalServer.h deleted file mode 100644 index b1ae18f9..00000000 --- a/Pod/Classes/Dev/DoricLocalServer.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright [2019] [Doric.Pub] - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// -// DoricLocalServer.h -// Doric -// -// Created by pengfei.zhou on 2019/8/14. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface DoricLocalServer : NSObject -- (void)startWithPort:(NSUInteger)port; -@end - -NS_ASSUME_NONNULL_END diff --git a/Pod/Classes/Dev/DoricLocalServer.m b/Pod/Classes/Dev/DoricLocalServer.m deleted file mode 100644 index 8fa1454f..00000000 --- a/Pod/Classes/Dev/DoricLocalServer.m +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright [2019] [Doric.Pub] - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// -// DoricLocalServer.m -// Doric -// -// Created by pengfei.zhou on 2019/8/14. -// - -#import "DoricLocalServer.h" -#import "GCDWebServer.h" -#import "GCDWebServerDataResponse.h" -#import "DoricUtil.h" -#import "DoricContextManager.h" - -#include -#include -#include - -typedef id (^ServerHandler)(GCDWebServerRequest *request); - -@interface DoricLocalServer () -@property(nonatomic, strong) GCDWebServer *server; -@property(nonatomic, strong) NSMutableDictionary *handlers; -@end - -@implementation DoricLocalServer - -- (instancetype)init { - if (self = [super init]) { - _server = [[GCDWebServer alloc] init]; - _handlers = [[NSMutableDictionary alloc] init]; - [self configurate]; - } - return self; -} - -- (NSString *)localIPAddress { - NSString *localIP = nil; - struct ifaddrs *addrs; - if (getifaddrs(&addrs) == 0) { - const struct ifaddrs *cursor = addrs; - while (cursor != NULL) { - if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0) { - //NSString *name = [NSString stringWithUTF8String:cursor->ifa_name]; - //if ([name isEqualToString:@"en0"]) // Wi-Fi adapter - { - localIP = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *) cursor->ifa_addr)->sin_addr)]; - break; - } - } - cursor = cursor->ifa_next; - } - freeifaddrs(addrs); - } - return localIP; -} - -- (GCDWebServerResponse *)handleRequest:(GCDWebServerRequest *)request { - if ([request.path hasPrefix:@"/api/"]) { - NSString *command = [request.path substringFromIndex:@"/api/".length]; - ServerHandler handler = [self.handlers objectForKey:command]; - if (handler) { - id dic = handler(request); - return [GCDWebServerDataResponse responseWithJSONObject:dic]; - } - return [GCDWebServerDataResponse responseWithHTML:@"

It's a API request.

"]; - } - NSBundle *bundle = DoricBundle(); - NSString *filePath = [NSString stringWithFormat:@"%@/dist%@", bundle.bundlePath, request.path]; - NSData *data = [NSData dataWithContentsOfFile:filePath]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; - NSHTTPURLResponse *response; - [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:nil]; - return [GCDWebServerDataResponse responseWithData:data contentType:response.MIMEType]; -} - -- (void)configurate { - __weak typeof(self) _self = self; - [self.server addDefaultHandlerForMethod:@"GET" - requestClass:[GCDWebServerRequest class] - processBlock:^GCDWebServerResponse *(GCDWebServerRequest *request) { - __strong typeof(_self) self = _self; - return [self handleRequest:request]; - }]; - [self.handlers setObject:^id(GCDWebServerRequest *request) { - NSMutableArray *array = [[NSMutableArray alloc] init]; - - for (NSValue *value in [[DoricContextManager instance] aliveContexts]) { - DoricContext *context = value.nonretainedObjectValue; - [array addObject:@{ - @"source": context.source, - @"id": context.contextId, - }]; - } - return array; - } - forKey:@"allContexts"]; - - [self.handlers setObject:^id(GCDWebServerRequest *request) { - NSString *contextId = [request.query objectForKey:@"id"]; - DoricContext *context = [[DoricContextManager instance] getContext:contextId]; - return @{ - @"id": context.contextId, - @"source": context.source, - @"script": context.script - }; - } - forKey:@"context"]; -} - -- (void)startWithPort:(NSUInteger)port { - [self.server startWithPort:port bonjourName:nil]; - DoricLog(@"Start Server At %@:%d", [self localIPAddress], port); -} -@end diff --git a/Pod/Classes/Shader/DoricLayouts.h b/Pod/Classes/Shader/DoricLayouts.h index fcddee0c..4e859b78 100644 --- a/Pod/Classes/Shader/DoricLayouts.h +++ b/Pod/Classes/Shader/DoricLayouts.h @@ -20,6 +20,7 @@ #import typedef UIEdgeInsets DoricMargin; +typedef UIEdgeInsets DoricPadding; DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom); @@ -82,6 +83,10 @@ typedef NS_ENUM(NSInteger, DoricGravity) { @property(nonatomic, strong) DoricLayoutConfig *layoutConfig; @end +@interface UIView (DoricPadding) +@property(nonatomic, assign) DoricPadding padding; +@end + @interface UIView (DoricTag) @property(nonatomic, copy) NSString *tagString; diff --git a/Pod/Classes/Shader/DoricLayouts.m b/Pod/Classes/Shader/DoricLayouts.m index c1e0adfb..2d1d4c40 100644 --- a/Pod/Classes/Shader/DoricLayouts.m +++ b/Pod/Classes/Shader/DoricLayouts.m @@ -37,6 +37,24 @@ - (DoricLayoutConfig *)layoutConfig { @end +static const void *kLayoutPadding = &kLayoutPadding; + +@implementation UIView (DoricPadding) +@dynamic padding; + +- (void)setPadding:(DoricPadding)padding { + objc_setAssociatedObject(self, kLayoutPadding, [NSValue value:&padding withObjCType:@encode(DoricPadding)], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (DoricPadding)padding { + DoricPadding value; + value.left = value.right = value.top = value.bottom = 0; + [objc_getAssociatedObject(self, kLayoutPadding) getValue:&value]; + return value; +} + +@end + static const void *kTagString = &kTagString; @implementation UIView (DoricTag) @@ -79,13 +97,15 @@ - (CGSize)measureSize:(CGSize)targetSize { || config.heightSpec == DoricLayoutWrapContent) { height = targetSize.height - config.margin.top - config.margin.bottom; } - - CGSize contentSize = [self sizeThatFits:CGSizeMake(width, height)]; + DoricPadding padding = self.padding; + CGSize contentSize = [self sizeThatFits:CGSizeMake( + width - padding.left - padding.right, + height - padding.top - padding.bottom)]; if (config.widthSpec == DoricLayoutWrapContent) { - width = contentSize.width; + width = contentSize.width + padding.left + padding.right; } if (config.heightSpec == DoricLayoutWrapContent) { - height = contentSize.height; + height = contentSize.height + padding.left + padding.top + padding.bottom; } return CGSizeMake(width, height); } @@ -208,6 +228,8 @@ - (CGSize)sizeThatFits:(CGSize)size { - (void)layoutSelf:(CGSize)targetSize { self.width = targetSize.width; self.height = targetSize.height; + DoricPadding padding = self.padding; + for (UIView *child in self.subviews) { if (child.isHidden) { continue; @@ -219,33 +241,35 @@ - (void)layoutSelf:(CGSize)targetSize { if (!childConfig) { childConfig = [DoricLayoutConfig new]; } - CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height)]; + CGSize size = [child measureSize:CGSizeMake( + targetSize.width - padding.left - padding.right, + targetSize.height - padding.top - padding.bottom)]; [child layoutSelf:size]; DoricGravity gravity = childConfig.alignment; if ((gravity & LEFT) == LEFT) { - child.left = 0; + child.left = padding.left; } else if ((gravity & RIGHT) == RIGHT) { - child.right = targetSize.width; + child.right = targetSize.width - padding.right; } else if ((gravity & CENTER_X) == CENTER_X) { - child.centerX = targetSize.width / 2; + child.centerX = (targetSize.width - padding.left - padding.right) / 2; } else { if (childConfig.margin.left) { - child.left = childConfig.margin.left; + child.left = childConfig.margin.left + padding.left; } else if (childConfig.margin.right) { - child.right = targetSize.width - childConfig.margin.right; + child.right = targetSize.width - childConfig.margin.right - padding.right; } } if ((gravity & TOP) == TOP) { - child.top = 0; + child.top = padding.top; } else if ((gravity & BOTTOM) == BOTTOM) { - child.bottom = targetSize.height; + child.bottom = targetSize.height - padding.bottom; } else if ((gravity & CENTER_Y) == CENTER_Y) { - child.centerY = targetSize.height / 2; + child.centerY = (targetSize.height - padding.top - padding.bottom) / 2; } else { if (childConfig.margin.top) { - child.top = childConfig.margin.top; + child.top = childConfig.margin.top + padding.top; } else if (childConfig.margin.bottom) { - child.bottom = targetSize.height - childConfig.margin.bottom; + child.bottom = targetSize.height - childConfig.margin.bottom - padding.bottom; } } } @@ -292,15 +316,16 @@ - (CGSize)sizeThatFits:(CGSize)size { - (void)layoutSelf:(CGSize)targetSize { self.width = targetSize.width; self.height = targetSize.height; - CGFloat yStart = 0; + DoricPadding padding = self.padding; + CGFloat yStart = padding.top; if ((self.gravity & TOP) == TOP) { - yStart = 0; + yStart = padding.top; } else if ((self.gravity & BOTTOM) == BOTTOM) { - yStart = targetSize.height - self.contentHeight; + yStart = targetSize.height - self.contentHeight - padding.bottom; } else if ((self.gravity & CENTER_Y) == CENTER_Y) { - yStart = (targetSize.height - self.contentHeight) / 2; + yStart = (targetSize.height - self.contentHeight - padding.top - padding.bottom) / 2; } - CGFloat remain = targetSize.height - self.contentHeight; + CGFloat remain = targetSize.height - self.contentHeight - padding.top - padding.bottom; for (UIView *child in self.subviews) { if (child.isHidden) { continue; @@ -313,24 +338,26 @@ - (void)layoutSelf:(CGSize)targetSize { childConfig = [DoricLayoutConfig new]; } - CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height - yStart)]; + CGSize size = [child measureSize:CGSizeMake( + targetSize.width - padding.left - padding.right, + targetSize.height - yStart - padding.bottom)]; if (childConfig.weight) { size.height += remain / self.contentWeight * childConfig.weight; } [child layoutSelf:size]; DoricGravity gravity = childConfig.alignment | self.gravity; if ((gravity & LEFT) == LEFT) { - child.left = 0; + child.left = padding.left; } else if ((gravity & RIGHT) == RIGHT) { - child.right = self.width; + child.right = self.width - padding.right; } else if ((gravity & CENTER_X) == CENTER_X) { - child.centerX = targetSize.width / 2; + child.centerX = (targetSize.width - padding.left - padding.right) / 2; + } else if (childConfig.margin.left) { + child.left = childConfig.margin.left + padding.left; + } else if (childConfig.margin.right) { + child.right = targetSize.width - childConfig.margin.right - padding.right; } else { - if (childConfig.margin.left) { - child.left = childConfig.margin.left; - } else if (childConfig.margin.right) { - child.right = targetSize.width - childConfig.margin.right; - } + child.left = padding.left; } if (childConfig.margin.top) { yStart += childConfig.margin.top; @@ -380,17 +407,16 @@ - (CGSize)sizeThatFits:(CGSize)size { - (void)layoutSelf:(CGSize)targetSize { self.width = targetSize.width; self.height = targetSize.height; - CGFloat xStart = 0; - if (self.contentWeight) { - xStart = 0; - } else if ((self.gravity & LEFT) == LEFT) { - xStart = 0; + DoricPadding padding = self.padding; + CGFloat xStart = padding.left; + if ((self.gravity & LEFT) == LEFT) { + xStart = padding.left; } else if ((self.gravity & RIGHT) == RIGHT) { - xStart = targetSize.width - self.contentWidth; + xStart = targetSize.width - self.contentWidth - padding.right; } else if ((self.gravity & CENTER_X) == CENTER_X) { - xStart = (targetSize.width - self.contentWidth) / 2; + xStart = (targetSize.width - self.contentWidth - padding.left - padding.right) / 2; } - CGFloat remain = targetSize.width - self.contentWidth; + CGFloat remain = targetSize.width - self.contentWidth - padding.left - padding.right; for (UIView *child in self.subviews) { if (child.isHidden) { continue; @@ -403,7 +429,9 @@ - (void)layoutSelf:(CGSize)targetSize { childConfig = [DoricLayoutConfig new]; } - CGSize size = [child measureSize:CGSizeMake(targetSize.width - xStart, targetSize.height)]; + CGSize size = [child measureSize:CGSizeMake( + targetSize.width - xStart - padding.right, + targetSize.height - padding.top - padding.bottom)]; if (childConfig.weight) { size.width += remain / self.contentWeight * childConfig.weight; } @@ -412,17 +440,17 @@ - (void)layoutSelf:(CGSize)targetSize { DoricGravity gravity = childConfig.alignment | self.gravity; if ((gravity & TOP) == TOP) { - child.top = 0; + child.top = padding.top; } else if ((gravity & BOTTOM) == BOTTOM) { - child.bottom = targetSize.height; + child.bottom = targetSize.height - padding.bottom; } else if ((gravity & CENTER_Y) == CENTER_Y) { - child.centerY = targetSize.height / 2; + child.centerY = (targetSize.height - padding.top - padding.bottom) / 2; + } else if (childConfig.margin.top) { + child.top = childConfig.margin.top + padding.top; + } else if (childConfig.margin.bottom) { + child.bottom = targetSize.height - childConfig.margin.bottom - padding.bottom; } else { - if (childConfig.margin.top) { - child.top = childConfig.margin.top; - } else if (childConfig.margin.bottom) { - child.bottom = targetSize.height - childConfig.margin.bottom; - } + child.top = padding.top; } if (childConfig.margin.left) { diff --git a/Pod/Classes/Shader/DoricViewNode.m b/Pod/Classes/Shader/DoricViewNode.m index 09e9ee8b..9dd2fffd 100644 --- a/Pod/Classes/Shader/DoricViewNode.m +++ b/Pod/Classes/Shader/DoricViewNode.m @@ -235,7 +235,6 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop } else { view.clipsToBounds = YES; } - } else if ([name isEqualToString:@"translationX"]) { self.translationX = prop; } else if ([name isEqualToString:@"translationY"]) { @@ -250,6 +249,17 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop self.pivotY = prop; } else if ([name isEqualToString:@"rotation"]) { self.rotation = prop; + } else if ([name isEqualToString:@"padding"]) { + DoricPadding padding; + padding.left = padding.right = padding.top = padding.bottom = 0; + if ([prop isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = prop; + padding.left = [dictionary[@"left"] floatValue]; + padding.right = [dictionary[@"right"] floatValue]; + padding.top = [dictionary[@"top"] floatValue]; + padding.bottom = [dictionary[@"bottom"] floatValue]; + } + self.view.padding = padding; } else { DoricLog(@"Blend View error for View Type :%@, prop is %@", self.class, name); } @@ -357,6 +367,8 @@ - (NSDictionary *)transformation { return dictionary; } +#pragma animations + - (void)doAnimation:(id)params withPromise:(DoricPromise *)promise { CAAnimation *animation = [self parseAnimation:params]; AnimationCallback *originDelegate = animation.delegate; @@ -371,6 +383,7 @@ - (void)doAnimation:(id)params withPromise:(DoricPromise *)promise { if (originDelegate) { originDelegate.endBlock(callback); } + [self.view.layer removeAllAnimations]; [self transformProperties]; [promise resolve:self.transformation]; }; @@ -379,6 +392,8 @@ - (void)doAnimation:(id)params withPromise:(DoricPromise *)promise { if (params[@"delay"]) { animation.beginTime = CACurrentMediaTime() + [params[@"delay"] floatValue] / 1000; } + animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeForwards; [self.view.layer addAnimation:animation forKey:nil]; }