You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ac...@apache.org on 2018/04/26 12:39:54 UTC

[02/16] incubator-weex git commit: [WEEX-311] [iOS] use new layoutEngin to replace yoga

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm b/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
new file mode 100644
index 0000000..0556ca5
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
@@ -0,0 +1,953 @@
+/*
+ * 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 "WXComponent.h"
+#import "WXComponent_internal.h"
+#import "WXComponentManager.h"
+#import "WXSDKManager.h"
+#import "WXSDKInstance.h"
+#import "WXSDKInstance_private.h"
+#import "WXDefine.h"
+#import "WXLog.h"
+#import "WXWeakObjectWrapper.h"
+#import "WXUtility.h"
+#import "WXConvert.h"
+#import "WXMonitor.h"
+#import "WXAssert.h"
+#import "WXThreadSafeMutableDictionary.h"
+#import "WXThreadSafeMutableArray.h"
+#import "WXTransform.h"
+#import "WXRoundedRect.h"
+#import <pthread/pthread.h>
+#import "WXComponent+PseudoClassManagement.h"
+#import "WXComponent+BoxShadow.h"
+#import "WXTracingManager.h"
+#import "WXComponent+Events.h"
+#import "WXComponent+Layout.h"
+
+#pragma clang diagnostic ignored "-Wincomplete-implementation"
+#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+
+@interface WXComponent () <UIGestureRecognizerDelegate>
+
+@end
+
+@implementation WXComponent
+{
+@private
+    NSString *_ref;
+    NSMutableDictionary *_styles;
+    NSMutableDictionary *_attributes;
+    NSMutableArray *_events;
+    
+    // Protects properties styles/attributes/events/subcomponents which will be accessed from multiple threads.
+    pthread_mutex_t _propertyMutex;
+    pthread_mutexattr_t _propertMutexAttr;
+    
+    __weak WXComponent *_supercomponent;
+    __weak id<WXScrollerProtocol> _ancestorScroller;
+    __weak WXSDKInstance *_weexInstance;
+}
+
+#pragma mark Life Cycle
+
+- (instancetype)initWithRef:(NSString *)ref
+                       type:(NSString *)type
+                     styles:(NSDictionary *)styles
+                 attributes:(NSDictionary *)attributes
+                     events:(NSArray *)events
+               weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super init]) {
+        pthread_mutexattr_init(&_propertMutexAttr);
+        pthread_mutexattr_settype(&_propertMutexAttr, PTHREAD_MUTEX_RECURSIVE);
+        pthread_mutex_init(&_propertyMutex, &_propertMutexAttr);
+        
+        _ref = ref;
+        _type = type;
+        _weexInstance = weexInstance;
+        _componentType = WXComponentTypeCommon;
+        _styles = [self parseStyles:styles];
+        _attributes = attributes ? [NSMutableDictionary dictionaryWithDictionary:attributes] : [NSMutableDictionary dictionary];
+        _events = events ? [NSMutableArray arrayWithArray:events] : [NSMutableArray array];
+        _subcomponents = [NSMutableArray array];
+        _absolutePosition = CGPointMake(NAN, NAN);
+        
+        _displayType = WXDisplayTypeBlock;
+        _isNeedJoinLayoutSystem = YES;
+        _isLayoutDirty = YES;
+        _isViewFrameSyncWithCalculated = YES;
+        _ariaHidden = nil;
+        _accessible = nil;
+        _accessibilityHintContent = nil;
+        
+        _async = NO;
+        
+        if (styles[kWXTransitionProperty]) {
+            _transition = [[WXTransition alloc]initWithStyles:styles];
+        }
+
+        //TODO set indicator style 
+        if ([type isEqualToString:@"indicator"]) {
+            _styles[@"position"] = @"absolute";
+            if (!_styles[@"left"] && !_styles[@"right"]) {
+                _styles[@"left"] = @0.0f;
+            }
+            if (!_styles[@"top"] && !_styles[@"bottom"]) {
+                _styles[@"top"] = @0.0f;
+            }
+        }
+        
+        if (attributes[@"ariaHidden"]) {
+            
+            _ariaHidden = [WXConvert NSString:attributes[@"ariaHidden"]];
+        }
+        if (attributes[@"role"]) {
+            _roles = attributes[@"role"];
+        }
+        if (attributes[@"ariaLabel"]) {
+            _ariaLabel = [WXConvert NSString:attributes[@"ariaLabel"]];
+        }
+        if (attributes[@"accessible"]) {
+            _accessible = [WXConvert NSString:attributes[@"accessible"]];
+        }
+        if(attributes[@"accessibilityHint"]) {
+            _accessibilityHintContent = [WXConvert NSString:attributes[@"accessibilityHint"]];
+        }
+        if (attributes[@"groupAccessibilityChildren"]) {
+            _groupAccessibilityChildren = [WXConvert NSString:attributes[@"groupAccessibilityChildren"]];
+        }
+        
+        if (attributes[@"testId"]) {
+            _testId = [WXConvert NSString:attributes[@"testId"]];
+        }
+        
+#ifdef DEBUG
+        WXLogDebug(@"flexLayout -> init component: ref : %@ , styles: %@",ref,styles);
+        WXLogDebug(@"flexLayout -> init component: ref : %@ , attributes: %@",ref,attributes);
+#endif
+        [self _setupNavBarWithStyles:_styles attributes:_attributes];
+
+        [self _initCSSNodeWithStyles:_styles];
+        [self _initViewPropertyWithStyles:_styles];
+        [self _initCompositingAttribute:_attributes];
+        [self _handleBorders:styles isUpdating:NO];
+        
+    }
+    
+    return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    NSInteger copyId = 0;
+    @synchronized(self){
+        static NSInteger __copy = 0;
+        copyId = __copy % (1024*1024);
+        __copy++;
+    }
+    NSString *copyRef = [NSString stringWithFormat:@"%ldcopy_of%@", (long)copyId, _isTemplate ? self.ref : self->_templateComponent.ref];
+    WXComponent *component = [[[self class] allocWithZone:zone] initWithRef:copyRef type:self.type styles:self.styles attributes:self.attributes events:self.events weexInstance:self.weexInstance];
+    if (_isTemplate) {
+        component->_templateComponent = self;
+    } else {
+        component->_templateComponent = self->_templateComponent;
+    }
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        memcpy(component->_cssNode, self.cssNode, sizeof(css_node_t));
+        component->_cssNode->context = (__bridge void *)component;
+    }
+//#else
+    else
+    {
+        //memcpy((void*)component->_flexCssNode,self.flexCssNode,sizeof(WeexCore::WXCoreLayoutNode));
+        component->_flexCssNode->copyStyle(self.flexCssNode);
+        component->_flexCssNode->copyMeasureFunc(self.flexCssNode);
+        component->_flexCssNode->setContext((__bridge void *)component);
+    }
+//#endif
+    component->_calculatedFrame = self.calculatedFrame;
+    
+    NSMutableArray *subcomponentsCopy = [NSMutableArray array];
+    
+    if ([WXComponent isUseFlex]) {
+        component->_subcomponents = subcomponentsCopy;
+        NSUInteger count = [self.subcomponents count];
+        for (NSInteger i = 0 ; i < count;i++){
+            WXComponent *subcomponentCopy = [[self.subcomponents objectAtIndex:i] copy];
+            [component _insertSubcomponent:subcomponentCopy atIndex:i];
+        }
+    }else{
+        for (WXComponent *subcomponent in self.subcomponents) {
+            WXComponent *subcomponentCopy = [subcomponent copy];
+            subcomponentCopy->_supercomponent = component;
+            [subcomponentsCopy addObject:subcomponentCopy];
+        }
+        component->_subcomponents = subcomponentsCopy;
+    }
+    
+    WXPerformBlockOnComponentThread(^{
+        [self.weexInstance.componentManager addComponent:component toIndexDictForRef:copyRef];
+    });
+    
+    return component;
+}
+
+- (UIAccessibilityTraits)_parseAccessibilityTraitsWithTraits:(UIAccessibilityTraits)trait roles:(NSString*)roleStr
+{
+    UIAccessibilityTraits newTrait = trait;
+    for (NSString * role in [roleStr componentsSeparatedByString:@" "]) {
+        newTrait |= [WXConvert WXUIAccessibilityTraits: role];
+    }
+    
+    return newTrait;
+}
+
+- (void)dealloc
+{
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+         free_css_node(_cssNode);
+    }
+//#else
+    else
+    {
+        if(self.flexCssNode){
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> dealloc %@",self.ref);
+#endif
+            delete self.flexCssNode;
+        }
+    }
+//#endif
+    
+    // remove all gesture and all
+    if (_isTemplate && self.attributes[@"@templateId"]) {
+        [[WXSDKManager bridgeMgr] callComponentHook:_weexInstance.instanceId componentId:self.attributes[@"@templateId"] type:@"lifecycle" hook:@"destroy" args:nil competion:nil];
+    }
+    if (_tapGesture) {
+        [_tapGesture removeTarget:nil action:NULL];
+    }
+    if ([_swipeGestures count]) {
+        for (UISwipeGestureRecognizer *swipeGestures in _swipeGestures) {
+            [swipeGestures removeTarget:nil action:NULL];
+        }
+    }
+    
+    if (_longPressGesture) {
+        [_longPressGesture removeTarget:nil action:NULL];
+    }
+    
+    if (_panGesture) {
+        [_panGesture removeTarget:nil action:NULL];
+    }
+    
+    if (_positionType == WXPositionTypeFixed) {
+        [self.weexInstance.componentManager removeFixedComponent:self];
+    }
+
+    pthread_mutex_destroy(&_propertyMutex);
+    pthread_mutexattr_destroy(&_propertMutexAttr);
+
+}
+
+- (NSDictionary *)styles
+{
+    NSDictionary *styles;
+    pthread_mutex_lock(&_propertyMutex);
+    styles = _styles;
+    pthread_mutex_unlock(&_propertyMutex);
+    return styles;
+}
+
+- (NSDictionary *)pseudoClassStyles
+{
+    NSDictionary *pseudoClassStyles;
+    pthread_mutex_lock(&_propertyMutex);
+    pseudoClassStyles = _pseudoClassStyles;
+    pthread_mutex_unlock(&_propertyMutex);
+    
+    return pseudoClassStyles;
+}
+
+- (NSString *)type
+{
+    return _type;
+}
+
+- (NSDictionary *)attributes
+{
+    NSDictionary *attributes;
+    pthread_mutex_lock(&_propertyMutex);
+    attributes = _attributes;
+    pthread_mutex_unlock(&_propertyMutex);
+    
+    return attributes;
+}
+
+- (NSArray *)events
+{
+    NSArray *events;
+    pthread_mutex_lock(&_propertyMutex);
+    events = [_events copy];
+    pthread_mutex_unlock(&_propertyMutex);
+    
+    return events;
+}
+
+- (void)setDisplayType:(WXDisplayType)displayType
+{
+    if (_displayType != displayType) {
+        _displayType = displayType;
+        if (displayType == WXDisplayTypeNone) {
+            _isNeedJoinLayoutSystem = NO;
+            [self.supercomponent _recomputeCSSNodeChildren];
+            WXPerformBlockOnMainThread(^{
+                [self removeFromSuperview];
+            });
+        } else {
+            _isNeedJoinLayoutSystem = YES;
+            [self.supercomponent _recomputeCSSNodeChildren];
+            WXPerformBlockOnMainThread(^{
+                [self _buildViewHierarchyLazily];
+                // TODO: insert into the correct index
+                [self.supercomponent.view addSubview:self.view];
+            });
+        }
+        [self setNeedsLayout];
+    }
+}
+
+- (WXSDKInstance *)weexInstance
+{
+    return _weexInstance;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@:%p ref=%@> %@", _type, self, _ref, _view];
+}
+
+#pragma mark Property
+
+- (UIView *)view
+{
+    if (_componentType != WXComponentTypeCommon) {
+        return nil;
+    }
+    if ([self isViewLoaded]) {
+        return _view;
+    } else {
+        WXAssertMainThread();
+        
+        // compositing child will be drew by its composited ancestor
+        if (_isCompositingChild) {
+            return nil;
+        }
+        
+        [self viewWillLoad];
+        
+        _view = [self loadView];
+#ifdef DEBUG
+        WXLogDebug(@"flexLayout -> loadView:addr-(%p),componentRef-(%@)",_view,self.ref);
+#endif
+        _layer = _view.layer;
+        _view.frame = [self _fixIllegalFrame:_calculatedFrame];
+        _view.hidden = _visibility == WXVisibilityShow ? NO : YES;
+        _view.clipsToBounds = _clipToBounds;
+        if (![self _needsDrawBorder]) {
+            _layer.borderColor = _borderTopColor.CGColor;
+            _layer.borderWidth = _borderTopWidth;
+            [self _resetNativeBorderRadius];
+            _layer.opacity = _opacity;
+            _view.backgroundColor = _backgroundColor;
+        }
+
+        if (_backgroundImage) {
+            [self setGradientLayer];
+        }
+        
+        if (_transform) {
+            [_transform applyTransformForView:_view];
+        }
+        
+        if (_boxShadow) {
+            [self configBoxShadow:_boxShadow];
+        }
+        
+        _view.wx_component = self;
+        _view.wx_ref = self.ref;
+        _layer.wx_component = self;
+        
+        if (_roles) {
+            [_view setAccessibilityTraits:[self _parseAccessibilityTraitsWithTraits:self.view.accessibilityTraits roles:_roles]];
+        }
+        
+        if (_testId) {
+            _view.accessibilityIdentifier = _testId;
+        }
+        
+        if (_accessibilityHintContent) {
+            [_view setAccessibilityHint:_accessibilityHintContent];
+        }
+        
+        if (_ariaLabel) {
+            _view.accessibilityLabel = _ariaLabel;
+        }
+        if (_accessible) {
+            [_view setIsAccessibilityElement:[WXConvert BOOL:_accessible]];
+        }
+        
+        if (_ariaHidden) {
+            [_view setAccessibilityElementsHidden:[WXConvert BOOL:_ariaHidden]];
+        }
+        if (_groupAccessibilityChildren) {
+            [_view setShouldGroupAccessibilityChildren:[WXConvert BOOL:_groupAccessibilityChildren]];
+        }
+        
+        [self _initEvents:self.events];
+        [self _initPseudoEvents:_isListenPseudoTouch];
+        
+        if (_positionType == WXPositionTypeSticky) {
+            [self.ancestorScroller addStickyComponent:self];
+        }
+        
+        if (self.supercomponent && self.supercomponent->_async) {
+            self->_async = YES;
+        }
+        
+        [self setNeedsDisplay];
+        [[NSNotificationCenter defaultCenter] postNotificationName:WX_COMPONENT_NOTIFICATION_VIEW_LOADED object:self];
+        [self viewDidLoad];
+        
+        if (_lazyCreateView) {
+            [self _buildViewHierarchyLazily];
+        }
+
+        [self _handleFirstScreenTime];
+        
+        return _view;
+    }
+}
+
+- (CGRect)_fixIllegalFrame:(CGRect)frame{
+    CGPoint origin = frame.origin;
+    CGSize size = frame.size;
+    CGRect fixedFrame = CGRectMake(isnan(origin.x)?0.0f:origin.x
+                                   , isnan(origin.y)?0.0f:origin.y
+                                   , isnan(size.width)?0.0f:size.width
+                                   , isnan(size.height)?0.0f:size.height);
+    return fixedFrame;
+}
+
+- (void)_buildViewHierarchyLazily
+{
+    if (self.supercomponent && !((WXComponent *)self.supercomponent)->_lazyCreateView) {
+        NSArray *subcomponents = ((WXComponent *)self.supercomponent).subcomponents;
+        
+        NSInteger index = [subcomponents indexOfObject:self];
+        if (index != NSNotFound) {
+            [(WXComponent *)self.supercomponent insertSubview:self atIndex:index];
+        }
+    }
+    
+    NSArray *subcomponents = self.subcomponents;
+    for (int i = 0; i < subcomponents.count; i++) {
+        WXComponent *subcomponent = subcomponents[i];
+        [self insertSubview:subcomponent atIndex:i];
+    }
+}
+
+- (void)_resetNativeBorderRadius
+{
+    WXRoundedRect *borderRect = [[WXRoundedRect alloc] initWithRect:_calculatedFrame topLeft:_borderTopLeftRadius topRight:_borderTopRightRadius bottomLeft:_borderBottomLeftRadius bottomRight:_borderBottomRightRadius];
+    _layer.cornerRadius = borderRect.radii.topLeft;
+}
+
+- (void)_handleFirstScreenTime
+{
+    if (WX_MONITOR_INSTANCE_PERF_IS_RECORDED(WXPTFirstScreenRender, self.weexInstance)) {
+        return;
+    }
+    CGPoint absolutePosition = [self.supercomponent.view convertPoint:_view.frame.origin toView:_weexInstance.rootView];
+    if (absolutePosition.y + _view.frame.size.height > self.weexInstance.rootView.frame.size.height + 1) {
+        WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, self.weexInstance);
+    }
+}
+
+- (CALayer *)layer
+{
+    return _layer;
+}
+
+- (CGRect)calculatedFrame
+{
+    return _calculatedFrame;
+}
+
+- (CGPoint)absolutePosition
+{
+    return _absolutePosition;
+}
+
+//#ifndef USE_FLEX
+- (css_node_t *)cssNode
+{
+    return _cssNode;
+}
+//#else
+//#endif
+
+- (void)_addEventParams:(NSDictionary *)params
+{
+    pthread_mutex_lock(&_propertyMutex);
+    if (!_eventParameters) {
+        _eventParameters = [NSMutableDictionary dictionary];
+    }
+    [_eventParameters addEntriesFromDictionary:params];
+    pthread_mutex_unlock(&_propertyMutex);
+}
+
+- (NSArray *)_paramsForEvent:(NSString *)eventName
+{
+    NSArray *params;
+    pthread_mutex_lock(&_propertyMutex);
+    params = _eventParameters[eventName];
+    pthread_mutex_unlock(&_propertyMutex);
+    
+    return params;
+}
+
+#pragma mark Component Hierarchy 
+
+- (NSArray<WXComponent *> *)subcomponents
+{
+    NSArray<WXComponent *> *subcomponents;
+    pthread_mutex_lock(&_propertyMutex);
+    subcomponents = [_subcomponents copy];
+    pthread_mutex_unlock(&_propertyMutex);
+    
+    return subcomponents;
+}
+
+- (WXComponent *)supercomponent
+{
+    return _supercomponent;
+}
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    WXAssert(subcomponent, @"The subcomponent to insert to %@ at index %d must not be nil", self, index);
+    if (index > [_subcomponents count]) {
+        WXLogError(@"the index of inserted %ld is out of range as the current is %lu", (long)index, (unsigned long)[_subcomponents count]);
+        return;
+    }
+    
+    subcomponent->_supercomponent = self;
+    
+    pthread_mutex_lock(&_propertyMutex);
+    [_subcomponents insertObject:subcomponent atIndex:index];
+    pthread_mutex_unlock(&_propertyMutex);
+    
+    if (subcomponent->_positionType == WXPositionTypeFixed) {
+        [self.weexInstance.componentManager addFixedComponent:subcomponent];
+        subcomponent->_isNeedJoinLayoutSystem = NO;
+    }
+    
+    if (_useCompositing || _isCompositingChild) {
+        subcomponent->_isCompositingChild = YES;
+    }
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        
+    }
+//#else
+    else
+    {
+        if (subcomponent->_isNeedJoinLayoutSystem) {
+            NSInteger actualIndex = [self getActualNodeIndex:subcomponent atIndex:index];
+            [self _insertChildCssNode:subcomponent atIndex:actualIndex];
+        }else{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> no need JoinLayoutSystem parent ref:%@ type:%@, self ref:%@ type:%@ ",
+                  self.ref,
+                  self.type,
+                  subcomponent.ref,
+                  subcomponent.type
+                  );
+#endif
+        }
+    }
+//#endif
+    
+    [self _recomputeCSSNodeChildren];
+    [self setNeedsLayout];
+}
+
+- (void)_removeSubcomponent:(WXComponent *)subcomponent
+{
+    pthread_mutex_lock(&_propertyMutex);
+    [_subcomponents removeObject:subcomponent];
+//#ifndef USE_FLEX
+      if (![WXComponent isUseFlex]) {
+      }
+//#else
+    else
+    {
+        //subcomponent->_isNeedJoinLayoutSystem = NO;
+        [self _rmChildCssNode:subcomponent];
+    }
+//#endif
+    pthread_mutex_unlock(&_propertyMutex);
+}
+
+- (void)_removeFromSupercomponent
+{
+    [self.supercomponent _removeSubcomponent:self];
+    [self.supercomponent _recomputeCSSNodeChildren];
+    [self.supercomponent setNeedsLayout];
+    
+    if (_positionType == WXPositionTypeFixed) {
+        [self.weexInstance.componentManager removeFixedComponent:self];
+        self->_isNeedJoinLayoutSystem = YES;
+    }
+}
+
+- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
+{
+    [self _removeFromSupercomponent];
+    [newSupercomponent _insertSubcomponent:self atIndex:index];
+}
+
+- (void)_didInserted
+{
+    
+}
+
+- (id<WXScrollerProtocol>)ancestorScroller
+{
+    if(!_ancestorScroller) {
+        WXComponent *supercomponent = self.supercomponent;
+        while (supercomponent) {
+            if([supercomponent conformsToProtocol:@protocol(WXScrollerProtocol)]) {
+                _ancestorScroller = (id<WXScrollerProtocol>)supercomponent;
+                break;
+            }
+            supercomponent = supercomponent.supercomponent;
+        }
+    }
+    
+    return _ancestorScroller;
+}
+
+#pragma mark Updating
+- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles
+{
+    NSLog(@"tempTest updating");
+    
+    BOOL isTransitionTag = _transition ? [self _isTransitionTag:styles] : NO;
+    if (isTransitionTag) {
+        [_transition _handleTransitionWithStyles:styles resetStyles:resetStyles target:self];
+    } else {
+        styles = [self parseStyles:styles];
+        [self _updateCSSNodeStyles:styles];
+        [self _resetCSSNodeStyles:resetStyles];
+    }
+    if (isUpdateStyles) {
+        [self _modifyStyles:styles];
+        if ([self needsLayout]) {
+            // call update style may take effect on layout, maybe the component
+            // displaylink has been paused, so we need to restart the component task, and it will auto-pause when task queue is empty.
+            [self.weexInstance.componentManager startComponentTasks];
+        }
+    }
+}
+
+- (BOOL)_isTransitionTag:(NSDictionary *)styles
+{
+    BOOL yesOrNo = false;
+    if (_transition.transitionOptions != WXTransitionOptionsNone) {
+        yesOrNo = true;
+    }
+    return yesOrNo;
+}
+
+- (BOOL)_isTransitionOnMainThreadStyles:(NSDictionary *)styles
+{
+    BOOL yesOrNo = false;
+    if (_transition.transitionOptions != WXTransitionOptionsNone) {
+        if ((_transition.transitionOptions & WXTransitionOptionsBackgroundColor &&styles[@"backgroundColor"])
+            ||(_transition.transitionOptions & WXTransitionOptionsTransform &&styles[@"transform"])
+            ||(_transition.transitionOptions & WXTransitionOptionsOpacity &&styles[@"opacity"])) {
+            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);
+    [_attributes addEntriesFromDictionary:attributes];
+    pthread_mutex_unlock(&_propertyMutex);
+}
+
+- (void)_addEventOnComponentThread:(NSString *)eventName
+{
+    pthread_mutex_lock(&_propertyMutex);
+    [_events addObject:eventName];
+    pthread_mutex_unlock(&_propertyMutex);
+}
+
+- (void)_removeEventOnComponentThread:(NSString *)eventName
+{
+    pthread_mutex_lock(&_propertyMutex);
+    [_events removeObject:eventName];
+    pthread_mutex_unlock(&_propertyMutex);
+}
+
+- (void)_updateStylesOnMainThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles
+{
+    WXAssertMainThread();
+    if (![self _isTransitionOnMainThreadStyles:styles]) {
+        [self _updateViewStyles:styles];
+    } else {
+        [self _transitionUpdateViewProperty:styles];
+    }
+#ifdef DEBUG
+    NSDictionary *copySelfStyle = [NSDictionary dictionaryWithDictionary:self.styles];
+    WXLogDebug(@"flexLayout -> ref:%@ style before : %@",self.ref,copySelfStyle);
+    
+    if (styles) {
+        WXLogDebug(@"flexLayout -> ref:%@ update styles : %@",self.ref,styles);
+    }
+    
+    if (resetStyles) {
+        WXLogDebug(@"flexLayout -> ref:%@ update resetStyles : %@",self.ref,resetStyles);
+    }
+#endif
+    
+    [self _resetStyles:resetStyles];
+    [self _handleBorders:styles isUpdating:YES];
+    [self updateStyles:styles];
+    [self resetStyles:resetStyles];
+    
+#ifdef DEBUG
+    //self.styles may change
+    copySelfStyle = [NSDictionary dictionaryWithDictionary:self.styles];
+    WXLogDebug(@"flexLayout -> ref:%@ style after : %@",self.ref,copySelfStyle);
+#endif
+}
+
+- (void)_updateAttributesOnMainThread:(NSDictionary *)attributes
+{
+    WXAssertMainThread();
+    
+    [self _updateNavBarAttributes:attributes];
+    
+    [self updateAttributes:attributes];
+    [self _configWXComponentA11yWithAttributes:attributes];
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+    WXAssertMainThread();
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    WXAssertMainThread();
+}
+
+- (void)setNativeTransform:(CGAffineTransform)transform
+{
+    WXAssertMainThread();
+    
+    _transform = [[WXTransform alloc] initWithNativeTransform:CATransform3DMakeAffineTransform(transform) instance:self.weexInstance];
+    if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
+        [_transform applyTransformForView:_view];
+        [_layer setNeedsDisplay];
+    }
+}
+
+- (void)readyToRender
+{
+    if (self.weexInstance.trackComponent) {
+        [self.supercomponent readyToRender];
+    }
+}
+
+
+- (void)setGradientLayer
+{
+    if (CGRectEqualToRect(self.view.frame, CGRectZero)) {
+        return;
+    }
+    NSDictionary * linearGradient = [WXUtility linearGradientWithBackgroundImage:_backgroundImage];
+    if (!linearGradient) {
+        return ;
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    dispatch_async(dispatch_get_main_queue(), ^{
+        __strong typeof(self) strongSelf = weakSelf;
+        if(strongSelf) {
+            UIColor * startColor = (UIColor*)linearGradient[@"startColor"];
+            UIColor * endColor = (UIColor*)linearGradient[@"endColor"];
+            CAGradientLayer * gradientLayer = [WXUtility gradientLayerFromColors:@[startColor, endColor] locations:nil frame:strongSelf.view.bounds gradientType:(WXGradientType)[linearGradient[@"gradientType"] integerValue]];
+            if (gradientLayer) {
+                _backgroundColor = [UIColor colorWithPatternImage:[strongSelf imageFromLayer:gradientLayer]];
+                strongSelf.view.backgroundColor = _backgroundColor;
+            }
+        }
+    });
+}
+
+- (void)_configWXComponentA11yWithAttributes:(NSDictionary *)attributes
+{
+    WX_CHECK_COMPONENT_TYPE(self.componentType)
+    if (attributes[@"role"]){
+        _roles = attributes[@"role"];
+        [self.view setAccessibilityTraits:[self _parseAccessibilityTraitsWithTraits:self.view.accessibilityTraits roles:_roles]];
+    }
+    if (attributes[@"ariaHidden"]) {
+        _ariaHidden = [WXConvert NSString:attributes[@"ariaHidden"]];
+        [self.view setAccessibilityElementsHidden:[WXConvert BOOL:_ariaHidden]];
+    }
+    if (attributes[@"accessible"]) {
+        _accessible = [WXConvert NSString:attributes[@"accessible"]];
+        [self.view setIsAccessibilityElement:[WXConvert BOOL:_accessible]];
+    }
+    if (attributes[@"ariaLabel"]) {
+        _ariaLabel = [WXConvert NSString:attributes[@"ariaLabel"]];
+        self.view.accessibilityValue = _ariaLabel;
+    }
+    if (attributes[@"accessibilityHint"]) {
+        _accessibilityHintContent = [WXConvert NSString:attributes[@"accessibilityHint"]];
+        [self.view setAccessibilityHint:_accessibilityHintContent];
+    }
+    
+    if (attributes[@"groupAccessibilityChildren"]) {
+        _groupAccessibilityChildren = [WXConvert NSString:attributes[@"groupAccessibilityChildren"]];
+        [self.view setShouldGroupAccessibilityChildren:[WXConvert BOOL:_groupAccessibilityChildren]];
+    }
+
+    
+    if (attributes[@"testId"]) {
+        [self.view setAccessibilityIdentifier:[WXConvert NSString:attributes[@"testId"]]];
+    }
+
+}
+
+- (UIImage *)imageFromLayer:(CALayer *)layer
+{
+    UIGraphicsBeginImageContextWithOptions(layer.frame.size, NO, 0);
+    [layer renderInContext:UIGraphicsGetCurrentContext()];
+    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return outputImage;
+}
+
+#pragma mark Reset
+- (void)resetStyles:(NSArray *)styles
+{
+    WXAssertMainThread();
+}
+
+#pragma mark Layout
+
+/**
+ *  @see WXComponent+Layout.m
+ */
+
+#pragma mark View Management
+
+/**
+ *  @see WXComponent+ViewManagement.m
+ */
+
+#pragma mark Events
+
+/**
+ *  @see WXComponent+Events.m
+ */
+
+#pragma mark Display
+
+/**
+ *  @see WXComponent+Display.m
+ */
+
+@end
+
+
+@implementation UIView (WXComponent)
+
+- (WXComponent *)wx_component
+{
+    WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_component));
+    return [weakWrapper weakObject];
+}
+
+- (void)setWx_component:(WXComponent *)wx_component
+{
+    id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_component];
+    objc_setAssociatedObject(self, @selector(wx_component), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (NSString *)wx_ref
+{
+    WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_ref));
+    return [weakWrapper weakObject];
+}
+
+- (void)setWx_ref:(NSString *)wx_ref
+{
+    id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_ref];
+    objc_setAssociatedObject(self, @selector(wx_ref), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+@end
+
+@implementation CALayer (WXComponents_new)
+
+- (WXComponent *)wx_component
+{
+    WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_component));
+    return [weakWrapper weakObject];
+}
+
+- (void)setWx_component:(WXComponent *)wx_component
+{
+    id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_component];
+    objc_setAssociatedObject(self, @selector(wx_component), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
index 13fc4cf..b4c5a2e 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
@@ -76,7 +76,8 @@ typedef enum : NSUInteger {
     BOOL _needDestroy;
     BOOL _syncDestroyComponentManager;
     BOOL _debugJS;
-    id<WXBridgeProtocol> _instanceJavaScriptContext; // sandbox javaScript context
+    id<WXBridgeProtocol> _instanceJavaScriptContext; // sandbox javaScript context    
+    CGFloat _defaultPixelScaleFactor;
 }
 
 - (void)dealloc
@@ -102,7 +103,7 @@ typedef enum : NSUInteger {
             __instance++;
         }
         _instanceId = [NSString stringWithFormat:@"%ld", (long)instanceId];
-
+        
         [WXSDKManager storeInstance:self forID:_instanceId];
         
         _bizType = @"";
@@ -122,6 +123,7 @@ typedef enum : NSUInteger {
         if ([configCenter respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) {
             _syncDestroyComponentManager = [[configCenter configForKey:@"iOS_weex_ext_config.syncDestroyComponentManager" defaultValue:@(YES) isDefault:NULL] boolValue];
         }
+        _defaultPixelScaleFactor = CGFLOAT_MIN;
         
         [self addObservers];
     }
@@ -183,6 +185,9 @@ typedef enum : NSUInteger {
 
 - (void)setFrame:(CGRect)frame
 {
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> setFrame :%@,instance :%@",NSStringFromCGRect(frame),self);
+#endif
     if (!CGRectEqualToRect(frame, _frame)) {
         _frame = frame;
         WXPerformBlockOnMainThread(^{
@@ -583,7 +588,12 @@ typedef enum : NSUInteger {
     if (self.viewportWidth > 0) {
         return [WXUtility portraitScreenSize].width / self.viewportWidth;
     } else {
-        return [WXUtility defaultPixelScaleFactor];
+        if (_defaultPixelScaleFactor != CGFLOAT_MIN) {
+            return _defaultPixelScaleFactor;
+        }
+        
+        _defaultPixelScaleFactor = [WXUtility defaultPixelScaleFactor];
+        return _defaultPixelScaleFactor;
     }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/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
deleted file mode 100644
index 8e982ac..0000000
--- a/ios/sdk/WeexSDK/Sources/Module/WXTransition.m
+++ /dev/null
@@ -1,519 +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.
- */
-
-#define SOLVE_EPS(dur) (1. / (1000. * (dur)))
-
-#import <QuartzCore/CATransaction.h>
-#import <QuartzCore/CADisplayLink.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"
-#import "WXLength.h"
-
-@implementation WXTransitionInfo
-@end
-
-@interface WXTransition()
-{
-    WXComponent *_targetComponent;
-    double ax;
-    double bx;
-    double cx;
-    
-    double ay;
-    double by;
-    double cy;
-    
-    float _transitionDuration;
-    float _transitionDelay;
-    NSUInteger _transitionCount;
-    
-    CAMediaTimingFunction *_transitionTimingFunction;
-    CADisplayLink *_transitionDisplayLink;
-
-    NSMutableDictionary *_filterStyles;
-    NSMutableDictionary *_oldFilterStyles;
-}
-
-@end
-
-@implementation WXTransition
-
-- (instancetype)initWithStyles:(NSDictionary *)styles
-{
-    if (self = [super init]) {
-        NSString *property = styles[kWXTransitionProperty];
-        NSArray *properties = [property componentsSeparatedByString:@","];
-        for (NSString *string in properties) {
-            _transitionOptions |= [self transitionOptionsFromString:string];
-        }
-    }
-    return self;
-}
-
-#pragma mark - HandleStyle
-- (WXTransitionOptions)transitionOptionsFromString:(NSString *)string
-{
-    NSDictionary<NSString*,NSNumber*> *options = @{
-                                                  @"width": @(WXTransitionOptionsWidth),
-                                                  @"height": @(WXTransitionOptionsHeight),
-                                                  @"right": @(WXTransitionOptionsRight),
-                                                  @"left": @(WXTransitionOptionsLeft),
-                                                  @"bottom": @(WXTransitionOptionsBottom),
-                                                  @"top": @(WXTransitionOptionsTop),
-                                                  @"backgroundColor": @(WXTransitionOptionsBackgroundColor),
-                                                  @"transform": @(WXTransitionOptionsTransform),
-                                                  @"opacity": @(WXTransitionOptionsOpacity),
-                                                  };
-    return options[string].integerValue;
-}
-
-- (void)_handleTransitionWithStyles:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles target:(WXComponent *)targetComponent
-{
-    BOOL isRunning = [self _isTransitionRunning];
-    if (isRunning) {
-        [self _rollBackTransitionWithStyles:styles];
-    }
-    else
-    {
-        [self _suspendTransitionDisplayLink];
-    }
-    
-    _filterStyles = _filterStyles ?:[NSMutableDictionary new];
-    _oldFilterStyles = _oldFilterStyles ?: [NSMutableDictionary new];
-    NSMutableDictionary *futileStyles = [NSMutableDictionary new];
-    
-    for (NSString *key in styles) {
-        if (self.transitionOptions & [self transitionOptionsFromString:key]) {
-            [_filterStyles setObject:styles[key] forKey:key];
-            if (![key isEqualToString:@"transform"]) {
-                if (!isRunning) {
-                    [_oldFilterStyles setObject:targetComponent.styles[key] forKey:key];
-                }
-            }
-        }
-        else
-        {
-            [futileStyles setObject:styles[key] forKey:key];
-        }
-    }
-    [self updateFutileStyles:futileStyles resetStyles:nil target:targetComponent];
-
-    _targetComponent = targetComponent;
-    NSMutableDictionary *componentStyles = [NSMutableDictionary dictionaryWithDictionary:styles];
-    [componentStyles addEntriesFromDictionary:targetComponent.styles];
-
-    _transitionDuration = componentStyles[kWXTransitionDuration] ? [WXConvert CGFloat:componentStyles[kWXTransitionDuration]] : 0;
-    _transitionDelay = componentStyles[kWXTransitionDelay] ? [WXConvert CGFloat:componentStyles[kWXTransitionDelay]] : 0;
-    _transitionTimingFunction = [WXConvert CAMediaTimingFunction:componentStyles[kWXTransitionTimingFunction]];
-    
-    if (_transitionDuration == 0 ) {
-        [self updateFutileStyles:_filterStyles resetStyles:nil target:targetComponent];
-        return;
-    }
-    
-    if (![[NSString stringWithFormat:@"%@",_transitionTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) {
-        float vec[4] = {0.};
-        [_transitionTimingFunction getControlPointAtIndex:1 values:&vec[0]];
-        [_transitionTimingFunction getControlPointAtIndex:2 values:&vec[2]];
-        [self unitBezierp1x:vec[0] p1y:vec[1] p2x:vec[2] p2y:vec[3]];
-    }
-    
-    [self _resloveTransitionProperty];
-    [self performSelector:@selector(_startTransitionDisplayLink) withObject:self afterDelay:_transitionDelay/1000];
-}
-
-- (void)updateFutileStyles:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles target:(WXComponent *)targetComponent
-{
-    [targetComponent _updateCSSNodeStyles:styles];
-    [targetComponent _resetCSSNodeStyles:resetStyles];
-    WXPerformBlockOnMainThread(^{
-        [targetComponent _updateViewStyles:styles];
-    });
-}
-
-- (void)_rollBackTransitionWithStyles:(NSDictionary *)styles
-{
-    _transitionDuration = _transitionCount * 1000 / 60;
-    _transitionCount = 0;
-    _propertyArray = nil;
-}
-
-- (void)_resloveTransitionProperty
-{
-    if (_filterStyles.count == 0) {
-        return;
-    }
-    for (NSString * name  in _filterStyles.allKeys) {
-        [self _dealTransitionWithProperty:name];
-    }
-}
-
-- (void)_dealTransitionWithProperty:(NSString *)singleProperty
-{
-    if (_filterStyles[singleProperty])
-    {
-        if (!_propertyArray) {
-            _propertyArray = [NSMutableArray new];
-        }
-        if ([singleProperty isEqualToString:@"backgroundColor"]) {
-            WXTransitionInfo *info = [WXTransitionInfo new];
-            info.fromValue = [self _dealWithColor:[WXConvert UIColor:_oldFilterStyles[singleProperty]]];
-            info.toValue = [self _dealWithColor:[WXConvert UIColor:_filterStyles[singleProperty]]];
-            info.perValue = [self _calculatePerColorRGB1:info.toValue RGB2:info.fromValue];
-            info.propertyName = singleProperty;
-            [_propertyArray addObject:info];
-        }
-        else if ([singleProperty isEqualToString:@"transform"]) {
-            NSString *transformOrigin = _filterStyles[@"transformOrigin"];
-            WXTransform *wxTransform = [[WXTransform alloc] initWithCSSValue:_filterStyles[singleProperty] origin:transformOrigin instance:_targetComponent.weexInstance];
-            WXTransform *oldTransform = _targetComponent->_transform;
-            if (wxTransform.rotateAngle != oldTransform.rotateAngle) {
-                WXTransitionInfo *info = [WXTransitionInfo new];
-                info.propertyName = @"transform.rotation";
-                info.fromValue = @(oldTransform.rotateAngle);
-                info.toValue = [NSNumber numberWithDouble:wxTransform.rotateAngle];
-                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
-                [_propertyArray addObject:info];
-            }
-            if (wxTransform.rotateX != oldTransform.rotateX)
-            {
-                WXTransitionInfo *info = [WXTransitionInfo new];
-                info.propertyName = @"transform.rotation.x";
-                info.fromValue = @(oldTransform.rotateX);
-                info.toValue = [NSNumber numberWithDouble:wxTransform.rotateX];
-                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
-                [_propertyArray addObject:info];
-            }
-            if (wxTransform.rotateY != oldTransform.rotateY)
-            {
-                WXTransitionInfo *info = [WXTransitionInfo new];
-                info.propertyName = @"transform.rotation.y";
-                info.fromValue = @(oldTransform.rotateY);
-                info.toValue = [NSNumber numberWithDouble:wxTransform.rotateY];
-                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
-                [_propertyArray addObject:info];
-            }
-            if (wxTransform.rotateZ != oldTransform.rotateZ)
-            {
-                WXTransitionInfo *info = [WXTransitionInfo new];
-                info.propertyName = @"transform.rotation.z";
-                info.fromValue = @(oldTransform.rotateZ);
-                info.toValue = [NSNumber numberWithDouble:wxTransform.rotateZ];
-                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
-                [_propertyArray addObject:info];
-            }
-            if (wxTransform.scaleX != oldTransform.scaleX) {
-                WXTransitionInfo *info = [WXTransitionInfo new];
-                info.propertyName = @"transform.scale.x";
-                info.fromValue = @(oldTransform.scaleX);
-                info.toValue = @(wxTransform.scaleX);
-                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
-                [_propertyArray addObject:info];
-            }
-            if (wxTransform.scaleY != oldTransform.scaleY) {
-                WXTransitionInfo *info = [WXTransitionInfo new];
-                info.propertyName = @"transform.scale.y";
-                info.fromValue = @(oldTransform.scaleY);
-                info.toValue = @(wxTransform.scaleY);
-                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
-                [_propertyArray addObject:info];
-            }
-            if (wxTransform.translateX && [wxTransform.translateX floatValue] !=[oldTransform.translateX floatValue]) {
-                WXTransitionInfo *info = [WXTransitionInfo new];
-                info.propertyName = @"transform.translation.x";
-                info.fromValue = @([oldTransform.translateX floatValue]);
-                info.toValue = @([wxTransform.translateX floatValue]);
-                info.perValue = @([wxTransform.translateX floatValue] - [oldTransform.translateX floatValue]);
-                [_propertyArray addObject:info];
-            }
-            if (wxTransform.translateY && [wxTransform.translateY floatValue] !=[oldTransform.translateY floatValue]) {
-                WXTransitionInfo *info = [WXTransitionInfo new];
-                info.propertyName = @"transform.translation.y";
-                info.fromValue = @([oldTransform.translateY floatValue]);
-                info.toValue = @([wxTransform.translateY floatValue]);
-                info.perValue = @([wxTransform.translateY floatValue] - [oldTransform.translateY floatValue]);
-                [_propertyArray addObject:info];
-            }
-            _targetComponent->_transform = wxTransform;
-        }
-        else
-        {
-            WXTransitionInfo *info = [WXTransitionInfo new];
-            info.fromValue = @(_oldFilterStyles[singleProperty] ? [WXConvert CGFloat:_oldFilterStyles[singleProperty]] : 0);
-            info.toValue = @(_filterStyles[singleProperty] ? [WXConvert CGFloat:_filterStyles[singleProperty]] : 0 );
-            info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
-            info.propertyName = singleProperty;
-            [_propertyArray addObject:info];
-        }
-    }
-}
-
-- (NSArray *)_dealWithColor:(UIColor *)color
-{
-    CGFloat R, G, B, A;
-    [color getRed:&R green:&G blue:&B alpha:&A];
-    return @[@(R),@(G),@(B),@(A)];
-}
-
-- (NSArray *)_calculatePerColorRGB1:(NSArray *)RGB1 RGB2:(NSArray *)RGB2
-{
-    CGFloat R = [RGB1[0] doubleValue] - [RGB2[0] doubleValue];
-    CGFloat G = [RGB1[1] doubleValue] - [RGB2[1] doubleValue];
-    CGFloat B = [RGB1[2] doubleValue] - [RGB2[2] doubleValue];
-    CGFloat A = [RGB1[3] doubleValue] - [RGB2[3] doubleValue];
-    return @[@(R),@(G),@(B),@(A)];
-}
-
-- (void)_calculatetransitionProcessingStyle
-{
-    if (_propertyArray.count == 0) {
-        return;
-    }
-    double per = 1000 * (_transitionCount + 1 ) / (60 * _transitionDuration);//linear
-    if (![[NSString stringWithFormat:@"%@",_transitionTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) {
-        per = [self solveWithx:((_transitionCount+2)*16)/_transitionDuration epsilon:SOLVE_EPS(_transitionDuration)];
-    }
-    NSString *transformString = [NSString string];
-    for (WXTransitionInfo *info in _propertyArray) {
-        if ([info.propertyName isEqualToString:@"backgroundColor"]) {
-            NSArray *array = @[
-                               @([info.fromValue[0] floatValue] + [info.perValue[0] floatValue] * per),
-                               @([info.fromValue[1] floatValue] + [info.perValue[1] floatValue] * per),
-                               @([info.fromValue[2] floatValue] + [info.perValue[2] floatValue] * per),
-                               @([info.fromValue[3] floatValue] + [info.perValue[3] floatValue] * per)];
-            UIColor *color = [UIColor colorWithRed:[array[0] floatValue] green:[array[1] floatValue] blue:[array[2] floatValue] alpha:[array[3] floatValue]];
-            WXPerformBlockOnMainThread(^{
-                _targetComponent.view.backgroundColor = color;
-                [_targetComponent.view setNeedsDisplay];
-            });
-            NSString *colorString = [WXConvert HexWithColor:color];
-            [_oldFilterStyles setObject:colorString forKey:info.propertyName];
-        }
-        else if ([info.propertyName hasPrefix:@"transform"])
-        {
-            double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per;
-            NSString *newString = [NSString string];
-            if ([info.propertyName isEqualToString:@"transform.rotation"]) {
-                newString = [NSString stringWithFormat:@"rotate(%lfdeg)",currentValue * 180.0 / M_PI];
-                transformString = [transformString stringByAppendingFormat:@" %@",newString];
-            }
-            if ([info.propertyName isEqualToString:@"transform.rotation.x"]) {
-                newString = [NSString stringWithFormat:@"rotateX(%lfdeg)",currentValue * 180.0 / M_PI];
-                transformString = [transformString stringByAppendingFormat:@" %@",newString];
-            }
-            if ([info.propertyName isEqualToString:@"transform.rotation.y"]) {
-                newString = [NSString stringWithFormat:@"rotateY(%lfdeg)",currentValue * 180.0 / M_PI];
-                transformString = [transformString stringByAppendingFormat:@" %@",newString];
-            }
-            if ([info.propertyName isEqualToString:@"transform.rotation.z"]) {
-                newString = [NSString stringWithFormat:@"rotateZ(%lfdeg)",currentValue * 180.0 / M_PI];
-                transformString = [transformString stringByAppendingFormat:@" %@",newString];
-            }
-            if ([info.propertyName isEqualToString:@"transform.scale.x"]) {
-                newString = [NSString stringWithFormat:@"scaleX(%lf)",currentValue];
-                transformString = [transformString stringByAppendingFormat:@" %@",newString];
-            }
-            if ([info.propertyName isEqualToString:@"transform.scale.y"]) {
-                newString = [NSString stringWithFormat:@"scaleY(%lf)",currentValue];
-                transformString = [transformString stringByAppendingFormat:@" %@",newString];
-            }
-            if ([info.propertyName isEqualToString:@"transform.translation.x"]) {
-                newString = [NSString stringWithFormat:@"translateX(%lfpx)",currentValue / _targetComponent.weexInstance.pixelScaleFactor];
-                transformString = [transformString stringByAppendingFormat:@" %@",newString];
-            }
-            if ([info.propertyName isEqualToString:@"transform.translation.y"]) {
-                newString = [NSString stringWithFormat:@"translateY(%lfpx)",currentValue / _targetComponent.weexInstance.pixelScaleFactor];
-                transformString = [transformString stringByAppendingFormat:@" %@",newString];
-            }
-            [_oldFilterStyles setObject:transformString forKey:@"transform"];
-        }
-        else
-        {
-            double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per;
-            [_oldFilterStyles setObject:@(currentValue) forKey:info.propertyName];
-        }
-    }
-    WXPerformBlockOnMainThread(^{
-        [_targetComponent _updateViewStyles:_oldFilterStyles];
-    });
-    [_targetComponent _updateCSSNodeStyles:_oldFilterStyles];
-    [_targetComponent.weexInstance.componentManager startComponentTasks];
-}
-
-#pragma mark CADisplayLink
-- (void)_startTransitionDisplayLink
-{
-    WXAssertComponentThread();
-    if (!_transitionDisplayLink) {
-        _transitionDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleTransitionDisplayLink)];
-        [_transitionDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-    }
-    else{
-        [self _awakeTransitionDisplayLink];
-    }
-}
-
-- (void)_stopTransitionDisplayLink
-{
-    WXAssertComponentThread();
-    if (_transitionDisplayLink) {
-        [_transitionDisplayLink invalidate];
-        _transitionDisplayLink = nil;
-    }
-}
-
-- (BOOL)_isTransitionRunning
-{
-    WXAssertComponentThread();
-    BOOL yesOrNo = NO;
-    if (!_transitionDisplayLink.paused && _transitionCount >= 5) {
-        yesOrNo = YES;
-    }
-    return yesOrNo;
-}
-
-- (void)_suspendTransitionDisplayLink
-{
-    WXAssertComponentThread();
-    if(_transitionDisplayLink && !_transitionDisplayLink.paused){
-        _transitionDisplayLink.paused = YES;
-    }
-}
-
-- (void)_awakeTransitionDisplayLink
-{
-    WXAssertComponentThread();
-    if (_transitionDisplayLink && _transitionDisplayLink.paused) {
-        _transitionDisplayLink.paused = NO;
-    }
-}
-
-- (void)_handleTransitionDisplayLink
-{
-    WXAssertComponentThread();
-    int count = _transitionDuration * 60 / 1000;
-    if (_transitionCount >= count) {
-        [self _suspendTransitionDisplayLink];
-        [self _resetProcessAnimationParameter];
-        return;
-    }
-    else
-    {
-        [self _calculatetransitionProcessingStyle];
-    }
-    _transitionCount ++;
-}
-
-- (void)_resetProcessAnimationParameter
-{
-    _transitionCount = 0;
-    _transitionDuration = 0;
-    _propertyArray = nil;
-    _oldFilterStyles = nil;
-    _filterStyles= nil;
-}
-
-- (NSMutableDictionary *)_filterStyles
-{
-    return self.filterStyles;
-}
-
-- (NSMutableDictionary *)_oldFilterStyles
-{
-    return self.oldFilterStyles;
-}
-
-#pragma mark UnitBezierp
-- (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/b77b4259/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm b/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm
new file mode 100644
index 0000000..8e982ac
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm
@@ -0,0 +1,519 @@
+/*
+ * 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 "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"
+#import "WXLength.h"
+
+@implementation WXTransitionInfo
+@end
+
+@interface WXTransition()
+{
+    WXComponent *_targetComponent;
+    double ax;
+    double bx;
+    double cx;
+    
+    double ay;
+    double by;
+    double cy;
+    
+    float _transitionDuration;
+    float _transitionDelay;
+    NSUInteger _transitionCount;
+    
+    CAMediaTimingFunction *_transitionTimingFunction;
+    CADisplayLink *_transitionDisplayLink;
+
+    NSMutableDictionary *_filterStyles;
+    NSMutableDictionary *_oldFilterStyles;
+}
+
+@end
+
+@implementation WXTransition
+
+- (instancetype)initWithStyles:(NSDictionary *)styles
+{
+    if (self = [super init]) {
+        NSString *property = styles[kWXTransitionProperty];
+        NSArray *properties = [property componentsSeparatedByString:@","];
+        for (NSString *string in properties) {
+            _transitionOptions |= [self transitionOptionsFromString:string];
+        }
+    }
+    return self;
+}
+
+#pragma mark - HandleStyle
+- (WXTransitionOptions)transitionOptionsFromString:(NSString *)string
+{
+    NSDictionary<NSString*,NSNumber*> *options = @{
+                                                  @"width": @(WXTransitionOptionsWidth),
+                                                  @"height": @(WXTransitionOptionsHeight),
+                                                  @"right": @(WXTransitionOptionsRight),
+                                                  @"left": @(WXTransitionOptionsLeft),
+                                                  @"bottom": @(WXTransitionOptionsBottom),
+                                                  @"top": @(WXTransitionOptionsTop),
+                                                  @"backgroundColor": @(WXTransitionOptionsBackgroundColor),
+                                                  @"transform": @(WXTransitionOptionsTransform),
+                                                  @"opacity": @(WXTransitionOptionsOpacity),
+                                                  };
+    return options[string].integerValue;
+}
+
+- (void)_handleTransitionWithStyles:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles target:(WXComponent *)targetComponent
+{
+    BOOL isRunning = [self _isTransitionRunning];
+    if (isRunning) {
+        [self _rollBackTransitionWithStyles:styles];
+    }
+    else
+    {
+        [self _suspendTransitionDisplayLink];
+    }
+    
+    _filterStyles = _filterStyles ?:[NSMutableDictionary new];
+    _oldFilterStyles = _oldFilterStyles ?: [NSMutableDictionary new];
+    NSMutableDictionary *futileStyles = [NSMutableDictionary new];
+    
+    for (NSString *key in styles) {
+        if (self.transitionOptions & [self transitionOptionsFromString:key]) {
+            [_filterStyles setObject:styles[key] forKey:key];
+            if (![key isEqualToString:@"transform"]) {
+                if (!isRunning) {
+                    [_oldFilterStyles setObject:targetComponent.styles[key] forKey:key];
+                }
+            }
+        }
+        else
+        {
+            [futileStyles setObject:styles[key] forKey:key];
+        }
+    }
+    [self updateFutileStyles:futileStyles resetStyles:nil target:targetComponent];
+
+    _targetComponent = targetComponent;
+    NSMutableDictionary *componentStyles = [NSMutableDictionary dictionaryWithDictionary:styles];
+    [componentStyles addEntriesFromDictionary:targetComponent.styles];
+
+    _transitionDuration = componentStyles[kWXTransitionDuration] ? [WXConvert CGFloat:componentStyles[kWXTransitionDuration]] : 0;
+    _transitionDelay = componentStyles[kWXTransitionDelay] ? [WXConvert CGFloat:componentStyles[kWXTransitionDelay]] : 0;
+    _transitionTimingFunction = [WXConvert CAMediaTimingFunction:componentStyles[kWXTransitionTimingFunction]];
+    
+    if (_transitionDuration == 0 ) {
+        [self updateFutileStyles:_filterStyles resetStyles:nil target:targetComponent];
+        return;
+    }
+    
+    if (![[NSString stringWithFormat:@"%@",_transitionTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) {
+        float vec[4] = {0.};
+        [_transitionTimingFunction getControlPointAtIndex:1 values:&vec[0]];
+        [_transitionTimingFunction getControlPointAtIndex:2 values:&vec[2]];
+        [self unitBezierp1x:vec[0] p1y:vec[1] p2x:vec[2] p2y:vec[3]];
+    }
+    
+    [self _resloveTransitionProperty];
+    [self performSelector:@selector(_startTransitionDisplayLink) withObject:self afterDelay:_transitionDelay/1000];
+}
+
+- (void)updateFutileStyles:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles target:(WXComponent *)targetComponent
+{
+    [targetComponent _updateCSSNodeStyles:styles];
+    [targetComponent _resetCSSNodeStyles:resetStyles];
+    WXPerformBlockOnMainThread(^{
+        [targetComponent _updateViewStyles:styles];
+    });
+}
+
+- (void)_rollBackTransitionWithStyles:(NSDictionary *)styles
+{
+    _transitionDuration = _transitionCount * 1000 / 60;
+    _transitionCount = 0;
+    _propertyArray = nil;
+}
+
+- (void)_resloveTransitionProperty
+{
+    if (_filterStyles.count == 0) {
+        return;
+    }
+    for (NSString * name  in _filterStyles.allKeys) {
+        [self _dealTransitionWithProperty:name];
+    }
+}
+
+- (void)_dealTransitionWithProperty:(NSString *)singleProperty
+{
+    if (_filterStyles[singleProperty])
+    {
+        if (!_propertyArray) {
+            _propertyArray = [NSMutableArray new];
+        }
+        if ([singleProperty isEqualToString:@"backgroundColor"]) {
+            WXTransitionInfo *info = [WXTransitionInfo new];
+            info.fromValue = [self _dealWithColor:[WXConvert UIColor:_oldFilterStyles[singleProperty]]];
+            info.toValue = [self _dealWithColor:[WXConvert UIColor:_filterStyles[singleProperty]]];
+            info.perValue = [self _calculatePerColorRGB1:info.toValue RGB2:info.fromValue];
+            info.propertyName = singleProperty;
+            [_propertyArray addObject:info];
+        }
+        else if ([singleProperty isEqualToString:@"transform"]) {
+            NSString *transformOrigin = _filterStyles[@"transformOrigin"];
+            WXTransform *wxTransform = [[WXTransform alloc] initWithCSSValue:_filterStyles[singleProperty] origin:transformOrigin instance:_targetComponent.weexInstance];
+            WXTransform *oldTransform = _targetComponent->_transform;
+            if (wxTransform.rotateAngle != oldTransform.rotateAngle) {
+                WXTransitionInfo *info = [WXTransitionInfo new];
+                info.propertyName = @"transform.rotation";
+                info.fromValue = @(oldTransform.rotateAngle);
+                info.toValue = [NSNumber numberWithDouble:wxTransform.rotateAngle];
+                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
+                [_propertyArray addObject:info];
+            }
+            if (wxTransform.rotateX != oldTransform.rotateX)
+            {
+                WXTransitionInfo *info = [WXTransitionInfo new];
+                info.propertyName = @"transform.rotation.x";
+                info.fromValue = @(oldTransform.rotateX);
+                info.toValue = [NSNumber numberWithDouble:wxTransform.rotateX];
+                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
+                [_propertyArray addObject:info];
+            }
+            if (wxTransform.rotateY != oldTransform.rotateY)
+            {
+                WXTransitionInfo *info = [WXTransitionInfo new];
+                info.propertyName = @"transform.rotation.y";
+                info.fromValue = @(oldTransform.rotateY);
+                info.toValue = [NSNumber numberWithDouble:wxTransform.rotateY];
+                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
+                [_propertyArray addObject:info];
+            }
+            if (wxTransform.rotateZ != oldTransform.rotateZ)
+            {
+                WXTransitionInfo *info = [WXTransitionInfo new];
+                info.propertyName = @"transform.rotation.z";
+                info.fromValue = @(oldTransform.rotateZ);
+                info.toValue = [NSNumber numberWithDouble:wxTransform.rotateZ];
+                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
+                [_propertyArray addObject:info];
+            }
+            if (wxTransform.scaleX != oldTransform.scaleX) {
+                WXTransitionInfo *info = [WXTransitionInfo new];
+                info.propertyName = @"transform.scale.x";
+                info.fromValue = @(oldTransform.scaleX);
+                info.toValue = @(wxTransform.scaleX);
+                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
+                [_propertyArray addObject:info];
+            }
+            if (wxTransform.scaleY != oldTransform.scaleY) {
+                WXTransitionInfo *info = [WXTransitionInfo new];
+                info.propertyName = @"transform.scale.y";
+                info.fromValue = @(oldTransform.scaleY);
+                info.toValue = @(wxTransform.scaleY);
+                info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
+                [_propertyArray addObject:info];
+            }
+            if (wxTransform.translateX && [wxTransform.translateX floatValue] !=[oldTransform.translateX floatValue]) {
+                WXTransitionInfo *info = [WXTransitionInfo new];
+                info.propertyName = @"transform.translation.x";
+                info.fromValue = @([oldTransform.translateX floatValue]);
+                info.toValue = @([wxTransform.translateX floatValue]);
+                info.perValue = @([wxTransform.translateX floatValue] - [oldTransform.translateX floatValue]);
+                [_propertyArray addObject:info];
+            }
+            if (wxTransform.translateY && [wxTransform.translateY floatValue] !=[oldTransform.translateY floatValue]) {
+                WXTransitionInfo *info = [WXTransitionInfo new];
+                info.propertyName = @"transform.translation.y";
+                info.fromValue = @([oldTransform.translateY floatValue]);
+                info.toValue = @([wxTransform.translateY floatValue]);
+                info.perValue = @([wxTransform.translateY floatValue] - [oldTransform.translateY floatValue]);
+                [_propertyArray addObject:info];
+            }
+            _targetComponent->_transform = wxTransform;
+        }
+        else
+        {
+            WXTransitionInfo *info = [WXTransitionInfo new];
+            info.fromValue = @(_oldFilterStyles[singleProperty] ? [WXConvert CGFloat:_oldFilterStyles[singleProperty]] : 0);
+            info.toValue = @(_filterStyles[singleProperty] ? [WXConvert CGFloat:_filterStyles[singleProperty]] : 0 );
+            info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]);
+            info.propertyName = singleProperty;
+            [_propertyArray addObject:info];
+        }
+    }
+}
+
+- (NSArray *)_dealWithColor:(UIColor *)color
+{
+    CGFloat R, G, B, A;
+    [color getRed:&R green:&G blue:&B alpha:&A];
+    return @[@(R),@(G),@(B),@(A)];
+}
+
+- (NSArray *)_calculatePerColorRGB1:(NSArray *)RGB1 RGB2:(NSArray *)RGB2
+{
+    CGFloat R = [RGB1[0] doubleValue] - [RGB2[0] doubleValue];
+    CGFloat G = [RGB1[1] doubleValue] - [RGB2[1] doubleValue];
+    CGFloat B = [RGB1[2] doubleValue] - [RGB2[2] doubleValue];
+    CGFloat A = [RGB1[3] doubleValue] - [RGB2[3] doubleValue];
+    return @[@(R),@(G),@(B),@(A)];
+}
+
+- (void)_calculatetransitionProcessingStyle
+{
+    if (_propertyArray.count == 0) {
+        return;
+    }
+    double per = 1000 * (_transitionCount + 1 ) / (60 * _transitionDuration);//linear
+    if (![[NSString stringWithFormat:@"%@",_transitionTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) {
+        per = [self solveWithx:((_transitionCount+2)*16)/_transitionDuration epsilon:SOLVE_EPS(_transitionDuration)];
+    }
+    NSString *transformString = [NSString string];
+    for (WXTransitionInfo *info in _propertyArray) {
+        if ([info.propertyName isEqualToString:@"backgroundColor"]) {
+            NSArray *array = @[
+                               @([info.fromValue[0] floatValue] + [info.perValue[0] floatValue] * per),
+                               @([info.fromValue[1] floatValue] + [info.perValue[1] floatValue] * per),
+                               @([info.fromValue[2] floatValue] + [info.perValue[2] floatValue] * per),
+                               @([info.fromValue[3] floatValue] + [info.perValue[3] floatValue] * per)];
+            UIColor *color = [UIColor colorWithRed:[array[0] floatValue] green:[array[1] floatValue] blue:[array[2] floatValue] alpha:[array[3] floatValue]];
+            WXPerformBlockOnMainThread(^{
+                _targetComponent.view.backgroundColor = color;
+                [_targetComponent.view setNeedsDisplay];
+            });
+            NSString *colorString = [WXConvert HexWithColor:color];
+            [_oldFilterStyles setObject:colorString forKey:info.propertyName];
+        }
+        else if ([info.propertyName hasPrefix:@"transform"])
+        {
+            double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per;
+            NSString *newString = [NSString string];
+            if ([info.propertyName isEqualToString:@"transform.rotation"]) {
+                newString = [NSString stringWithFormat:@"rotate(%lfdeg)",currentValue * 180.0 / M_PI];
+                transformString = [transformString stringByAppendingFormat:@" %@",newString];
+            }
+            if ([info.propertyName isEqualToString:@"transform.rotation.x"]) {
+                newString = [NSString stringWithFormat:@"rotateX(%lfdeg)",currentValue * 180.0 / M_PI];
+                transformString = [transformString stringByAppendingFormat:@" %@",newString];
+            }
+            if ([info.propertyName isEqualToString:@"transform.rotation.y"]) {
+                newString = [NSString stringWithFormat:@"rotateY(%lfdeg)",currentValue * 180.0 / M_PI];
+                transformString = [transformString stringByAppendingFormat:@" %@",newString];
+            }
+            if ([info.propertyName isEqualToString:@"transform.rotation.z"]) {
+                newString = [NSString stringWithFormat:@"rotateZ(%lfdeg)",currentValue * 180.0 / M_PI];
+                transformString = [transformString stringByAppendingFormat:@" %@",newString];
+            }
+            if ([info.propertyName isEqualToString:@"transform.scale.x"]) {
+                newString = [NSString stringWithFormat:@"scaleX(%lf)",currentValue];
+                transformString = [transformString stringByAppendingFormat:@" %@",newString];
+            }
+            if ([info.propertyName isEqualToString:@"transform.scale.y"]) {
+                newString = [NSString stringWithFormat:@"scaleY(%lf)",currentValue];
+                transformString = [transformString stringByAppendingFormat:@" %@",newString];
+            }
+            if ([info.propertyName isEqualToString:@"transform.translation.x"]) {
+                newString = [NSString stringWithFormat:@"translateX(%lfpx)",currentValue / _targetComponent.weexInstance.pixelScaleFactor];
+                transformString = [transformString stringByAppendingFormat:@" %@",newString];
+            }
+            if ([info.propertyName isEqualToString:@"transform.translation.y"]) {
+                newString = [NSString stringWithFormat:@"translateY(%lfpx)",currentValue / _targetComponent.weexInstance.pixelScaleFactor];
+                transformString = [transformString stringByAppendingFormat:@" %@",newString];
+            }
+            [_oldFilterStyles setObject:transformString forKey:@"transform"];
+        }
+        else
+        {
+            double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per;
+            [_oldFilterStyles setObject:@(currentValue) forKey:info.propertyName];
+        }
+    }
+    WXPerformBlockOnMainThread(^{
+        [_targetComponent _updateViewStyles:_oldFilterStyles];
+    });
+    [_targetComponent _updateCSSNodeStyles:_oldFilterStyles];
+    [_targetComponent.weexInstance.componentManager startComponentTasks];
+}
+
+#pragma mark CADisplayLink
+- (void)_startTransitionDisplayLink
+{
+    WXAssertComponentThread();
+    if (!_transitionDisplayLink) {
+        _transitionDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleTransitionDisplayLink)];
+        [_transitionDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+    }
+    else{
+        [self _awakeTransitionDisplayLink];
+    }
+}
+
+- (void)_stopTransitionDisplayLink
+{
+    WXAssertComponentThread();
+    if (_transitionDisplayLink) {
+        [_transitionDisplayLink invalidate];
+        _transitionDisplayLink = nil;
+    }
+}
+
+- (BOOL)_isTransitionRunning
+{
+    WXAssertComponentThread();
+    BOOL yesOrNo = NO;
+    if (!_transitionDisplayLink.paused && _transitionCount >= 5) {
+        yesOrNo = YES;
+    }
+    return yesOrNo;
+}
+
+- (void)_suspendTransitionDisplayLink
+{
+    WXAssertComponentThread();
+    if(_transitionDisplayLink && !_transitionDisplayLink.paused){
+        _transitionDisplayLink.paused = YES;
+    }
+}
+
+- (void)_awakeTransitionDisplayLink
+{
+    WXAssertComponentThread();
+    if (_transitionDisplayLink && _transitionDisplayLink.paused) {
+        _transitionDisplayLink.paused = NO;
+    }
+}
+
+- (void)_handleTransitionDisplayLink
+{
+    WXAssertComponentThread();
+    int count = _transitionDuration * 60 / 1000;
+    if (_transitionCount >= count) {
+        [self _suspendTransitionDisplayLink];
+        [self _resetProcessAnimationParameter];
+        return;
+    }
+    else
+    {
+        [self _calculatetransitionProcessingStyle];
+    }
+    _transitionCount ++;
+}
+
+- (void)_resetProcessAnimationParameter
+{
+    _transitionCount = 0;
+    _transitionDuration = 0;
+    _propertyArray = nil;
+    _oldFilterStyles = nil;
+    _filterStyles= nil;
+}
+
+- (NSMutableDictionary *)_filterStyles
+{
+    return self.filterStyles;
+}
+
+- (NSMutableDictionary *)_oldFilterStyles
+{
+    return self.oldFilterStyles;
+}
+
+#pragma mark UnitBezierp
+- (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/b77b4259/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m b/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m
index 2744e60..a303ddb 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m
@@ -63,6 +63,9 @@ WX_NUMBER_CONVERT(NSUInteger, unsignedIntegerValue)
 {
     if ([value isKindOfClass:[NSString class]]) {
         NSString *valueString = (NSString *)value;
+        if (valueString.length <=0) {
+            return NAN;
+        }
         if ([valueString hasSuffix:@"px"] || [valueString hasSuffix:@"wx"]) {
             valueString = [valueString substringToIndex:(valueString.length - 2)];
         }
@@ -72,12 +75,32 @@ WX_NUMBER_CONVERT(NSUInteger, unsignedIntegerValue)
             value = [value substringWithRange:NSMakeRange(start, end-start)];
             return [self safeAreaInset:value];
         }
+        //value maybe not number ,such as 100%
+        if (![WXConvert checkStringIsRealNum:valueString]) {
+            return NAN;
+        }
         return [valueString doubleValue];
     }
     
     return [self double:value];
 }
 
++ (BOOL)checkStringIsRealNum:(NSString *)checkedNumString {
+    NSScanner* scan = [NSScanner scannerWithString:checkedNumString];
+    int intVal;
+    BOOL isInt = [scan scanInt:&intVal] && [scan isAtEnd];
+    if (isInt) {
+        return YES;
+    }
+    float floatVal;
+    BOOL isFloat = [scan scanFloat:&floatVal] && [scan isAtEnd];
+    if (isFloat) {
+        return YES;
+    }
+    
+    return NO;
+}
+
 + (CGFloat)safeAreaInset:(NSString*)value
 {
     static NSArray * directionArray = nil;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
index 0e2bb06..b1b852a 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
@@ -253,6 +253,9 @@ _Nonnull SEL WXSwizzledSelectorForSelector(_Nonnull SEL selector);
  */
 + (CGFloat)defaultPixelScaleFactor;
 
+#if defined __cplusplus
+extern "C" {
+#endif
 /**
  * @abstract Returns the scale of the main screen.
  *
@@ -276,7 +279,11 @@ CGFloat WXFloorPixelValue(CGFloat value);
  *
  */
 CGFloat WXCeilPixelValue(CGFloat value);
-
+    
+#if defined __cplusplus
+};
+#endif
+    
 /**
  *  @abstract check whether the file is exist
  *
@@ -404,6 +411,10 @@ CGPoint WXPixelPointResize(CGPoint value) DEPRECATED_MSG_ATTRIBUTE("Use WXPixelS
  */
 + (NSDictionary *_Nullable)linearGradientWithBackgroundImage:(NSString *_Nullable)backgroundImage;
 
+#if defined __cplusplus
+extern "C" {
+#endif
+    
 /**
  *  @abstract compare float a and b, if a equal b, return true,or reture false.
  *
@@ -435,6 +446,10 @@ BOOL WXFloatGreaterThan(CGFloat a, CGFloat b);
  */
 BOOL WXFloatGreaterThanWithPrecision(CGFloat a,CGFloat b,double precision);
 
+#if defined __cplusplus
+};
+#endif
+
 /**
  *  @abstract convert returnKeyType to type string .
  *