* [ios] WXTransition
Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/741ee207 Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/741ee207 Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/741ee207 Branch: refs/heads/0.16-dev Commit: 741ee207ec66508d9124cb99a88e530a1458733f Parents: 6bd86e5 Author: doumafang <doumaf...@gmail.com> Authored: Thu Aug 10 21:34:48 2017 +0800 Committer: doumafang <doumaf...@gmail.com> Committed: Thu Aug 10 21:34:48 2017 +0800 ---------------------------------------------------------------------- .../Sources/Component/WXComponent_internal.h | 38 +-- .../WeexSDK/Sources/Layout/WXComponent+Layout.m | 280 ----------------- ios/sdk/WeexSDK/Sources/Model/WXComponent.m | 34 ++- .../WeexSDK/Sources/Module/WXAnimationLayout.h | 49 --- .../WeexSDK/Sources/Module/WXAnimationLayout.m | 115 ------- .../WeexSDK/Sources/Module/WXAnimationModule.h | 2 + .../WeexSDK/Sources/Module/WXAnimationModule.m | 46 ++- ios/sdk/WeexSDK/Sources/Module/WXTransition.h | 38 +++ ios/sdk/WeexSDK/Sources/Module/WXTransition.m | 299 +++++++++++++++++++ 9 files changed, 380 insertions(+), 521 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h index d2b7d54..49db7a9 100644 --- a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h +++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h @@ -21,9 +21,9 @@ #import "WXComponent.h" #import "WXConvert.h" #import "WXTransform.h" +#import "WXTransition.h" @class WXTouchGestureRecognizer; @class WXThreadSafeCounter; -@class WXLayoutAnimationInfo; /** @@ -45,34 +45,8 @@ WXPositionType _positionType; - - //LayoutAnimation - WXLayoutAnimationInfo *_heightInfo; - WXLayoutAnimationInfo *_widthInfo; - WXLayoutAnimationInfo *_topInfo; - WXLayoutAnimationInfo *_rightInfo; - WXLayoutAnimationInfo *_leftInfo; - WXLayoutAnimationInfo *_bottomInfo; - double ax; - double bx; - double cx; - - double ay; - double by; - double cy; - - - float _layoutAnimationDuration; - float _layoutAnimationDelay; - CAMediaTimingFunction *_layoutAnimationTimingFunction; - NSUInteger _layoutAnimationCount; - - NSMutableDictionary *_toStyles; - NSMutableDictionary *_fromStyles; - NSMutableDictionary *_addStyles; - CADisplayLink *_layoutAnimationDisplayLink; - - + //Transition + WXTransition *_transition; /** * View @@ -252,10 +226,4 @@ @end -@interface WXLayoutAnimationInfo : NSObject -@property (nonatomic, strong) id fromValue; -@property (nonatomic, strong) id toValue; -@property (nonatomic, strong) id perValue; -@property (nonatomic, assign) BOOL isAnimated; -@end http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.m ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.m b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.m index 14034a6..4eb57f5 100644 --- a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.m +++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.m @@ -17,8 +17,6 @@ * under the License. */ -#define SOLVE_EPS(dur) (1. / (1000. * (dur))) - #import "WXComponent+Layout.h" #import "WXComponent_internal.h" @@ -116,210 +114,6 @@ } -#pragma mark LayoutAnimationDisplayLink -- (void)_startLayoutAnimationDisplayLink -{ - WXAssertComponentThread(); - if (!_layoutAnimationDisplayLink) { - _layoutAnimationDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleLayoutAnimationDisplayLink)]; - [_layoutAnimationDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - } - else{ - [self _awakeLayoutAnimationDisplayLink]; - } - -} - -- (void)_stopLayoutAnimationDisplayLink -{ - WXAssertComponentThread(); - if (_layoutAnimationDisplayLink) { - [_layoutAnimationDisplayLink invalidate]; - _layoutAnimationDisplayLink = nil; - } -} - -- (void)_suspendLayoutAnimationDisplayLink -{ - WXAssertComponentThread(); - if(_layoutAnimationDisplayLink && !_layoutAnimationDisplayLink.paused) - { - _layoutAnimationDisplayLink.paused = YES; - } -} - - -- (void)_awakeLayoutAnimationDisplayLink -{ - WXAssertComponentThread(); - if (_layoutAnimationDisplayLink && _layoutAnimationDisplayLink.paused) { - _layoutAnimationDisplayLink.paused = NO; - } -} - -- (void)_handleLayoutAnimationDisplayLink -{ - WXAssertComponentThread(); - int count = _layoutAnimationDuration * 60 / 1000; - if (_layoutAnimationCount >= count) { - [self _suspendLayoutAnimationDisplayLink]; - [self _resetProcessAnimationParameter]; - return; - } - else - { - [self _calculateLayoutAnimationProcessingStyle]; - } - _layoutAnimationCount ++; -} - - -- (void)_resetProcessAnimationParameter -{ - - _layoutAnimationCount = 0; - _layoutAnimationDuration = 0; - _widthInfo = nil; - _heightInfo = nil; - _leftInfo = nil; - _rightInfo = nil; - _topInfo = nil; - _bottomInfo = nil; -} - -- (void)_handleLayoutAnimationWithStyles:(NSDictionary *)styles -{ - [self _suspendLayoutAnimationDisplayLink]; - - if (!_addStyles) { - _fromStyles = [NSMutableDictionary dictionaryWithDictionary:self.styles]; - _addStyles = [NSMutableDictionary dictionaryWithDictionary:styles]; - } - else - { - [_addStyles addEntriesFromDictionary:styles]; - }//ä¿è¯_addStylesæ¯å¯ä¸ç - - _toStyles = [NSMutableDictionary dictionaryWithDictionary:_fromStyles]; - [_toStyles addEntriesFromDictionary:_addStyles]; - - _layoutAnimationDuration = _fromStyles[@"transitionDuration"] ? [WXConvert CGFloat:_fromStyles[@"transitionDuration"]] : 0; - _layoutAnimationDelay = _fromStyles[@"transitionDelay"] ? [WXConvert CGFloat:_fromStyles[@"transitionDelay"]] : 0; - _layoutAnimationTimingFunction = [WXConvert CAMediaTimingFunction:_fromStyles[@"transitionTimingFunction"]]; - - - if (_layoutAnimationDuration == 0) { - [self _fillCSSNode:styles]; - return;//å¦æduration为é¶ç´æ¥å ³éå¨ç»ææ - } - - if (![[NSString stringWithFormat:@"%@",_layoutAnimationTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) { - float vec[4] = {0.}; - [_layoutAnimationTimingFunction getControlPointAtIndex:1 values:&vec[0]]; - [_layoutAnimationTimingFunction getControlPointAtIndex:2 values:&vec[2]]; - [self unitBezierp1x:vec[0] p1y:vec[1] p2x:vec[2] p2y:vec[3]]; - } - - - NSString *layoutAnimationProperty = _fromStyles[@"transitionProperty"]; - if ([layoutAnimationProperty containsString:@"width"]) { - _widthInfo = [WXLayoutAnimationInfo new]; - _widthInfo.isAnimated = YES; - _widthInfo.fromValue = @(_fromStyles[@"width"] ? [WXConvert CGFloat:_fromStyles[@"width" ]] : 0); - _widthInfo.toValue = @(_toStyles[@"width"] ? [WXConvert CGFloat:_toStyles[@"width"]] : 0 ); - _widthInfo.perValue = @([_widthInfo.toValue doubleValue] - [_widthInfo.fromValue doubleValue]); - - } - if ([layoutAnimationProperty containsString:@"height"]) - { - _heightInfo = [WXLayoutAnimationInfo new]; - _heightInfo.isAnimated = YES; - _heightInfo.fromValue = @(_fromStyles[@"height"] ? [WXConvert CGFloat:_fromStyles[@"height" ]] : 0); - _heightInfo.toValue = @(_toStyles[@"height"] ? [WXConvert CGFloat:_toStyles[@"height"]] : 0 ); - _heightInfo.perValue = @([_heightInfo.toValue doubleValue] - [_heightInfo.fromValue doubleValue]); - - } - if ([layoutAnimationProperty containsString:@"left"]) - { - _leftInfo = [WXLayoutAnimationInfo new]; - _leftInfo.isAnimated = YES; - _leftInfo.fromValue = @(_fromStyles[@"left"] ? [WXConvert CGFloat:_fromStyles[@"left" ]] : 0); - _leftInfo.toValue = @(_toStyles[@"left"] ? [WXConvert CGFloat:_toStyles[@"left"]] : 0 ); - _leftInfo.perValue = @([_leftInfo.toValue doubleValue] - [_leftInfo.fromValue doubleValue]); - - } - if ([layoutAnimationProperty containsString:@"right"]) - { - _rightInfo = [WXLayoutAnimationInfo new]; - _rightInfo.isAnimated = YES; - _rightInfo.fromValue = @(_fromStyles[@"right"] ? [WXConvert CGFloat:_fromStyles[@"right" ]] : 0); - _rightInfo.toValue = @(_toStyles[@"right"] ? [WXConvert CGFloat:_toStyles[@"right"]] : 0 ); - _rightInfo.perValue = @([_rightInfo.toValue doubleValue] - [_rightInfo.fromValue doubleValue]); - - } - if ([layoutAnimationProperty containsString:@"top"]) - { - _topInfo = [WXLayoutAnimationInfo new]; - _topInfo.isAnimated = YES; - _topInfo.fromValue = @(_fromStyles[@"top"] ? [WXConvert CGFloat:_fromStyles[@"top" ]] : 0); - _topInfo.toValue = @(_toStyles[@"top"] ? [WXConvert CGFloat:_toStyles[@"top"]] : 0 ); - _topInfo.perValue = @([_topInfo.toValue doubleValue] - [_topInfo.fromValue doubleValue]); - - } - if ([layoutAnimationProperty containsString:@"bottom"]) - { - _bottomInfo = [WXLayoutAnimationInfo new]; - _bottomInfo.isAnimated = YES; - _bottomInfo.fromValue = @(_fromStyles[@"bottom"] ? [WXConvert CGFloat:_fromStyles[@"bottom" ]] : 0); - _bottomInfo.toValue = @(_toStyles[@"bottom"] ? [WXConvert CGFloat:_toStyles[@"bottom"]] : 0 ); - _bottomInfo.perValue = @([_widthInfo.toValue doubleValue] - [_bottomInfo.fromValue doubleValue]); - - } - if ([layoutAnimationProperty containsString:@"transform"]) { - - - } - - - [self performSelector:@selector(_startLayoutAnimationDisplayLink) withObject:self afterDelay:_layoutAnimationDelay/1000]; - // [self _startLayoutAnimationDisplayLink]; - -} - - -- (void)_calculateLayoutAnimationProcessingStyle -{ - //linear å¨åè´å¡å°æ²çº¿æ¨¡å - double per = 1000 * (_layoutAnimationCount + 1 ) / (60 * _layoutAnimationDuration);//linear - if (![[NSString stringWithFormat:@"%@",_layoutAnimationTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) { - per = [self solveWithx:((_layoutAnimationCount+2)*16)/_layoutAnimationDuration epsilon:SOLVE_EPS(_layoutAnimationDuration)]; - } - - double currentWidth = [_widthInfo.fromValue doubleValue] + [_widthInfo.perValue doubleValue] * per; - double currentHeight = [_heightInfo.fromValue doubleValue] + [_heightInfo.perValue doubleValue] * per; - double currentLeft = [_leftInfo.fromValue doubleValue] + [_leftInfo.perValue doubleValue] * per; - double currentRight = [_rightInfo.fromValue doubleValue] + [_rightInfo.perValue doubleValue] * per; - double currentTop = [_topInfo.fromValue doubleValue] + [_topInfo.perValue doubleValue] * per; - double currentBottom = [_bottomInfo.fromValue doubleValue] + [_bottomInfo.perValue doubleValue] * per; - - - - _widthInfo.isAnimated ? [_fromStyles setObject:@(currentWidth) forKey:@"width"]:0; - _heightInfo.isAnimated ? [_fromStyles setObject:@(currentHeight) forKey:@"height"]:0; - _leftInfo.isAnimated ? [_fromStyles setObject:@(currentLeft) forKey:@"left"]:0; - _rightInfo.isAnimated ? [_fromStyles setObject:@(currentRight) forKey:@"right"]:0; - _topInfo.isAnimated ? [_fromStyles setObject:@(currentTop) forKey:@"top"]:0; - _bottomInfo.isAnimated ? [_fromStyles setObject:@(currentBottom) forKey:@"bottom"]:0; - - NSLog(@"%@",_fromStyles); - - [self _fillCSSNode:_fromStyles]; - -} - - - - - (void)_frameDidCalculated:(BOOL)isChanged { WXAssertComponentThread(); @@ -616,78 +410,4 @@ static css_dim_t cssNodeMeasure(void *context, float width, css_measure_mode_t w return (css_dim_t){resultSize.width, resultSize.height}; } - -//è´å¡å°æ²çº¿è®¡ç® -- (void)unitBezierp1x:(double)p1x p1y:(double)p1y p2x:(double)p2x p2y:(double)p2y -{ - cx = 3.0 * p1x; - bx = 3.0 * (p2x - p1x) - cx; - ax = 1.0 - cx -bx; - - cy = 3.0 * p1y; - by = 3.0 * (p2y - p1y) - cy; - ay = 1.0 - cy - by; -} -- (double)sampleCurveX:(double)t -{ - return ((ax * t + bx) * t + cx) * t; -} - -- (double)sampleCurveY:(double)t -{ - return ((ay * t + by) * t + cy) * t; -} - -- (double)sampleCurveDerivativeX:(double)t -{ - return (3.0 * ax * t + 2.0 * bx) * t + cx; -} - -- (double)solveCurveX:(double)x epsilon:(double)epsilon -{ - double t0; - double t1; - double t2; - double x2; - double d2; - int i; - - for (t2 = x, i = 0; i < 8; i++) { - x2 = [self sampleCurveX:t2] - x; - if (fabs (x2) < epsilon) - return t2; - d2 = [self sampleCurveDerivativeX:t2]; - if (fabs(d2) < 1e-6) - break; - t2 = t2 - x2 / d2; - } - t0 = 0.0; - t1 = 1.0; - t2 = x; - - if (t2 < t0) - return t0; - if (t2 > t1) - return t1; - - while (t0 < t1) { - x2 = [self sampleCurveX:t2]; - if (fabs(x2 - x) < epsilon) - return t2; - if (x > x2) - t0 = t2; - else - t1 = t2; - t2 = (t1 - t0) * .5 + t0; - } - return t2; -} - -- (double)solveWithx:(double)x epsilon:(double)epsilon -{ - return [self sampleCurveY:([self solveCurveX:x epsilon:epsilon])]; -} - - - @end http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Model/WXComponent.m ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.m b/ios/sdk/WeexSDK/Sources/Model/WXComponent.m index 929d5a5..b8ae789 100644 --- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.m +++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.m @@ -436,12 +436,13 @@ - (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles { - - //æ ¹æ®å½åçstyleæ¯å¦å«ætransitionPropertyå±æ§æ¥å¤ææ¯å¦æLayout Animation - if (_styles[@"transitionProperty"]) { - [self _handleLayoutAnimationWithStyles:styles]; + if ([self _isPropertyTransition]) { + if (!_transition) { + _transition = [WXTransition new]; + } + [_transition _handleTransitionWithStyles:styles withTarget:self]; } - else//å¦æ没æå¨ç»å±æ§æ æ ç´æ¥è§¦ålayout + else { styles = [self parseStyles:styles]; [self _updateCSSNodeStyles:styles]; @@ -449,22 +450,30 @@ if (isUpdateStyles) { [self _modifyStyles:styles]; - }//ä¿®æ¹_style + } [self _resetCSSNodeStyles:resetStyles]; } -- (void)_modifyStyles:(NSDictionary *)styles //主è¦ç®çæ¯æ¥æ´æ°_style +- (BOOL)_isPropertyTransition +{ + BOOL yesOrNo = false; + NSString *property = _styles[@"transitionProperty"]; + if (property) { + if ([property containsString:@"width"]||[property containsString:@"height"]||[property containsString:@"top"]||[property containsString:@"left"]||[property containsString:@"bottom"]||[property containsString:@"transform"]) { + yesOrNo = true; + } + } + return yesOrNo; +} + +- (void)_modifyStyles:(NSDictionary *)styles { pthread_mutex_lock(&_propertyMutex); [_styles addEntriesFromDictionary:styles]; pthread_mutex_unlock(&_propertyMutex); } - - - - - (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes { pthread_mutex_lock(&_propertyMutex); @@ -669,6 +678,3 @@ } @end -@implementation WXLayoutAnimationInfo - -@end http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Module/WXAnimationLayout.h ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Module/WXAnimationLayout.h b/ios/sdk/WeexSDK/Sources/Module/WXAnimationLayout.h deleted file mode 100644 index 1784498..0000000 --- a/ios/sdk/WeexSDK/Sources/Module/WXAnimationLayout.h +++ /dev/null @@ -1,49 +0,0 @@ -///* -// * Licensed to the Apache Software Foundation (ASF) under one -// * or more contributor license agreements. See the NOTICE file -// * distributed with this work for additional information -// * regarding copyright ownership. The ASF licenses this file -// * to you 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. -// */ -// -//#import <Foundation/Foundation.h> -// -//#import "WXComponent.h" -//#import "WXComponent_internal.h" -//#import "NSTimer+Weex.h" -// -//@interface WXAnimationLayoutInfo : NSObject -// -//@property (nonatomic, strong) NSString *propertyName; -//@property (nonatomic, strong) id fromValue; -//@property (nonatomic, strong) id toValue; -// -//@end -// -// -//@interface WXAnimationLayout : NSObject -// -//@property (nonatomic,strong) NSTimer *updateStyleTimer; -//@property (nonatomic,strong) WXComponent *targetComponent; -//@property (nonatomic,strong) NSDate *animationStartDate; -//@property (nonatomic,strong) WXAnimationLayoutInfo *widthInfo; -//@property (nonatomic,strong) WXAnimationLayoutInfo *heightInfo; -//@property (nonatomic,assign) double animationDuration; -//@property (nonatomic,assign) double animationDelay; -//@property (nonatomic,strong) NSDictionary *needUpdateStyles; -//@property (nonatomic, weak) WXSDKInstance *weexInstance; -// -//- (void)layoutForAnimation; -// -//@end http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Module/WXAnimationLayout.m ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Module/WXAnimationLayout.m b/ios/sdk/WeexSDK/Sources/Module/WXAnimationLayout.m deleted file mode 100644 index 341f5d2..0000000 --- a/ios/sdk/WeexSDK/Sources/Module/WXAnimationLayout.m +++ /dev/null @@ -1,115 +0,0 @@ -///* -// * Licensed to the Apache Software Foundation (ASF) under one -// * or more contributor license agreements. See the NOTICE file -// * distributed with this work for additional information -// * regarding copyright ownership. The ASF licenses this file -// * to you 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. -// */ -// -//#import "WXAnimationLayout.h" -//#import "WXSDKInstance_private.h" -// -//@implementation WXAnimationLayoutInfo -// -//@end -// -//@implementation WXAnimationLayout -// -//- (instancetype)init -//{ -// if (self = [super init]) { -// -// } -// return self; -//} -// -//- (void)layoutForAnimation -//{ -// self.animationStartDate = [NSDate date]; -// if (_animationDelay > 0) { -// [self performSelector:@selector(startUpdateStyleTimer) withObject:nil afterDelay:_animationDelay/1000]; -// } else { -// [self startUpdateStyleTimer]; -// } -//} -// -//#pragma mark UpdateStyle Methods -// -//- (void)startUpdateStyleTimer -//{ -// if (!self.updateStyleTimer || ![self.updateStyleTimer isValid]) { -// __weak __typeof__(self) weakSelf = self; -// self.updateStyleTimer = [NSTimer wx_scheduledTimerWithTimeInterval:16/1000.0f block:^() { -// [weakSelf updateStyleOnTimer]; -// } repeats:YES]; -// [[NSRunLoop currentRunLoop] addTimer:self.updateStyleTimer forMode:NSRunLoopCommonModes]; -// } -//} -// -//- (void)stopUpdateStyleTimer -//{ -// if (self.updateStyleTimer && [self.updateStyleTimer isValid]) { -// [self.updateStyleTimer invalidate]; -// self.updateStyleTimer = nil; -// } -//} -// -//- (void)updateStyleOnTimer -//{ -// NSTimeInterval startMsecond = [_animationStartDate timeIntervalSince1970]*1000; -// NSTimeInterval nowMsecond = [[NSDate date] timeIntervalSince1970]*1000; -// NSTimeInterval interval = nowMsecond - startMsecond; -// if (!(_widthInfo || _heightInfo)) { -// [self stopUpdateStyleTimer]; -// return; -// } -// if (interval > _animationDuration + _animationDelay) { -// [self stopUpdateStyleTimer]; -// return; -// } -// CGFloat scaleFactor = self.weexInstance.pixelScaleFactor; -// _needUpdateStyles = [[NSMutableDictionary alloc] init]; -// if (_widthInfo) { -// double currentValue = (([_widthInfo.toValue doubleValue] - [_widthInfo.fromValue doubleValue]) * ((interval - _animationDelay) / _animationDuration) + [_widthInfo.fromValue doubleValue]) / scaleFactor; -// [_needUpdateStyles setValue:[NSNumber numberWithDouble:currentValue] forKey:@"width"]; -// } -// if (_heightInfo) { -// double currentValue = (([_heightInfo.toValue doubleValue] - [_heightInfo.fromValue doubleValue]) * ((interval - _animationDelay) / _animationDuration) + [_heightInfo.fromValue doubleValue]) / scaleFactor; -// [_needUpdateStyles setValue:[NSNumber numberWithDouble:currentValue] forKey:@"height"]; -// } -// [self updateStyle:_needUpdateStyles]; -//} -// -//- (void)updateStyle:(NSDictionary *)styles -//{ -// if ([styles count]>0) { -// __weak typeof(self) weakSelf = self; -// WXPerformBlockOnComponentThread(^{ -// WXComponentManager *manager = weakSelf.weexInstance.componentManager; -// if (!manager.isValid) { -// return; -// } -// [manager updateStyles:styles forComponent:_targetComponent.ref]; -// [manager startComponentTasks]; -// }); -// } -//} -// -//- (void)dealloc -//{ -// [self stopUpdateStyleTimer]; -// [NSObject cancelPreviousPerformRequestsWithTarget:self]; -//} -// -//@end http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.h ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.h b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.h index ae7f068..d5a8c43 100644 --- a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.h +++ b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.h @@ -22,6 +22,8 @@ @interface WXAnimationModule : NSObject <WXModuleProtocol> + - (void)animation:(WXComponent *)targetComponent args:(NSDictionary *)args callback:(WXModuleCallback)callback; +- (void)animationModuleProcessAnimationWithArgs:(NSDictionary *)args withWeexInstance:(WXSDKInstance *)instance targetComponent:(WXComponent *)target; @end http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m index 46cf68a..dc01af3 100644 --- a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m +++ b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m @@ -24,7 +24,7 @@ #import "WXTransform.h" #import "WXUtility.h" #import "WXLength.h" -#import "WXAnimationLayout.h" +#import "WXTransition.h" @interface WXAnimationInfo : NSObject<NSCopying> @@ -36,7 +36,6 @@ @property (nonatomic, assign) double delay; @property (nonatomic, strong) CAMediaTimingFunction *timingFunction; @property (nonatomic, assign) CGPoint originAnchorPoint; - @end @implementation WXAnimationInfo @@ -137,8 +136,9 @@ @interface WXAnimationModule () -//@property (nonatomic,strong) WXAnimationLayout *animationLayout; @property (nonatomic,assign) BOOL needLayout; +@property (nonatomic, strong) WXTransition *transition; + @end @implementation WXAnimationModule @@ -150,8 +150,6 @@ WX_EXPORT_METHOD(@selector(transition:args:callback:)) - (void)transition:(NSString *)nodeRef args:(NSDictionary *)args callback:(WXModuleCallback)callback { _needLayout = NO; -// _animationLayout = [[WXAnimationLayout alloc] init]; -// _animationLayout.weexInstance = self.weexInstance; WXPerformBlockOnComponentThread(^{ WXComponent *targetComponent = [self.weexInstance componentForRef:nodeRef]; if (!targetComponent) { @@ -177,9 +175,8 @@ WX_EXPORT_METHOD(@selector(transition:args:callback:)) double delay = [args[@"delay"] doubleValue] / 1000; if (args[@"needLayout"]) { _needLayout = [WXConvert BOOL:args[@"needLayout"]]; + _transition = [WXTransition new]; } -// _animationLayout.animationDuration = duration * 1000; -// _animationLayout.animationDelay = delay * 1000; CAMediaTimingFunction *timingFunction = [WXConvert CAMediaTimingFunction:args[@"timingFunction"]]; NSDictionary *styles = args[@"styles"]; for (NSString *property in styles) { @@ -276,10 +273,6 @@ WX_EXPORT_METHOD(@selector(transition:args:callback:)) } else if ([property isEqualToString:@"width"]) { if (_needLayout) { [self animationWithLayoutAnimationTarget:target handleProperty:property withDic:args]; - // _animationLayout.widthInfo = [[WXAnimationLayoutInfo alloc] init]; - // _animationLayout.widthInfo.toValue = info.toValue; - // _animationLayout.widthInfo.fromValue = info.fromValue; - // _animationLayout.widthInfo.propertyName = info.propertyName; } else { @@ -293,10 +286,6 @@ WX_EXPORT_METHOD(@selector(transition:args:callback:)) } else if ([property isEqualToString:@"height"]) { if (_needLayout) { [self animationWithLayoutAnimationTarget:target handleProperty:property withDic:args]; - // _animationLayout.heightInfo = [[WXAnimationLayoutInfo alloc] init]; - // _animationLayout.heightInfo.toValue = info.toValue; - // _animationLayout.heightInfo.fromValue = info.fromValue; - // _animationLayout.heightInfo.propertyName = info.propertyName; } else { @@ -313,14 +302,20 @@ WX_EXPORT_METHOD(@selector(transition:args:callback:)) return infos; } +- (void)animationModuleProcessAnimationWithArgs:(NSDictionary *)args withWeexInstance:(WXSDKInstance *)instance targetComponent:(WXComponent *)target +{ + self.weexInstance = instance; + [self animation:target args:args callback:nil]; +} + - (void)animationWithLayoutAnimationTarget:(WXComponent *)target handleProperty:(NSString *)property withDic:(NSDictionary *)args { NSDictionary *styles = args[@"styles"]; - target->_addStyles = [NSMutableDictionary dictionaryWithDictionary:styles]; - target->_fromStyles = target->_fromStyles ? :[NSMutableDictionary dictionaryWithDictionary:target.styles] ; - [target->_fromStyles setObject:@([args[@"duration"] doubleValue]) forKey:@"transitionDuration"]; - [target->_fromStyles setObject:@([args[@"delay"] doubleValue]) forKey:@"transitionDelay"]; - NSString *oldProperty = target->_fromStyles[@"transitionProperty"]; + _transition.addStyles = [NSMutableDictionary dictionaryWithDictionary:styles]; + _transition.fromStyles =_transition.fromStyles ? :[NSMutableDictionary dictionaryWithDictionary:target.styles] ; + [_transition.fromStyles setObject:@([args[@"duration"] doubleValue]) forKey:@"transitionDuration"]; + [_transition.fromStyles setObject:@([args[@"delay"] doubleValue]) forKey:@"transitionDelay"]; + NSString *oldProperty = _transition.fromStyles[@"transitionProperty"]; NSString *newProperty; if (oldProperty) { if ([oldProperty containsString:property]) { @@ -335,14 +330,11 @@ WX_EXPORT_METHOD(@selector(transition:args:callback:)) { newProperty = property; } - [target->_fromStyles setObject:newProperty forKey:@"transitionProperty"]; - [target->_fromStyles setObject:args[@"timingFunction"] forKey:@"transitionTimingFunction"]; + [_transition.fromStyles setObject:newProperty forKey:@"transitionProperty"]; + [_transition.fromStyles setObject:args[@"timingFunction"] forKey:@"transitionTimingFunction"]; [target _modifyStyles:styles]; } - - - - (void)animation:(WXComponent *)targetComponent args:(NSDictionary *)args callback:(WXModuleCallback)callback { /** @@ -364,10 +356,8 @@ WX_EXPORT_METHOD(@selector(transition:args:callback:)) [CATransaction commit]; if (_needLayout) { - // _animationLayout.targetComponent = targetComponent; - // [_animationLayout layoutForAnimation]; WXPerformBlockOnComponentThread(^{ - [targetComponent _handleLayoutAnimationWithStyles:targetComponent->_addStyles]; + [_transition _handleTransitionWithStyles:_transition.addStyles withTarget:targetComponent]; }); } } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Module/WXTransition.h ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Module/WXTransition.h b/ios/sdk/WeexSDK/Sources/Module/WXTransition.h new file mode 100644 index 0000000..9a0d5a8 --- /dev/null +++ b/ios/sdk/WeexSDK/Sources/Module/WXTransition.h @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +#import <Foundation/Foundation.h> + +@interface WXLayoutAnimationInfo : NSObject +@property (nonatomic, strong) id fromValue; +@property (nonatomic, strong) id toValue; +@property (nonatomic, strong) id perValue; +@property (nonatomic, strong) NSString *propertyName; + +@end + +@interface WXTransition : NSObject +@property(nonatomic,strong) NSMutableDictionary *fromStyles; +@property(nonatomic,strong) NSMutableDictionary *addStyles; +@property(nonatomic,strong) NSMutableArray *propertyArray; +- (void)_handleTransitionWithStyles:(NSDictionary *)styles withTarget:(WXComponent *)targetComponent; + +@end + + http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/741ee207/ios/sdk/WeexSDK/Sources/Module/WXTransition.m ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Module/WXTransition.m b/ios/sdk/WeexSDK/Sources/Module/WXTransition.m new file mode 100644 index 0000000..26d9fb9 --- /dev/null +++ b/ios/sdk/WeexSDK/Sources/Module/WXTransition.m @@ -0,0 +1,299 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +#define SOLVE_EPS(dur) (1. / (1000. * (dur))) + +#import <QuartzCore/CATransaction.h> +#import <QuartzCore/CADisplayLink.h> +#import "WXAnimationModule.h" +#import "WXComponentManager.h" +#import "WXSDKInstance.h" +#import "WXComponent+Layout.h" +#import "WXComponent_internal.h" +#import "WXTransition.h" +#import "WXUtility.h" +#import "WXAssert.h" +#import "WXSDKInstance_private.h" + +@implementation WXLayoutAnimationInfo + +@end + +@interface WXTransition() +{ + WXComponent *_targetComponent; + + double ax; + double bx; + double cx; + + double ay; + double by; + double cy; + + float _layoutAnimationDuration; + float _layoutAnimationDelay; + NSUInteger _layoutAnimationCount; + + CAMediaTimingFunction *_layoutAnimationTimingFunction; + CADisplayLink *_layoutAnimationDisplayLink; + + NSMutableDictionary *_toStyles; + NSMutableDictionary *_fromStyles; + NSMutableDictionary *_addStyles; +} + +@end + +@implementation WXTransition + +- (void)_handleTransitionWithStyles:(NSDictionary *)styles withTarget:(WXComponent *)targetComponent +{ + [self _suspendLayoutAnimationDisplayLink]; + _targetComponent = targetComponent; + if (!_addStyles) { + _fromStyles = [NSMutableDictionary dictionaryWithDictionary:targetComponent.styles]; + _addStyles = [NSMutableDictionary dictionaryWithDictionary:styles]; + } + else + { + [_addStyles addEntriesFromDictionary:styles]; + } + + _toStyles = [NSMutableDictionary dictionaryWithDictionary:_fromStyles]; + [_toStyles addEntriesFromDictionary:_addStyles]; + + _layoutAnimationDuration = _fromStyles[@"transitionDuration"] ? [WXConvert CGFloat:_fromStyles[@"transitionDuration"]] : 0; + _layoutAnimationDelay = _fromStyles[@"transitionDelay"] ? [WXConvert CGFloat:_fromStyles[@"transitionDelay"]] : 0; + _layoutAnimationTimingFunction = [WXConvert CAMediaTimingFunction:_fromStyles[@"transitionTimingFunction"]]; + + if (_layoutAnimationDuration == 0) { + [targetComponent _updateCSSNodeStyles:styles]; + WXPerformBlockOnMainThread(^{ + [targetComponent _updateViewStyles:styles]; + }); + return; + } + + if (![[NSString stringWithFormat:@"%@",_layoutAnimationTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) { + float vec[4] = {0.}; + [_layoutAnimationTimingFunction getControlPointAtIndex:1 values:&vec[0]]; + [_layoutAnimationTimingFunction getControlPointAtIndex:2 values:&vec[2]]; + [self unitBezierp1x:vec[0] p1y:vec[1] p2x:vec[2] p2y:vec[3]]; + } + + NSString *layoutAnimationProperty = _fromStyles[@"transitionProperty"]; + [self _resloveTransitionProperty:layoutAnimationProperty withStyles:styles]; + [self performSelector:@selector(_startLayoutAnimationDisplayLink) withObject:self afterDelay:_layoutAnimationDelay/1000]; +} + +- (void)_resloveTransitionProperty:(NSString *)propertyNames withStyles:(NSDictionary *)styles +{ + NSArray *array = @[@"width",@"height",@"top",@"bottom",@"right",@"left",@"transform",@"backgroundColor",@"opacity"]; + for (NSString *propertyName in array) { + if ([propertyNames containsString:propertyName]) { + [self _judgeProperty:propertyName withStyles:styles]; + } + } +} + +- (void)_judgeProperty:(NSString *)singleProperty withStyles:(NSDictionary *)styles +{ + if (([singleProperty isEqualToString:@"transform"]&&styles[@"transform"]) || ([singleProperty containsString:@"backgroundColor"]&&styles[@"backgroundColor"]) || ([singleProperty containsString:@"opacity"]&&styles[@"opacity"])) { + NSDictionary *args = @{@"delay":@(_layoutAnimationDelay),@"duration":@(_layoutAnimationDuration),@"styles":styles,@"timingFunction":_fromStyles[@"transitionTimingFunction"]}; + [self _animationModuleHandleTransition:args]; + } + else{ + WXLayoutAnimationInfo *info = [WXLayoutAnimationInfo new]; + info.fromValue = @(_fromStyles[singleProperty] ? [WXConvert CGFloat:_fromStyles[singleProperty]] : 0); + info.toValue = @(_toStyles[singleProperty] ? [WXConvert CGFloat:_toStyles[singleProperty]] : 0 ); + info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); + info.propertyName = singleProperty; + if (!_propertyArray) { + _propertyArray = [NSMutableArray new]; + } + [_propertyArray addObject:info]; + } +} + +- (void)_calculateLayoutAnimationProcessingStyle +{ + double per = 1000 * (_layoutAnimationCount + 1 ) / (60 * _layoutAnimationDuration);//linear + if (![[NSString stringWithFormat:@"%@",_layoutAnimationTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) { + per = [self solveWithx:((_layoutAnimationCount+2)*16)/_layoutAnimationDuration epsilon:SOLVE_EPS(_layoutAnimationDuration)]; + } + for (WXLayoutAnimationInfo *info in _propertyArray) { + double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per; + [_fromStyles setObject:@(currentValue) forKey:info.propertyName]; + } + [_targetComponent _updateCSSNodeStyles:_fromStyles]; + [_targetComponent.weexInstance.componentManager startComponentTasks]; +} + +- (void)_startLayoutAnimationDisplayLink +{ + WXAssertComponentThread(); + if (!_layoutAnimationDisplayLink) { + _layoutAnimationDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleLayoutAnimationDisplayLink)]; + [_layoutAnimationDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + } + else{ + [self _awakeLayoutAnimationDisplayLink]; + } +} + +- (void)_stopLayoutAnimationDisplayLink +{ + WXAssertComponentThread(); + if (_layoutAnimationDisplayLink) { + [_layoutAnimationDisplayLink invalidate]; + _layoutAnimationDisplayLink = nil; + } +} + +- (void)_suspendLayoutAnimationDisplayLink +{ + WXAssertComponentThread(); + if(_layoutAnimationDisplayLink && !_layoutAnimationDisplayLink.paused) + { + _layoutAnimationDisplayLink.paused = YES; + } +} + +- (void)_awakeLayoutAnimationDisplayLink +{ + WXAssertComponentThread(); + if (_layoutAnimationDisplayLink && _layoutAnimationDisplayLink.paused) { + _layoutAnimationDisplayLink.paused = NO; + } +} + +- (void)_handleLayoutAnimationDisplayLink +{ + WXAssertComponentThread(); + int count = _layoutAnimationDuration * 60 / 1000; + if (_layoutAnimationCount >= count) { + [self _suspendLayoutAnimationDisplayLink]; + [self _resetProcessAnimationParameter]; + return; + } + else + { + [self _calculateLayoutAnimationProcessingStyle]; + } + _layoutAnimationCount ++; +} + +- (void)_resetProcessAnimationParameter +{ + _layoutAnimationCount = 0; + _layoutAnimationDuration = 0; + +} + +- (void)_animationModuleHandleTransition:(NSDictionary *)args +{ + WXAnimationModule *animation = [WXAnimationModule new]; + WXPerformBlockOnMainThread(^{ + [animation animationModuleProcessAnimationWithArgs:args withWeexInstance:_targetComponent.weexInstance targetComponent:_targetComponent]; + }); +} + +- (NSMutableDictionary *)_addStyles +{ + return self.addStyles; +} + +- (NSMutableDictionary *)_fromStyles +{ + return self.fromStyles; +} + +- (void)unitBezierp1x:(double)p1x p1y:(double)p1y p2x:(double)p2x p2y:(double)p2y +{ + cx = 3.0 * p1x; + bx = 3.0 * (p2x - p1x) - cx; + ax = 1.0 - cx -bx; + + cy = 3.0 * p1y; + by = 3.0 * (p2y - p1y) - cy; + ay = 1.0 - cy - by; +} + +- (double)sampleCurveX:(double)t +{ + return ((ax * t + bx) * t + cx) * t; +} + +- (double)sampleCurveY:(double)t +{ + return ((ay * t + by) * t + cy) * t; +} + +- (double)sampleCurveDerivativeX:(double)t +{ + return (3.0 * ax * t + 2.0 * bx) * t + cx; +} + +- (double)solveCurveX:(double)x epsilon:(double)epsilon +{ + double t0; + double t1; + double t2; + double x2; + double d2; + int i; + + for (t2 = x, i = 0; i < 8; i++) { + x2 = [self sampleCurveX:t2] - x; + if (fabs (x2) < epsilon) + return t2; + d2 = [self sampleCurveDerivativeX:t2]; + if (fabs(d2) < 1e-6) + break; + t2 = t2 - x2 / d2; + } + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) + return t0; + if (t2 > t1) + return t1; + + while (t0 < t1) { + x2 = [self sampleCurveX:t2]; + if (fabs(x2 - x) < epsilon) + return t2; + if (x > x2) + t0 = t2; + else + t1 = t2; + t2 = (t1 - t0) * .5 + t0; + } + return t2; +} + +- (double)solveWithx:(double)x epsilon:(double)epsilon +{ + return [self sampleCurveY:([self solveCurveX:x epsilon:epsilon])]; +} + +@end