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:53 UTC

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

Repository: incubator-weex
Updated Branches:
  refs/heads/master bf14bcdb5 -> b77b42599


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
deleted file mode 100644
index 66d6ad5..0000000
--- a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
+++ /dev/null
@@ -1,346 +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 "WXComponent+ViewManagement.h"
-#import "WXComponent_internal.h"
-#import "WXComponent+BoxShadow.h"
-#import "WXAssert.h"
-#import "WXView.h"
-#import "WXSDKInstance_private.h"
-#import "WXTransform.h"
-#import "WXTracingManager.h"
-#import "WXSDKManager.h"
-
-#define WX_BOARD_RADIUS_RESET_ALL(key)\
-do {\
-    if (styles && [styles containsObject:@#key]) {\
-        _borderTopLeftRadius = _borderTopRightRadius = _borderBottomLeftRadius = _borderBottomRightRadius = 0;\
-        [self setNeedsDisplay];\
-    }\
-} while(0);
-
-#define WX_BOARD_RADIUS_RESET(key)\
-do {\
-    if (styles && [styles containsObject:@#key]) {\
-    _##key = 0;\
-    [self setNeedsDisplay];\
-    }\
-} while(0);
-
-#define WX_BOARD_WIDTH_RESET_ALL(key)\
-do {\
-    if (styles && [styles containsObject:@#key]) {\
-        _borderTopWidth = _borderLeftWidth = _borderRightWidth = _borderBottomWidth = 0;\
-        [self setNeedsLayout];\
-    }\
-} while(0);
-
-#define WX_BOARD_WIDTH_RESET(key)\
-do {\
-    if (styles && [styles containsObject:@#key]) {\
-        _##key = 0;\
-        [self setNeedsLayout];\
-    }\
-} while(0);
-
-#define WX_BOARD_RADIUS_COLOR_RESET_ALL(key)\
-do {\
-    if (styles && [styles containsObject:@#key]) {\
-        _borderTopColor = _borderLeftColor = _borderRightColor = _borderBottomColor = [UIColor blackColor];\
-        [self setNeedsDisplay];\
-    }\
-} while(0);
-
-#define WX_BOARD_COLOR_RESET(key)\
-do {\
-    if (styles && [styles containsObject:@#key]) {\
-        _##key = [UIColor blackColor];\
-        [self setNeedsDisplay];\
-    }\
-} while(0);
-
-#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
-
-@implementation WXComponent (ViewManagement)
-
-#pragma mark Public
-
-- (UIView *)loadView
-{
-    return [[WXView alloc] init];
-}
-
-- (BOOL)isViewLoaded
-{
-    return (_view != nil);
-}
-
-- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    WXAssertMainThread();
-    
-    if (subcomponent.displayType == WXDisplayTypeNone) {
-        return;
-    }
-    
-    WX_CHECK_COMPONENT_TYPE(self.componentType)
-    if (subcomponent->_positionType == WXPositionTypeFixed) {
-        [self.weexInstance.rootView addSubview:subcomponent.view];
-        return;
-    }
-    
-    // use _lazyCreateView to forbid component like cell's view creating
-    if(_lazyCreateView) {
-        subcomponent->_lazyCreateView = YES;
-    }
-    
-    if (!subcomponent->_lazyCreateView || (self->_lazyCreateView && [self isViewLoaded])) {
-        [self.view insertSubview:subcomponent.view atIndex:index];
-    }
-}
-
-- (void)willRemoveSubview:(WXComponent *)component
-{
-    WXAssertMainThread();
-}
-
-- (void)removeFromSuperview
-{
-    WXAssertMainThread();
-    
-    if ([self isViewLoaded]) {
-        [self.view removeFromSuperview];
-    }
-}
-
-- (void)moveToSuperview:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
-{
-    WX_CHECK_COMPONENT_TYPE(self.componentType)
-    [self removeFromSuperview];
-    [newSupercomponent insertSubview:self atIndex:index];
-}
-
-- (void)viewWillLoad
-{
-    WXAssertMainThread();
-}
-
-- (void)viewDidLoad
-{
-    WXAssertMainThread();
-}
-
-- (void)viewWillUnload
-{
-    WXAssertMainThread();
-}
-
-- (void)viewDidUnload
-{
-    WXAssertMainThread();
-}
-
-#pragma mark Private
-
-- (void)_initViewPropertyWithStyles:(NSDictionary *)styles
-{
-    _backgroundColor = styles[@"backgroundColor"] ? [WXConvert UIColor:styles[@"backgroundColor"]] : [UIColor clearColor];
-    _backgroundImage = styles[@"backgroundImage"] ? [WXConvert NSString:styles[@"backgroundImage"]]: nil;
-    _opacity = styles[@"opacity"] ? [WXConvert CGFloat:styles[@"opacity"]] : 1.0;
-    _clipToBounds = styles[@"overflow"] ? [WXConvert WXClipType:styles[@"overflow"]] : NO;
-    _visibility = styles[@"visibility"] ? [WXConvert WXVisibility:styles[@"visibility"]] : WXVisibilityShow;
-    _positionType = styles[@"position"] ? [WXConvert WXPositionType:styles[@"position"]] : WXPositionTypeRelative;
-    _transform = styles[@"transform"] || styles[@"transformOrigin"] ?
-    [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:styles[@"transform"]] origin:[WXConvert NSString:styles[@"transformOrigin"]] instance:self.weexInstance] :
-    [[WXTransform alloc] initWithCSSValue:nil origin:nil instance:self.weexInstance];
-    _boxShadow = styles[@"boxShadow"]?[WXConvert WXBoxShadow:styles[@"boxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor]:nil;
-    if (_boxShadow) {
-        _lastBoxShadow = _boxShadow;
-    }
-}
-- (void)_transitionUpdateViewProperty:(NSDictionary *)styles
-{
-    WX_CHECK_COMPONENT_TYPE(self.componentType)
-    if (styles[@"backgroundColor"]) {
-        _backgroundColor = [WXConvert UIColor:styles[@"backgroundColor"]];
-    }
-    if (styles[@"opacity"]) {
-        _opacity = [WXConvert CGFloat:styles[@"opacity"]];
-    }
-}
-
-- (void)_updateViewStyles:(NSDictionary *)styles
-{
-    WX_CHECK_COMPONENT_TYPE(self.componentType)
-    if (styles[@"boxShadow"]) {
-        _lastBoxShadow = _boxShadow;
-        _boxShadow = styles[@"boxShadow"]?[WXConvert WXBoxShadow:styles[@"boxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor]:nil;
-        [self configBoxShadow:_boxShadow];
-        [self setNeedsDisplay];
-    }
-    
-    if (styles[@"backgroundColor"]) {
-        _backgroundColor = [WXConvert UIColor:styles[@"backgroundColor"]];
-        [self setNeedsDisplay];
-    }
-    
-    if (styles[@"backgroundImage"]) {
-        _backgroundImage = styles[@"backgroundImage"] ? [WXConvert NSString:styles[@"backgroundImage"]]: nil;
-        if (_backgroundImage) {
-            [self setGradientLayer];
-        }
-    }
-    
-    if (styles[@"opacity"]) {
-        _opacity = [WXConvert CGFloat:styles[@"opacity"]];
-        _layer.opacity = _opacity;
-    }
-    
-    if (styles[@"overflow"]) {
-        _clipToBounds = [WXConvert WXClipType:styles[@"overflow"]];
-        _view.clipsToBounds = _clipToBounds;
-    }
-    
-    if (styles[@"position"]) {
-        WXPositionType positionType = [WXConvert WXPositionType:styles[@"position"]];
-        if (positionType == WXPositionTypeSticky) {
-            [self.ancestorScroller addStickyComponent:self];
-        } else if (_positionType == WXPositionTypeSticky) {
-            [self.ancestorScroller removeStickyComponent:self];
-        }
-        
-        WXPerformBlockOnComponentThread(^{
-            if (positionType == WXPositionTypeFixed) {
-                [self.weexInstance.componentManager addFixedComponent:self];
-                _isNeedJoinLayoutSystem = NO;
-                [self.supercomponent _recomputeCSSNodeChildren];
-            } else if (_positionType == WXPositionTypeFixed) {
-                [self.weexInstance.componentManager removeFixedComponent:self];
-                _isNeedJoinLayoutSystem = YES;
-                [self.supercomponent _recomputeCSSNodeChildren];
-            }
-            
-            _positionType = positionType;
-        });
-    }
-    
-    if (styles[@"visibility"]) {
-        _visibility = [WXConvert WXVisibility:styles[@"visibility"]];
-        if (_visibility == WXVisibilityShow) {
-            self.view.hidden = NO;
-        }
-        else {
-            self.view.hidden = YES;
-        }
-    }
-    if (styles[@"transform"]) {
-        _transform = [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:styles[@"transform"]] origin:[WXConvert NSString:self.styles[@"transformOrigin"]] instance:self.weexInstance];
-        if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
-            [_transform applyTransformForView:_view];
-            [_layer setNeedsDisplay];
-        }
-    }
-    
-    if (styles[@"transformOrigin"]) {
-        [_transform setTransformOrigin:[WXConvert NSString:styles[@"transformOrigin"]]];
-        if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
-            [_transform applyTransformForView:_view];
-            [_layer setNeedsDisplay];
-        }
-    }
-}
-
--(void)resetBorder:(NSArray *)styles
-{
-    WX_BOARD_RADIUS_RESET_ALL(borderRadius);
-    WX_BOARD_RADIUS_RESET(borderTopLeftRadius);
-    WX_BOARD_RADIUS_RESET(borderTopRightRadius);
-    WX_BOARD_RADIUS_RESET(borderBottomLeftRadius);
-    WX_BOARD_RADIUS_RESET(borderBottomRightRadius);
-    
-    WX_BOARD_WIDTH_RESET_ALL(borderWidth);
-    WX_BOARD_WIDTH_RESET(borderTopWidth);
-    WX_BOARD_WIDTH_RESET(borderLeftWidth);
-    WX_BOARD_WIDTH_RESET(borderRightWidth);
-    WX_BOARD_WIDTH_RESET(borderBottomWidth);
-    
-    WX_BOARD_RADIUS_COLOR_RESET_ALL(borderColor);
-    WX_BOARD_COLOR_RESET(borderTopColor);
-    WX_BOARD_COLOR_RESET(borderLeftColor);
-    WX_BOARD_COLOR_RESET(borderRightColor);
-    WX_BOARD_COLOR_RESET(borderBottomColor);
-}
-
--(void)_resetStyles:(NSArray *)styles
-{
-    if (styles && [styles containsObject:@"backgroundColor"]) {
-        _backgroundColor = [UIColor clearColor];
-        [self setNeedsDisplay];
-    }
-    if (styles && [styles containsObject:@"boxShadow"]) {
-        _lastBoxShadow = _boxShadow;
-        _boxShadow = nil;
-        [self setNeedsDisplay];
-    }
-    if (styles && [styles containsObject:@"backgroundImage"]) {
-        _backgroundImage = @"linear-gradient(to left,rgba(255,255,255,0),rgba(255,255,255,0))"; // if backgroundImage is nil, give defalut color value.
-        [self setGradientLayer];
-    }
-    
-    [self resetBorder:styles];
-}
-
-- (void)_unloadViewWithReusing:(BOOL)isReusing
-{
-    WXAssertMainThread();
-    
-    if (isReusing && self->_positionType == WXPositionTypeFixed) {
-        return;
-    }
-    
-    [self viewWillUnload];
-    
-    _view.gestureRecognizers = nil;
-    
-    [self _removeAllEvents];
-    
-    if(self.ancestorScroller){
-        [self.ancestorScroller removeStickyComponent:self];
-        [self.ancestorScroller removeScrollToListener:self];
-    }
-    
-    for (WXComponent *subcomponents in [self.subcomponents reverseObjectEnumerator]) {
-        [subcomponents _unloadViewWithReusing:isReusing];
-    }
-    
-    if ([_view superview]) {
-        [_view removeFromSuperview];
-    }
-    
-    if (self->_isTemplate && self.attributes[@"@templateId"]) {
-        [[WXSDKManager bridgeMgr] callComponentHook:self.weexInstance.instanceId componentId:self.attributes[@"@templateId"] type:@"lifecycle" hook:@"detach" args:nil competion:nil];
-    }
-    _view = nil;
-    [_layer removeFromSuperlayer];
-    _layer = nil;
-    
-    [self viewDidUnload];
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
new file mode 100644
index 0000000..29d5d87
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
@@ -0,0 +1,347 @@
+/*
+ * 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+ViewManagement.h"
+#import "WXComponent_internal.h"
+#import "WXComponent+BoxShadow.h"
+#import "WXAssert.h"
+#import "WXView.h"
+#import "WXSDKInstance_private.h"
+#import "WXTransform.h"
+#import "WXTracingManager.h"
+#import "WXSDKManager.h"
+#import "WXComponent+Layout.h"
+
+#define WX_BOARD_RADIUS_RESET_ALL(key)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+        _borderTopLeftRadius = _borderTopRightRadius = _borderBottomLeftRadius = _borderBottomRightRadius = 0;\
+        [self setNeedsDisplay];\
+    }\
+} while(0);
+
+#define WX_BOARD_RADIUS_RESET(key)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+    _##key = 0;\
+    [self setNeedsDisplay];\
+    }\
+} while(0);
+
+#define WX_BOARD_WIDTH_RESET_ALL(key)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+        _borderTopWidth = _borderLeftWidth = _borderRightWidth = _borderBottomWidth = 0;\
+        [self setNeedsLayout];\
+    }\
+} while(0);
+
+#define WX_BOARD_WIDTH_RESET(key)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+        _##key = 0;\
+        [self setNeedsLayout];\
+    }\
+} while(0);
+
+#define WX_BOARD_RADIUS_COLOR_RESET_ALL(key)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+        _borderTopColor = _borderLeftColor = _borderRightColor = _borderBottomColor = [UIColor blackColor];\
+        [self setNeedsDisplay];\
+    }\
+} while(0);
+
+#define WX_BOARD_COLOR_RESET(key)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+        _##key = [UIColor blackColor];\
+        [self setNeedsDisplay];\
+    }\
+} while(0);
+
+#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+
+@implementation WXComponent (ViewManagement)
+
+#pragma mark Public
+
+- (UIView *)loadView
+{
+    return [[WXView alloc] init];
+}
+
+- (BOOL)isViewLoaded
+{
+    return (_view != nil);
+}
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    WXAssertMainThread();
+    
+    if (subcomponent.displayType == WXDisplayTypeNone) {
+        return;
+    }
+  
+    WX_CHECK_COMPONENT_TYPE(self.componentType)
+    if (subcomponent->_positionType == WXPositionTypeFixed) {
+        [self.weexInstance.rootView addSubview:subcomponent.view];
+        return;
+    }
+    
+    // use _lazyCreateView to forbid component like cell's view creating
+    if(_lazyCreateView) {
+        subcomponent->_lazyCreateView = YES;
+    }
+    
+    if (!subcomponent->_lazyCreateView || (self->_lazyCreateView && [self isViewLoaded])) {
+        [self.view insertSubview:subcomponent.view atIndex:index];
+    }
+}
+
+- (void)willRemoveSubview:(WXComponent *)component
+{
+    WXAssertMainThread();
+}
+
+- (void)removeFromSuperview
+{
+    WXAssertMainThread();
+    
+    if ([self isViewLoaded]) {
+        [self.view removeFromSuperview];
+    }
+}
+
+- (void)moveToSuperview:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
+{
+    WX_CHECK_COMPONENT_TYPE(self.componentType)
+    [self removeFromSuperview];
+    [newSupercomponent insertSubview:self atIndex:index];
+}
+
+- (void)viewWillLoad
+{
+    WXAssertMainThread();
+}
+
+- (void)viewDidLoad
+{
+    WXAssertMainThread();
+}
+
+- (void)viewWillUnload
+{
+    WXAssertMainThread();
+}
+
+- (void)viewDidUnload
+{
+    WXAssertMainThread();
+}
+
+#pragma mark Private
+
+- (void)_initViewPropertyWithStyles:(NSDictionary *)styles
+{
+    _backgroundColor = styles[@"backgroundColor"] ? [WXConvert UIColor:styles[@"backgroundColor"]] : [UIColor clearColor];
+    _backgroundImage = styles[@"backgroundImage"] ? [WXConvert NSString:styles[@"backgroundImage"]]: nil;
+    _opacity = styles[@"opacity"] ? [WXConvert CGFloat:styles[@"opacity"]] : 1.0;
+    _clipToBounds = styles[@"overflow"] ? [WXConvert WXClipType:styles[@"overflow"]] : NO;
+    _visibility = styles[@"visibility"] ? [WXConvert WXVisibility:styles[@"visibility"]] : WXVisibilityShow;
+    _positionType = styles[@"position"] ? [WXConvert WXPositionType:styles[@"position"]] : WXPositionTypeRelative;
+    _transform = styles[@"transform"] || styles[@"transformOrigin"] ?
+    [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:styles[@"transform"]] origin:[WXConvert NSString:styles[@"transformOrigin"]] instance:self.weexInstance] :
+    [[WXTransform alloc] initWithCSSValue:nil origin:nil instance:self.weexInstance];
+    _boxShadow = styles[@"boxShadow"]?[WXConvert WXBoxShadow:styles[@"boxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor]:nil;
+    if (_boxShadow) {
+        _lastBoxShadow = _boxShadow;
+    }
+}
+- (void)_transitionUpdateViewProperty:(NSDictionary *)styles
+{
+    WX_CHECK_COMPONENT_TYPE(self.componentType)
+    if (styles[@"backgroundColor"]) {
+        _backgroundColor = [WXConvert UIColor:styles[@"backgroundColor"]];
+    }
+    if (styles[@"opacity"]) {
+        _opacity = [WXConvert CGFloat:styles[@"opacity"]];
+    }
+}
+
+- (void)_updateViewStyles:(NSDictionary *)styles
+{
+    WX_CHECK_COMPONENT_TYPE(self.componentType)
+    if (styles[@"boxShadow"]) {
+        _lastBoxShadow = _boxShadow;
+        _boxShadow = styles[@"boxShadow"]?[WXConvert WXBoxShadow:styles[@"boxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor]:nil;
+        [self configBoxShadow:_boxShadow];
+        [self setNeedsDisplay];
+    }
+    
+    if (styles[@"backgroundColor"]) {
+        _backgroundColor = [WXConvert UIColor:styles[@"backgroundColor"]];
+        [self setNeedsDisplay];
+    }
+    
+    if (styles[@"backgroundImage"]) {
+        _backgroundImage = styles[@"backgroundImage"] ? [WXConvert NSString:styles[@"backgroundImage"]]: nil;
+        if (_backgroundImage) {
+            [self setGradientLayer];
+        }
+    }
+    
+    if (styles[@"opacity"]) {
+        _opacity = [WXConvert CGFloat:styles[@"opacity"]];
+        _layer.opacity = _opacity;
+    }
+    
+    if (styles[@"overflow"]) {
+        _clipToBounds = [WXConvert WXClipType:styles[@"overflow"]];
+        _view.clipsToBounds = _clipToBounds;
+    }
+    
+    if (styles[@"position"]) {
+        WXPositionType positionType = [WXConvert WXPositionType:styles[@"position"]];
+        if (positionType == WXPositionTypeSticky) {
+            [self.ancestorScroller addStickyComponent:self];
+        } else if (_positionType == WXPositionTypeSticky) {
+            [self.ancestorScroller removeStickyComponent:self];
+        }
+        
+        WXPerformBlockOnComponentThread(^{
+            if (positionType == WXPositionTypeFixed) {
+                [self.weexInstance.componentManager addFixedComponent:self];
+                _isNeedJoinLayoutSystem = NO;
+                [self.supercomponent _recomputeCSSNodeChildren];
+            } else if (_positionType == WXPositionTypeFixed) {
+                [self.weexInstance.componentManager removeFixedComponent:self];
+                _isNeedJoinLayoutSystem = YES;
+                [self.supercomponent _recomputeCSSNodeChildren];
+            }
+            
+            _positionType = positionType;
+        });
+    }
+    
+    if (styles[@"visibility"]) {
+        _visibility = [WXConvert WXVisibility:styles[@"visibility"]];
+        if (_visibility == WXVisibilityShow) {
+            self.view.hidden = NO;
+        }
+        else {
+            self.view.hidden = YES;
+        }
+    }
+    if (styles[@"transform"]) {
+        _transform = [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:styles[@"transform"]] origin:[WXConvert NSString:self.styles[@"transformOrigin"]] instance:self.weexInstance];
+        if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
+            [_transform applyTransformForView:_view];
+            [_layer setNeedsDisplay];
+        }
+    }
+    
+    if (styles[@"transformOrigin"]) {
+        [_transform setTransformOrigin:[WXConvert NSString:styles[@"transformOrigin"]]];
+        if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
+            [_transform applyTransformForView:_view];
+            [_layer setNeedsDisplay];
+        }
+    }
+}
+
+-(void)resetBorder:(NSArray *)styles
+{
+    WX_BOARD_RADIUS_RESET_ALL(borderRadius);
+    WX_BOARD_RADIUS_RESET(borderTopLeftRadius);
+    WX_BOARD_RADIUS_RESET(borderTopRightRadius);
+    WX_BOARD_RADIUS_RESET(borderBottomLeftRadius);
+    WX_BOARD_RADIUS_RESET(borderBottomRightRadius);
+    
+    WX_BOARD_WIDTH_RESET_ALL(borderWidth);
+    WX_BOARD_WIDTH_RESET(borderTopWidth);
+    WX_BOARD_WIDTH_RESET(borderLeftWidth);
+    WX_BOARD_WIDTH_RESET(borderRightWidth);
+    WX_BOARD_WIDTH_RESET(borderBottomWidth);
+    
+    WX_BOARD_RADIUS_COLOR_RESET_ALL(borderColor);
+    WX_BOARD_COLOR_RESET(borderTopColor);
+    WX_BOARD_COLOR_RESET(borderLeftColor);
+    WX_BOARD_COLOR_RESET(borderRightColor);
+    WX_BOARD_COLOR_RESET(borderBottomColor);
+}
+
+-(void)_resetStyles:(NSArray *)styles
+{
+    if (styles && [styles containsObject:@"backgroundColor"]) {
+        _backgroundColor = [UIColor clearColor];
+        [self setNeedsDisplay];
+    }
+    if (styles && [styles containsObject:@"boxShadow"]) {
+        _lastBoxShadow = _boxShadow;
+        _boxShadow = nil;
+        [self setNeedsDisplay];
+    }
+    if (styles && [styles containsObject:@"backgroundImage"]) {
+        _backgroundImage = @"linear-gradient(to left,rgba(255,255,255,0),rgba(255,255,255,0))"; // if backgroundImage is nil, give defalut color value.
+        [self setGradientLayer];
+    }
+    
+    [self resetBorder:styles];
+}
+
+- (void)_unloadViewWithReusing:(BOOL)isReusing
+{
+    WXAssertMainThread();
+    
+    if (isReusing && self->_positionType == WXPositionTypeFixed) {
+        return;
+    }
+    
+    [self viewWillUnload];
+    
+    _view.gestureRecognizers = nil;
+    
+    [self _removeAllEvents];
+    
+    if(self.ancestorScroller){
+        [self.ancestorScroller removeStickyComponent:self];
+        [self.ancestorScroller removeScrollToListener:self];
+    }
+    
+    for (WXComponent *subcomponents in [self.subcomponents reverseObjectEnumerator]) {
+        [subcomponents _unloadViewWithReusing:isReusing];
+    }
+    
+    if ([_view superview]) {
+        [_view removeFromSuperview];
+    }
+    
+    if (self->_isTemplate && self.attributes[@"@templateId"]) {
+        [[WXSDKManager bridgeMgr] callComponentHook:self.weexInstance.instanceId componentId:self.attributes[@"@templateId"] type:@"lifecycle" hook:@"detach" args:nil competion:nil];
+    }
+    _view = nil;
+    [_layer removeFromSuperlayer];
+    _layer = nil;
+    
+    [self viewDidUnload];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/View/WXRootView.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/View/WXRootView.m b/ios/sdk/WeexSDK/Sources/View/WXRootView.m
index 11fb48d..4d35f48 100644
--- a/ios/sdk/WeexSDK/Sources/View/WXRootView.m
+++ b/ios/sdk/WeexSDK/Sources/View/WXRootView.m
@@ -50,7 +50,7 @@
 
 - (BOOL)isHasEvent
 {
-    return false;
+    return _mHasEvent;
 }
 
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/WeexSDK.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/WeexSDK.h b/ios/sdk/WeexSDK/Sources/WeexSDK.h
index 9d5ddcd..dfc0b42 100644
--- a/ios/sdk/WeexSDK/Sources/WeexSDK.h
+++ b/ios/sdk/WeexSDK/Sources/WeexSDK.h
@@ -59,10 +59,14 @@
 #import "WXErrorView.h"
 #import "WXDefine.h"
 #import "WXDebugTool.h"
+#import "WXCoreStyle.h"
+#import "WXCoreLayout.h"
+#import "WXCoreFlexEnum.h"
 #import "WXConvert.h"
 #import "WXConfigCenterProtocol.h"
 #import "WXComponentManager.h"
 #import "WXComponent.h"
+#import "WXComponent+Layout.h"
 #import "WXBridgeProtocol.h"
 #import "WXBridgeManager.h"
 #import "WXBaseViewController.h"


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXSliderNeighborComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXSliderNeighborComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXSliderNeighborComponent.m
deleted file mode 100644
index 5bfee0a..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXSliderNeighborComponent.m
+++ /dev/null
@@ -1,1803 +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 "WXSliderNeighborComponent.h"
-#import "WXConvert.h"
-#import "WXUtility.h"
-#import "WXComponent_internal.h"
-#import "WXIndicatorComponent.h"
-#import "WXSDKInstance.h"
-#import "NSTimer+Weex.h"
-
-#define MAX_VISIBLE_ITEMS 30
-#define MIN_TOGGLE_DURATION 0.2
-#define MAX_TOGGLE_DURATION 0.4
-#define SCROLL_DURATION 0.4
-#define INSERT_DURATION 0.4
-#define DECELERATE_THRESHOLD 0.1
-#define SCROLL_SPEED_THRESHOLD 2.0
-#define SCROLL_DISTANCE_THRESHOLD 0.1
-#define DECELERATION_MULTIPLIER 30.0
-#define FLOAT_ERROR_MARGIN 0.000001
-
-@protocol WXSliderNeighborDelegate, WXSliderNeighborDataSource;
-
-@interface WXSliderNeighborView: UIView
-@property (nonatomic, strong) WXIndicatorView *indicator;
-@property (nonatomic, weak) id<WXSliderNeighborDelegate> delegate;
-@property (nonatomic, weak) id<WXSliderNeighborDataSource> dataSource;
-@property (nonatomic, assign) CGFloat perspective;
-@property (nonatomic, readonly, getter = isDragging) BOOL dragging;
-@property (nonatomic, readonly, getter = isScrolling) BOOL scrolling;
-@property (nonatomic, assign) CGFloat autoscroll;
-@property (nonatomic, assign) CGFloat scrollOffset;
-@property (nonatomic, assign) CGFloat previousTranslation;
-@property (nonatomic, assign, getter = isVertical) BOOL vertical;
-@property (nonatomic, assign) CGFloat decelerationRate;
-@property (nonatomic, assign, getter = isScrollEnabled) BOOL scrollEnabled;
-@property (nonatomic, assign, getter = isPagingEnabled) BOOL pagingEnabled;
-@property (nonatomic, assign) BOOL bounces;
-@property (nonatomic, assign) BOOL didDrag;
-@property (nonatomic, readonly, getter = isDecelerating) BOOL decelerating;
-@property (nonatomic, strong, readonly) UIView *contentView;
-@property (nonatomic, strong) NSMutableDictionary *itemViews;
-@property (nonatomic, readonly) NSInteger numberOfVisibleItems;
-@property (nonatomic, readonly) NSInteger numberOfItems;
-@property (nonatomic, readonly) NSInteger numberOfPlaceholders;
-@property (nonatomic, strong) NSMutableSet *itemViewPool;
-@property (nonatomic, strong) NSMutableSet *placeholderViewPool;
-@property (nonatomic, assign) NSTimeInterval startTime;
-@property (nonatomic, assign) NSTimeInterval lastTime;
-@property (nonatomic, assign) CGFloat startVelocity;
-@property (nonatomic, assign) CGFloat offsetMultiplier;
-@property (nonatomic, assign) CGFloat startOffset;
-@property (nonatomic, assign) CGFloat endOffset;
-@property (nonatomic, assign) CGSize contentOffset;
-@property (nonatomic, assign) CGSize viewpointOffset;
-@property (nonatomic, assign) CGFloat scrollSpeed;
-@property (nonatomic, assign) CGFloat bounceDistance;
-@property (nonatomic, assign) BOOL stopAtItemBoundary;
-@property (nonatomic, assign) BOOL scrollToItemBoundary;
-@property (nonatomic, assign) BOOL centerItemWhenSelected;
-@property (nonatomic, assign) NSTimeInterval scrollDuration;
-@property (nonatomic, readonly, getter = isWrapEnabled) BOOL wrapEnabled;
-@property (nonatomic, strong) NSTimer *timer;
-@property (nonatomic, assign) NSInteger numberOfPlaceholdersToShow;
-@property (nonatomic, assign) CGFloat previousScrollOffset;
-@property (nonatomic, assign) NSTimeInterval toggleTime;
-@property (nonatomic, readonly) CGFloat toggle;
-@property (nonatomic, assign) NSInteger previousItemIndex;
-@property (nonatomic, readonly) CGFloat itemWidth;
-@property (nonatomic, assign) BOOL inited;
-@end
-
-@implementation WXSliderNeighborView
-
-- (instancetype)init {
-    
-    self = [super init];
-    if (!self) {
-    }
-    _decelerationRate = 0.01;
-    _scrollEnabled = YES;
-    _bounces = YES;
-    _offsetMultiplier = 1.0;
-    _perspective = -1.0/500.0;
-    _contentOffset = CGSizeZero;
-    _viewpointOffset = CGSizeZero;
-    _scrollSpeed = 1.0;
-    _bounceDistance = 1.0;
-    _stopAtItemBoundary = YES;
-    _scrollToItemBoundary = YES;
-    _centerItemWhenSelected = YES;
-    _inited = NO;
-    
-    _contentView = [[UIView alloc] initWithFrame:self.bounds];
-    
-    //pan gesture recognizer
-    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didPan:)];
-    panGesture.delegate = (id <UIGestureRecognizerDelegate>)self;
-    [_contentView addGestureRecognizer:panGesture];
-    
-    //tap gesture recognizer
-    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)];
-    tapGesture.delegate = (id <UIGestureRecognizerDelegate>)self;
-    [_contentView addGestureRecognizer:tapGesture];
-    
-    self.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;
-    self.isAccessibilityElement = YES;
-    
-    [self addSubview:_contentView];
-    
-    if (_dataSource) {
-        [self reloadData];
-    }
-    
-    return self;
-}
-
-- (void)dealloc
-{
-    [self stopAnimation];
-}
-
-- (void)accessibilityIncrement
-{
-    [self setCurrentItemIndex: [self lastItemIndex]];
-}
-
-- (void)accessibilityDecrement
-{
-    [self setCurrentItemIndex:[self nextItemIndex]];
-}
-
-- (void)setDataSource:(id<WXSliderNeighborDataSource>)dataSource
-{
-    if (_dataSource != dataSource) {
-        _dataSource = dataSource;
-        if (_dataSource) {
-            [self reloadData];
-        }
-    }
-}
-
-- (void)setDelegate:(id<WXSliderNeighborDelegate>)delegate
-{
-    if (_delegate != delegate) {
-        _delegate = delegate;
-        if (_delegate && _dataSource) {
-            [self setNeedsLayout];
-        }
-    }
-}
-
-- (void)setVertical:(BOOL)vertical
-{
-    if (_vertical != vertical)
-    {
-        _vertical = vertical;
-        [self layOutItemViews];
-    }
-}
-
-#pragma clang diagnostic push
-#pragma GCC diagnostic ignored "-Wundeclared-selector"
-- (void)setCurrentItemIndex:(NSInteger)currentItemIndex
-{
-    if ([self currentItemIndex] == currentItemIndex) return;
-    
-    [self setScrollOffset:currentItemIndex];
-    [self.indicator setCurrentPoint:currentItemIndex];
-    
-    if (self.delegate && [self.delegate respondsToSelector:@selector(sliderView:didScrollToItemAtIndex:)]) {
-        [self.delegate sliderNeighbor:self didScrollToItemAtIndex:currentItemIndex];
-    }
-    [self scroll2ItemViewAtIndex:currentItemIndex animated:YES];
-    
-}
-#pragma clang diagnostic pop
-
-- (void)updateItemWidth
-{
-    _itemWidth = [_delegate sliderNeighborItemWidth:self] ?: _itemWidth;
-    if (_numberOfItems > 0) {
-        if ([_itemViews count] == 0) {
-            [self loadViewAtIndex:0];
-        }
-    } else if (_numberOfPlaceholders > 0) {
-        if ([_itemViews count] == 0) {
-            [self loadViewAtIndex:-1];
-        }
-    }
-}
-
-- (NSInteger)circularCarouselItemCount
-{
-    NSInteger count = 0;
-    CGFloat spacing = [self valueForOption:WXSliderNeighborOptionSpacing withDefault:1.0];
-    CGFloat width = _vertical ? self.bounds.size.height: self.bounds.size.width;
-    count = MIN(MAX_VISIBLE_ITEMS, MAX(12, ceil(width / (spacing * _itemWidth)) * M_PI));
-    count = MIN(_numberOfItems + _numberOfPlaceholdersToShow, count);
-    return [self valueForOption:WXSliderNeighborOptionCount withDefault:count];
-}
-
-- (void)updateNumberOfVisibleItems
-{
-    //get number of visible items
-    //based on count value
-    CGFloat spacing = [self valueForOption:WXSliderNeighborOptionSpacing withDefault:1.0];
-    CGFloat width = _vertical ? self.bounds.size.height: self.bounds.size.width;
-    CGFloat itemWidth = _itemWidth * spacing;
-    _numberOfVisibleItems = ceil(width / itemWidth) + 2;
-    _numberOfVisibleItems = MIN(MAX_VISIBLE_ITEMS, _numberOfVisibleItems);
-    _numberOfVisibleItems = [self valueForOption:WXSliderNeighborOptionVisibleItems withDefault:_numberOfVisibleItems];
-    _numberOfVisibleItems = MAX(0, MIN(_numberOfVisibleItems, _numberOfItems + _numberOfPlaceholdersToShow));
-    
-}
-
-- (CGFloat)offsetForItemAtIndex:(NSInteger)index
-{
-    //calculate relative position
-    CGFloat offset = index - _scrollOffset;
-    if (_wrapEnabled) {
-        if (offset > _numberOfItems/2.0) {
-            offset -= _numberOfItems;
-        } else if (offset < -_numberOfItems/2.0) {
-            offset += _numberOfItems;
-        }
-    }
-    
-    return offset;
-}
-
-- (CGFloat)alphaForItemWithOffset:(CGFloat)offset
-{
-    CGFloat fadeMin = -INFINITY;
-    CGFloat fadeMax = INFINITY;
-    CGFloat fadeRange = 1.0;
-    CGFloat fadeMinAlpha = 0.0;
-    fadeMin = [self valueForOption:WXSliderNeighborOptionFadeMin withDefault:fadeMin];
-    fadeMax = [self valueForOption:WXSliderNeighborOptionFadeMax withDefault:fadeMax];
-    fadeRange = [self valueForOption:WXSliderNeighborOptionFadeRange withDefault:fadeRange];
-    fadeMinAlpha = [self valueForOption:WXSliderNeighborOptionFadeMinAlpha withDefault:fadeMinAlpha];
-    
-    CGFloat factor = 0.0;
-    if (offset > fadeMax) {
-        factor = offset - fadeMax;
-    } else if (offset < fadeMin) {
-        factor = fadeMin - offset;
-    }
-    return 1.0 - MIN(factor, fadeRange) / fadeRange * (1.0 - fadeMinAlpha);
-}
-
-
-- (UIView *)containView:(UIView *)view
-{
-    //set item width
-    if (!_itemWidth) {
-        _itemWidth = _vertical? view.frame.size.height: view.frame.size.width;
-    }
-    
-    //set container frame
-    CGRect frame = view.frame;
-    frame.size.width = _vertical? frame.size.width: _itemWidth;
-    frame.size.height = _vertical? _itemWidth: frame.size.height;
-    UIView *containerView = [[UIView alloc] initWithFrame:frame];
-    
-    //set view frame
-    frame = view.frame;
-    frame.origin.x = (containerView.bounds.size.width - frame.size.width) / 2.0;
-    frame.origin.y = (containerView.bounds.size.height - frame.size.height) / 2.0;
-    view.frame = frame;
-    [containerView addSubview:view];
-    containerView.layer.opacity = 0;
-    containerView.transform = CGAffineTransformMakeScale(0.8, 1.0);
-    return containerView;
-}
-
-- (void)transformItemViews
-{
-    for (NSNumber *number in _itemViews)
-    {
-        NSInteger index = [number integerValue];
-        UIView *view = _itemViews[number];
-        [self transformItemView:view atIndex:index];
-    }
-}
-
-- (CATransform3D)transformForItemViewWithOffset:(CGFloat)offset
-{
-    //set up base transform
-    CATransform3D transform = CATransform3DIdentity;
-    transform.m34 = _perspective;
-    transform = CATransform3DTranslate(transform, -_viewpointOffset.width, -_viewpointOffset.height, 0.0);
-    
-    //perform transforms
-    CGFloat spacing = [self valueForOption:WXSliderNeighborOptionSpacing withDefault:1.0];
-    if (_vertical) {
-        return CATransform3DTranslate(transform, 0.0, offset * _itemWidth * spacing, 0.0);
-    } else {
-        return CATransform3DTranslate(transform, offset * _itemWidth * spacing, 0.0, 0.0);
-    }
-}
-
-- (void)transformItemView:(UIView *)view atIndex:(NSInteger)index
-{
-    //calculate offset
-    CGFloat offset = [self offsetForItemAtIndex:index];
-    
-    //update alpha
-    view.superview.layer.opacity = [self alphaForItemWithOffset:offset];
-    
-    //center view
-    view.superview.center = CGPointMake(self.bounds.size.width/2.0 + _contentOffset.width,
-                                        self.bounds.size.height/2.0 + _contentOffset.height);
-    
-    //enable/disable interaction
-    view.superview.userInteractionEnabled = (!_centerItemWhenSelected || index == self.currentItemIndex);
-    view.superview.layer.rasterizationScale = [UIScreen mainScreen].scale;
-    
-    [view layoutIfNeeded];
-    
-    CGFloat clampedOffset = MAX(-1.0, MIN(1.0, offset));
-    if (_decelerating || (_scrolling && !_dragging && !_didDrag) || (_autoscroll && !_dragging) ||
-        (!_wrapEnabled && (_scrollOffset < 0 || _scrollOffset >= _numberOfItems - 1))) {
-        if (offset > 0) {
-            _toggle = (offset <= 0.5)? -clampedOffset: (1.0 - clampedOffset);
-        } else {
-            _toggle = (offset > -0.5)? -clampedOffset: (- 1.0 - clampedOffset);
-        }
-    }
-    
-    //calculate transform
-    CATransform3D transform = [self transformForItemViewWithOffset:offset];
-    
-    //transform view
-    view.superview.layer.transform = transform;
-    
-    //backface culling
-    BOOL showBackfaces = view.layer.doubleSided;
-    if (showBackfaces) {
-        showBackfaces = YES;
-    }
-    showBackfaces = !![self valueForOption:WXSliderNeighborOptionShowBackfaces withDefault:showBackfaces];
-    
-    view.superview.hidden = !(showBackfaces ?: (transform.m33 > 0.0));
-}
-
-NSComparisonResult sliderNeighorCompareViewDepth(UIView *view1, UIView *view2, WXSliderNeighborView *self)
-{
-    //compare depths
-    CATransform3D t1 = view1.superview.layer.transform;
-    CATransform3D t2 = view2.superview.layer.transform;
-    CGFloat z1 = t1.m13 + t1.m23 + t1.m33 + t1.m43;
-    CGFloat z2 = t2.m13 + t2.m23 + t2.m33 + t2.m43;
-    CGFloat difference = z1 - z2;
-    
-    //if depths are equal, compare distance from current view
-    if (difference == 0.0) {
-        CATransform3D t3 = [self currentItemView].superview.layer.transform;
-        if (self.vertical) {
-            CGFloat y1 = t1.m12 + t1.m22 + t1.m32 + t1.m42;
-            CGFloat y2 = t2.m12 + t2.m22 + t2.m32 + t2.m42;
-            CGFloat y3 = t3.m12 + t3.m22 + t3.m32 + t3.m42;
-            difference = fabs(y2 - y3) - fabs(y1 - y3);
-        } else {
-            CGFloat x1 = t1.m11 + t1.m21 + t1.m31 + t1.m41;
-            CGFloat x2 = t2.m11 + t2.m21 + t2.m31 + t2.m41;
-            CGFloat x3 = t3.m11 + t3.m21 + t3.m31 + t3.m41;
-            difference = fabs(x2 - x3) - fabs(x1 - x3);
-        }
-    }
-    return (difference < 0.0)? NSOrderedAscending: NSOrderedDescending;
-}
-
-- (void)depthSortViews
-{
-    for (UIView *view in [[_itemViews allValues] sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))sliderNeighorCompareViewDepth context:(__bridge void *)self])
-    {
-        [_contentView bringSubviewToFront:(UIView *__nonnull)view.superview];
-    }
-}
-
-- (void)layOutItemViews
-{
-    //bail out if not set up yet
-    if (!_dataSource || !_contentView) {
-        return;
-    }
-    
-    //update wrap
-    _wrapEnabled = YES;
-    _wrapEnabled = !![self valueForOption:WXSliderNeighborOptionWrap withDefault:_wrapEnabled];
-    
-    //no placeholders on wrapped carousels
-    _numberOfPlaceholdersToShow = _wrapEnabled? 0: _numberOfPlaceholders;
-    
-    //set item width
-    [self updateItemWidth];
-    
-    //update number of visible items
-    [self updateNumberOfVisibleItems];
-    
-    //prevent false index changed event
-    _previousScrollOffset = self.scrollOffset;
-    
-    //update offset multiplier
-    _offsetMultiplier = 1.0;
-    _offsetMultiplier = [self valueForOption:WXSliderNeighborOptionOffsetMultiplier withDefault:_offsetMultiplier];
-    
-    //align
-    if (!_scrolling && !_decelerating && !_autoscroll) {
-        if (_scrollToItemBoundary && self.currentItemIndex != -1) {
-            [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
-        } else {
-            _scrollOffset = [self clampedOffset:_scrollOffset];
-        }
-    }
-    //update views
-    if (_inited) {
-        [self didScroll];
-    }
-    
-    _inited = YES;
-}
-
-- (CGFloat)valueForOption:(WXSliderNeighborOption)option withDefault:(CGFloat)value
-{
-    if (_delegate && [_delegate respondsToSelector:@selector(sliderNeighbor:valueForOption:withDefault:)]) {
-        return [_delegate sliderNeighbor:self valueForOption:option withDefault:value];
-    }
-    return value;
-}
-
-#pragma mark -
-#pragma mark Gestures and taps
-
-- (NSInteger)viewOrSuperviewIndex:(UIView *)view
-{
-    if (view == nil || view == _contentView) {
-        return NSNotFound;
-    }
-    NSInteger index = [self indexOfItemView:view];
-    if (index == NSNotFound) {
-        return [self viewOrSuperviewIndex:view.superview];
-    }
-    return index;
-}
-
-- (BOOL)viewOrSuperview:(UIView *)view implementsSelector:(SEL)selector
-{
-    if (!view || view == self.contentView) {
-        return NO;
-    }
-    
-    Class viewClass = [view class];
-    while (viewClass && viewClass != [UIView class])
-    {
-        unsigned int numberOfMethods;
-        Method *methods = class_copyMethodList(viewClass, &numberOfMethods);
-        for (unsigned int i = 0; i < numberOfMethods; i++)
-        {
-            if (method_getName(methods[i]) == selector) {
-                free(methods);
-                return YES;
-            }
-        }
-        if (methods) free(methods);
-        viewClass = [viewClass superclass];
-    }
-    
-    return [self viewOrSuperview:view.superview implementsSelector:selector];
-}
-
-- (id)viewOrSuperview:(UIView *)view ofClass:(Class)class
-{
-    if (!view || view == self.contentView) {
-        return nil;
-    } else if ([view isKindOfClass:class]) {
-        return view;
-    }
-    return [self viewOrSuperview:view.superview ofClass:class];
-}
-
-- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch
-{
-    if (_scrollEnabled) {
-        _dragging = NO;
-        _scrolling = NO;
-        _decelerating = NO;
-    }
-    
-    if ([gesture isKindOfClass:[UITapGestureRecognizer class]]) {
-        //handle tap
-        NSInteger index = [self viewOrSuperviewIndex:touch.view];
-        if (index == NSNotFound && _centerItemWhenSelected) {
-            //view is a container view
-            index = [self viewOrSuperviewIndex:[touch.view.subviews lastObject]];
-        }
-        if (index != NSNotFound) {
-            if ([self viewOrSuperview:touch.view implementsSelector:@selector(touchesBegan:withEvent:)]) {
-                return NO;
-            }
-        }
-    } else if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) {
-        if (!_scrollEnabled) {
-            return NO;
-        } else if ([self viewOrSuperview:touch.view implementsSelector:@selector(touchesMoved:withEvent:)]) {
-            UIScrollView *scrollView = [self viewOrSuperview:touch.view ofClass:[UIScrollView class]];
-            if (scrollView) {
-                return !scrollView.scrollEnabled ||
-                (self.vertical && scrollView.contentSize.height <= scrollView.frame.size.height) ||
-                (!self.vertical && scrollView.contentSize.width <= scrollView.frame.size.width);
-            }
-            if ([self viewOrSuperview:touch.view ofClass:[UIButton class]] ||
-                [self viewOrSuperview:touch.view ofClass:[UIBarButtonItem class]]) {
-                return YES;
-            }
-            return NO;
-        }
-    }
-    return YES;
-}
-
-- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
-   //if the view which the otherGestureRecognizer works on is a scrollview and also it is scrollEnabled vertically ,at this time,we should not block the guesture from being recognized by the otherGestureRecognize
-    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
-        if ([otherGestureRecognizer.view isKindOfClass:[UIScrollView class]]) {
-            UIScrollView* scrollview = (UIScrollView *)otherGestureRecognizer.view;
-            if (scrollview.scrollEnabled) {
-                UIPanGestureRecognizer* panRcgn= (UIPanGestureRecognizer *)gestureRecognizer;
-                //check offset for confirming vertival movement
-                if (fabs([panRcgn translationInView:panRcgn.view].y) > fabs([panRcgn translationInView:panRcgn.view].x)*16) {
-                    return YES;
-                }
-            }
-        }
-    }
-    return NO;
-}
-
-
-- (void)didPan:(UIPanGestureRecognizer *)panGesture
-{
-    if (_scrollEnabled && _numberOfItems) {
-        switch (panGesture.state)
-        {
-            case UIGestureRecognizerStateBegan:
-            {
-                _dragging = YES;
-                _scrolling = NO;
-                _decelerating = NO;
-                _previousTranslation = _vertical? [panGesture translationInView:self].y: [panGesture translationInView:self].x;
-                
-                [_delegate sliderNeighborWillBeginDragging:self];
-                break;
-            }
-            case UIGestureRecognizerStateEnded:
-            case UIGestureRecognizerStateCancelled:
-            case UIGestureRecognizerStateFailed:
-            {
-                _dragging = NO;
-                _didDrag = YES;
-                if ([self shouldDecelerate]) {
-                    _didDrag = NO;
-                    [self startDecelerating];
-                }
-                
-                [self pushAnimationState:YES];
-                [_delegate sliderNeighborDidEndDragging:self willDecelerate:_decelerating];
-                [self popAnimationState];
-                
-                if (!_decelerating) {
-                    if ((_scrollToItemBoundary || fabs(_scrollOffset - [self clampedOffset:_scrollOffset]) > FLOAT_ERROR_MARGIN) && !_autoscroll) {
-                        if (fabs(_scrollOffset - self.currentItemIndex) < FLOAT_ERROR_MARGIN) {
-                            //call scroll to trigger events for legacy support reasons
-                            //even though technically we don't need to scroll at all
-                            [self scroll2ItemViewAtIndex:self.currentItemIndex duration:0.01];
-                        } else {
-                            [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
-                        }
-                    } else {
-                        [self depthSortViews];
-                    }
-                } else {
-                    [self pushAnimationState:YES];
-                    [_delegate sliderNeighborWillBeginDecelerating:self];
-                    [self popAnimationState];
-                }
-                break;
-            }
-            case UIGestureRecognizerStateChanged:
-            {
-                CGFloat translation = _vertical? [panGesture translationInView:self].y: [panGesture translationInView:self].x;
-                CGFloat velocity = _vertical? [panGesture velocityInView:self].y: [panGesture velocityInView:self].x;
-                
-                CGFloat factor = 1.0;
-                if (!_wrapEnabled && _bounces) {
-                    factor = 1.0 - MIN(fabs(_scrollOffset - [self clampedOffset:_scrollOffset]),
-                                       _bounceDistance) / _bounceDistance;
-                }
-                
-                _startVelocity = -velocity * factor * _scrollSpeed / _itemWidth;
-                _scrollOffset -= (translation - _previousTranslation) * factor * _offsetMultiplier / _itemWidth;
-                _previousTranslation = translation;
-                [self didScroll];
-                break;
-            }
-            case UIGestureRecognizerStatePossible:
-            {
-                //do nothing
-                break;
-            }
-        }
-    }
-}
-
-- (void)didTap:(UITapGestureRecognizer *)tapGesture
-{
-    //check for tapped view
-    NSInteger index = [self indexOfItemView:[self itemViewAtPoint:[tapGesture locationInView:_contentView]]];
-    if (index != NSNotFound) {
-        if (!_delegate || [_delegate sliderNeighbor:self shouldSelectItemAtIndex:index]) {
-            if ((index != self.currentItemIndex && _centerItemWhenSelected) ||
-                (index == self.currentItemIndex && _scrollToItemBoundary)) {
-                [self scroll2ItemViewAtIndex:index animated:YES];
-            }
-            [_delegate sliderNeighbor:self didSelectItemAtIndex:index];
-        } else if (_scrollEnabled && _scrollToItemBoundary && _autoscroll) {
-            [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
-        }
-    } else {
-        [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
-    }
-}
-
-- (void)pushAnimationState:(BOOL)enabled
-{
-    [CATransaction begin];
-    [CATransaction setDisableActions:!enabled];
-}
-
-- (void)popAnimationState
-{
-    [CATransaction commit];
-}
-
-- (void)reloadData
-{
-    //remove old views
-    for (UIView *view in [_itemViews allValues])
-    {
-        [view.superview removeFromSuperview];
-    }
-    
-    //bail out if not set up yet
-    if (!_dataSource || !_contentView)
-    {
-        return;
-    }
-    
-    //get number of items and placeholders
-    _numberOfVisibleItems = 0;
-    _numberOfItems = [_dataSource numberOfItemsInSliderNeighbor:self];
-    if ([_dataSource respondsToSelector:@selector(numberOfPlaceholdersInsliderNeighbor:)]) {
-        _numberOfPlaceholders = [_dataSource numberOfPlaceholdersInsliderNeighbor:self];
-    }
-    
-    //reset view pools
-    self.itemViews = [NSMutableDictionary dictionary];
-    self.itemViewPool = [NSMutableSet set];
-    self.placeholderViewPool = [NSMutableSet setWithCapacity:_numberOfPlaceholders];
-    
-    //layout views
-    [self setNeedsLayout];
-    
-    //fix scroll offset
-    if (_numberOfItems > 0 && _scrollOffset < 0.0)
-    {
-        [self scroll2ItemViewAtIndex:0 animated:(_numberOfPlaceholders > 0)];
-    }
-}
-
-#pragma mark scrolling
-
-- (NSInteger)currentItemIndex
-{
-    return [self clampedIndex:round(_scrollOffset)];
-}
-
-- (NSInteger)nextItemIndex
-{
-    return ([self currentItemIndex]+1)%_numberOfItems;
-}
-
-- (NSInteger)lastItemIndex
-{
-    if ([self currentItemIndex] == 0) {
-        return _numberOfItems - 1;
-    }
-    return ((NSInteger)round(abs((int)[self currentItemIndex] - 1))) % _numberOfItems;
-}
-
-- (NSInteger)minScrollDistanceFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex
-{
-    NSInteger directDistance = toIndex - fromIndex;
-    if (_wrapEnabled)
-    {
-        NSInteger wrappedDistance = MIN(toIndex, fromIndex) + _numberOfItems - MAX(toIndex, fromIndex);
-        if (fromIndex < toIndex)
-        {
-            wrappedDistance = -wrappedDistance;
-        }
-        return (ABS(directDistance) <= ABS(wrappedDistance))? directDistance: wrappedDistance;
-    }
-    return directDistance;
-}
-
-- (NSInteger)clampedIndex:(NSInteger)index
-{
-    if (_numberOfItems == 0)
-    {
-        return -1;
-    } else if (_wrapEnabled) {
-        return index - floor((CGFloat)index / (CGFloat)_numberOfItems) * _numberOfItems;
-    } else {
-        return MIN(MAX(0, index), MAX(0, _numberOfItems - 1));
-    }
-}
-
-- (CGFloat)clampedOffset:(CGFloat)offset
-{
-    if (_numberOfItems == 0) {
-        return -1.0;
-    } else if (_wrapEnabled) {
-        return offset - floor(offset / (CGFloat)_numberOfItems) * _numberOfItems;
-    } else {
-        return MIN(MAX(0.0, offset), MAX(0.0, (CGFloat)_numberOfItems - 1.0));
-    }
-}
-
-- (CGFloat)minScrollDistanceFromOffset:(CGFloat)fromOffset toOffset:(CGFloat)toOffset
-{
-    CGFloat directDistance = toOffset - fromOffset;
-    if (_wrapEnabled) {
-        CGFloat wrappedDistance = MIN(toOffset, fromOffset) + _numberOfItems - MAX(toOffset, fromOffset);
-        if (fromOffset < toOffset) {
-            wrappedDistance = -wrappedDistance;
-        }
-        return (fabs(directDistance) <= fabs(wrappedDistance))? directDistance: wrappedDistance;
-    }
-    return directDistance;
-}
-
-- (void)scrollByOffset:(CGFloat)offset duration:(NSTimeInterval)duration
-{
-    if (duration > 0.0) {
-        _decelerating = NO;
-        _scrolling = YES;
-        _startTime = CACurrentMediaTime();
-        _startOffset = _scrollOffset;
-        _scrollDuration = duration;
-        _endOffset = _startOffset + offset;
-        if (!_wrapEnabled) {
-            _endOffset = [self clampedOffset:_endOffset];
-        }
-        [_delegate sliderNeighborWillBeginScrollingAnimation:self];
-        [self startAnimation];
-    } else {
-        self.scrollOffset += offset;
-    }
-}
-
-- (void)scroll2Offset:(CGFloat)offset duration:(NSTimeInterval)duration
-{
-    [self scrollByOffset:[self minScrollDistanceFromOffset:_scrollOffset toOffset:offset] duration:duration];
-    if (_delegate && [_delegate respondsToSelector:@selector(sliderNeighbor:didScrollToItemAtIndex:)]) {
-        [_delegate sliderNeighbor:self didScrollToItemAtIndex:offset];
-    }
-}
-
-- (void)scroll2ItemViewAtIndex:(NSInteger)index duration:(NSTimeInterval)duration
-{
-    [self scroll2Offset:index duration:duration];
-}
-
-- (void)scroll2ItemViewAtIndex:(NSInteger)index animated:(BOOL)animated
-{
-    [self scroll2ItemViewAtIndex:index duration:animated? 0.6: 0];
-}
-
-- (void)scrollByNumberOfItems:(NSInteger)itemCount duration:(NSTimeInterval)duration
-{
-    if (duration > 0.0) {
-        CGFloat offset = 0.0;
-        if (itemCount > 0) {
-            offset = (floor(_scrollOffset) + itemCount) - _scrollOffset;
-        } else if (itemCount < 0) {
-            offset = (ceil(_scrollOffset) + itemCount) - _scrollOffset;
-        } else {
-            offset = round(_scrollOffset) - _scrollOffset;
-        }
-        [self scrollByOffset:offset duration:duration];
-    } else {
-        self.scrollOffset = [self clampedIndex:_previousItemIndex + itemCount];
-    }
-}
-
-- (void)removeItemAtIndex:(NSInteger)index animated:(BOOL)animated
-{
-    index = [self clampedIndex:index];
-    UIView *itemView = [self itemViewAtIndex:index];
-    
-    if (animated) {
-        [UIView beginAnimations:nil context:nil];
-        [UIView setAnimationDuration:0.1];
-        [UIView setAnimationDelegate:itemView.superview];
-        [UIView setAnimationDidStopSelector:@selector(removeFromSuperview)];
-        [self performSelector:@selector(queueItemView:) withObject:itemView afterDelay:0.1];
-        itemView.superview.layer.opacity = 0.0;
-        [UIView commitAnimations];
-        
-        [UIView beginAnimations:nil context:nil];
-        [UIView setAnimationDelay:0.1];
-        [UIView setAnimationDuration:INSERT_DURATION];
-        [UIView setAnimationDelegate:self];
-        [UIView setAnimationDidStopSelector:@selector(depthSortViews)];
-        [self removeViewAtIndex:index];
-        _numberOfItems --;
-        _wrapEnabled = !![self valueForOption:WXSliderNeighborOptionWrap withDefault:_wrapEnabled];
-        [self updateNumberOfVisibleItems];
-        _scrollOffset = self.currentItemIndex;
-        [self didScroll];
-        [UIView commitAnimations];
-    } else {
-        [self pushAnimationState:NO];
-        [self queueItemView:itemView];
-        [itemView.superview removeFromSuperview];
-        [self removeViewAtIndex:index];
-        _numberOfItems --;
-        _wrapEnabled = !![self valueForOption:WXSliderNeighborOptionWrap withDefault:_wrapEnabled];
-        _scrollOffset = self.currentItemIndex;
-        [self didScroll];
-        [self depthSortViews];
-        [self popAnimationState];
-    }
-}
-
-- (void)insertItemAtIndex:(NSInteger)index animated:(BOOL)animated
-{
-    _numberOfItems ++;
-    _wrapEnabled = !![self valueForOption:WXSliderNeighborOptionWrap withDefault:_wrapEnabled];
-    [self updateNumberOfVisibleItems];
-    
-    index = [self clampedIndex:index];
-    [self insertView:nil atIndex:index];
-    [self loadViewAtIndex:index];
-    
-    if (fabs(_itemWidth) < FLOAT_ERROR_MARGIN) {
-        [self updateItemWidth];
-    }
-    
-    if (animated) {
-        [UIView beginAnimations:nil context:nil];
-        [UIView setAnimationDuration:INSERT_DURATION];
-        [UIView setAnimationDelegate:self];
-        [UIView setAnimationDidStopSelector:@selector(didScroll)];
-        [self transformItemViews];
-        [UIView commitAnimations];
-    } else {
-        [self pushAnimationState:NO];
-        [self didScroll];
-        [self popAnimationState];
-    }
-    
-    if (_scrollOffset < 0.0) {
-        [self scroll2ItemViewAtIndex:0 animated:(animated && _numberOfPlaceholders)];
-    }
-}
-
-- (void)reloadItemAtIndex:(NSInteger)index animated:(BOOL)animated
-{
-    //get container view
-    UIView *containerView = [[self itemViewAtIndex:index] superview];
-    if (containerView) {
-        if (animated) {
-            //fade transition
-            CATransition *transition = [CATransition animation];
-            transition.duration = INSERT_DURATION;
-            transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
-            transition.type = kCATransitionFade;
-            [containerView.layer addAnimation:transition forKey:nil];
-        }
-        
-        //reload view
-        [self loadViewAtIndex:index withContainerView:containerView];
-    }
-}
-
-#pragma mark Animation
-- (void)step
-{
-    [self pushAnimationState:NO];
-    NSTimeInterval currentTime = CACurrentMediaTime();
-    double delta = currentTime - _lastTime;
-    _lastTime = currentTime;
-    
-    if (_scrolling && !_dragging) {
-        NSTimeInterval time = MIN(1.0, (currentTime - _startTime) / _scrollDuration);
-        delta = [self easeInOut:time];
-        _scrollOffset = _startOffset + (_endOffset - _startOffset) * delta;
-        [self didScroll];
-        if (time >= 1.0) {
-            _scrolling = NO;
-            [self depthSortViews];
-            [self pushAnimationState:YES];
-            [_delegate sliderNeighborDidEndScrollingAnimation:self];
-            [self popAnimationState];
-        }
-    } else if (_decelerating) {
-        CGFloat time = MIN(_scrollDuration, currentTime - _startTime);
-        CGFloat acceleration = -_startVelocity/_scrollDuration;
-        CGFloat distance = _startVelocity * time + 0.5 * acceleration * pow(time, 2.0);
-        _scrollOffset = _startOffset + distance;
-        [self didScroll];
-        if (fabs(time - _scrollDuration) < FLOAT_ERROR_MARGIN) {
-            _decelerating = NO;
-            [self pushAnimationState:YES];
-            [_delegate sliderNeighborDidEndDecelerating:self];
-            [self popAnimationState];
-            if ((_scrollToItemBoundary || fabs(_scrollOffset - [self clampedOffset:_scrollOffset]) > FLOAT_ERROR_MARGIN) && !_autoscroll) {
-                if (fabs(_scrollOffset - self.currentItemIndex) < FLOAT_ERROR_MARGIN) {
-                    //call scroll to trigger events for legacy support reasons
-                    //even though technically we don't need to scroll at all
-                    [self scroll2ItemViewAtIndex:self.currentItemIndex duration:0.01];
-                } else {
-                    [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
-                }
-            } else {
-                CGFloat difference = round(_scrollOffset) - _scrollOffset;
-                if (difference > 0.5) {
-                    difference = difference - 1.0;
-                } else if (difference < -0.5) {
-                    difference = 1.0 + difference;
-                }
-                _toggleTime = currentTime - MAX_TOGGLE_DURATION * fabs(difference);
-                _toggle = MAX(-1.0, MIN(1.0, -difference));
-            }
-        }
-    } else if (_autoscroll && !_dragging) {
-        //autoscroll goes backwards from what you'd expect, for historical reasons
-        self.scrollOffset = [self clampedOffset:_scrollOffset - delta * _autoscroll];
-    } else if (fabs(_toggle) > FLOAT_ERROR_MARGIN) {
-        NSTimeInterval toggleDuration = _startVelocity? MIN(1.0, MAX(0.0, 1.0 / fabs(_startVelocity))): 1.0;
-        toggleDuration = MIN_TOGGLE_DURATION + (MAX_TOGGLE_DURATION - MIN_TOGGLE_DURATION) * toggleDuration;
-        NSTimeInterval time = MIN(1.0, (currentTime - _toggleTime) / toggleDuration);
-        delta = [self easeInOut:time];
-        _toggle = (_toggle < 0.0)? (delta - 1.0): (1.0 - delta);
-        [self didScroll];
-    } else if (!_autoscroll) {
-        [self stopAnimation];
-    }
-    
-    [self popAnimationState];
-}
-
-- (CGFloat)easeInOut:(CGFloat)time
-{
-    return (time < 0.5)? 0.5 * pow(time * 2.0, 3.0): 0.5 * pow(time * 2.0 - 2.0, 3.0) + 1.0;
-}
-
-- (CGFloat)decelerationDistance
-{
-    CGFloat acceleration = -_startVelocity * DECELERATION_MULTIPLIER * (1.0 - _decelerationRate);
-    return -pow(_startVelocity, 2.0) / (2.0 * acceleration);
-}
-
-- (void)startDecelerating
-{
-    CGFloat distance = [self decelerationDistance];
-    _startOffset = _scrollOffset;
-    _endOffset = _startOffset + distance;
-    if (_pagingEnabled) {
-        if (distance > 0.0) {
-            _endOffset = ceil(_startOffset);
-        } else {
-            _endOffset = floor(_startOffset);
-        }
-    } else if (_stopAtItemBoundary) {
-        if (distance > 0.0) {
-            _endOffset = ceil(_endOffset);
-        } else {
-            _endOffset = floor(_endOffset);
-        }
-    }
-    if (!_wrapEnabled) {
-        if (_bounces) {
-            _endOffset = MAX(-_bounceDistance, MIN(_numberOfItems - 1.0 + _bounceDistance, _endOffset));
-        } else {
-            _endOffset = [self clampedOffset:_endOffset];
-        }
-    }
-    distance = _endOffset - _startOffset;
-    
-    _startTime = CACurrentMediaTime();
-    _scrollDuration = fabs(distance) / fabs(0.5 * _startVelocity);
-    
-    if (distance != 0.0) {
-        _decelerating = YES;
-        [self startAnimation];
-    }
-}
-
-
-- (BOOL)shouldDecelerate
-{
-    return (fabs(_startVelocity) > SCROLL_SPEED_THRESHOLD) &&
-    (fabs([self decelerationDistance]) > DECELERATE_THRESHOLD);
-}
-
-- (BOOL)shouldScroll
-{
-    return (fabs(_startVelocity) > SCROLL_SPEED_THRESHOLD) &&
-    (fabs(_scrollOffset - self.currentItemIndex) > SCROLL_DISTANCE_THRESHOLD);
-}
-
-- (void)didScroll
-{
-    if (_wrapEnabled || !_bounces) {
-        _scrollOffset = [self clampedOffset:_scrollOffset];
-    } else {
-        CGFloat min = -_bounceDistance;
-        CGFloat max = MAX(_numberOfItems - 1, 0.0) + _bounceDistance;
-        if (_scrollOffset < min) {
-            _scrollOffset = min;
-            _startVelocity = 0.0;
-        } else if (_scrollOffset > max) {
-            _scrollOffset = max;
-            _startVelocity = 0.0;
-        }
-    }
-    
-    //check if index has changed
-    NSInteger difference = [self minScrollDistanceFromIndex:self.currentItemIndex toIndex:self.previousItemIndex];
-    if (difference) {
-        _toggleTime = CACurrentMediaTime();
-        _toggle = MAX(-1, MIN(1, difference));
-        
-        [self startAnimation];
-    }
-    
-    [self loadUnloadViews];
-    [self transformItemViews];
-    
-    //notify delegate of offset change
-    if (fabs(_scrollOffset - _previousScrollOffset) > 0.000001)
-    {
-        [self pushAnimationState:YES];
-        [_delegate sliderNeighborDidScroll:self];
-        [self popAnimationState];
-    }
-    
-    //notify delegate of index change
-    if (_previousItemIndex != self.currentItemIndex)
-    {
-        [self pushAnimationState:YES];
-        if([_delegate respondsToSelector:@selector(sliderNeighborCurrentItemIndexDidChange:from:to:)]) {
-            [_delegate sliderNeighborCurrentItemIndexDidChange:self from:_previousItemIndex to:self.currentItemIndex];
-        }
-        [self popAnimationState];
-    }
-    
-    //update previous index
-    _previousScrollOffset = _scrollOffset;
-    _previousItemIndex = self.currentItemIndex;
-    [self.indicator setCurrentPoint:self.currentItemIndex];
-}
-
-- (void)startAnimation
-{
-    if (!_timer) {
-        self.timer = [NSTimer timerWithTimeInterval:1.0/60.0
-                                             target:self
-                                           selector:@selector(step)
-                                           userInfo:nil
-                                            repeats:YES];
-        
-        [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
-        [[NSRunLoop mainRunLoop] addTimer:_timer forMode:UITrackingRunLoopMode];
-        
-    }
-}
-
-- (void)stopAnimation
-{
-    [_timer invalidate];
-    _timer = nil;
-}
-
-#pragma mark -
-#pragma mark view management
-
-- (NSArray *)indexesForVisibleItems
-{
-    return [[_itemViews allKeys] sortedArrayUsingSelector:@selector(compare:)];
-}
-
-- (NSArray *)visibleItemViews
-{
-    NSArray *indexes = [self indexesForVisibleItems];
-    return [_itemViews objectsForKeys:indexes notFoundMarker:[NSNull null]];
-}
-
-- (UIView *)itemViewAtIndex:(NSInteger)index
-{
-    return _itemViews[@(index)];
-}
-
-- (UIView *)currentItemView
-{
-    return [self itemViewAtIndex:self.currentItemIndex];
-}
-
-- (NSInteger)indexOfItemView:(UIView *)view
-{
-    NSInteger index = [[_itemViews allValues] indexOfObject:view];
-    if (index != NSNotFound) {
-        return [[_itemViews allKeys][index] integerValue];
-    }
-    return NSNotFound;
-}
-
-- (NSInteger)indexOfItemViewOrSubview:(UIView *)view
-{
-    NSInteger index = [self indexOfItemView:view];
-    if (index == NSNotFound && view != nil && view != _contentView) {
-        return [self indexOfItemViewOrSubview:view.superview];
-    }
-    return index;
-}
-
-- (UIView *)itemViewAtPoint:(CGPoint)point
-{
-    for (UIView *view in [[[_itemViews allValues] sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))sliderNeighorCompareViewDepth context:(__bridge void *)self] reverseObjectEnumerator])
-    {
-        if ([view.superview.layer hitTest:point]) {
-            return view;
-        }
-    }
-    return nil;
-}
-
-- (void)setItemView:(UIView *)view forIndex:(NSInteger)index
-{
-    _itemViews[@(index)] = view;
-}
-
-- (void)removeViewAtIndex:(NSInteger)index
-{
-    NSMutableDictionary *newItemViews = [NSMutableDictionary dictionaryWithCapacity:[_itemViews count] - 1];
-    for (NSNumber *number in [self indexesForVisibleItems])
-    {
-        NSInteger i = [number integerValue];
-        if (i < index) {
-            newItemViews[number] = _itemViews[number];
-        } else if (i > index) {
-            newItemViews[@(i - 1)] = _itemViews[number];
-        }
-    }
-    self.itemViews = newItemViews;
-    [self.indicator setPointCount:self.itemViews.count];
-}
-
-- (void)insertView:(UIView *)view atIndex:(NSInteger)index
-{
-    NSMutableDictionary *newItemViews = [NSMutableDictionary dictionaryWithCapacity:[_itemViews count] + 1];
-    for (NSNumber *number in [self indexesForVisibleItems])
-    {
-        NSInteger i = [number integerValue];
-        if (i < index) {
-            newItemViews[number] = _itemViews[number];
-        } else {
-            newItemViews[@(i + 1)] = _itemViews[number];
-        }
-    }
-    if (view) {
-        [self setItemView:view forIndex:index];
-    }
-    self.itemViews = newItemViews;
-    
-    [self.indicator setPointCount:self.itemViews.count];
-}
-
-#pragma mark -
-#pragma mark View loading
-
-- (UIView *)loadViewAtIndex:(NSInteger)index withContainerView:(UIView *)containerView
-{
-    [self pushAnimationState:NO];
-    
-    UIView *view = nil;
-    if (index < 0) {
-        view = [_dataSource sliderNeighbor:self placeholderViewAtIndex:(NSInteger)(ceil((CGFloat)_numberOfPlaceholdersToShow/2.0)) + index reusingView:[self dequeuePlaceholderView]];
-    } else if (index >= _numberOfItems) {
-        view = [_dataSource sliderNeighbor:self placeholderViewAtIndex:_numberOfPlaceholdersToShow/2.0 + index - _numberOfItems reusingView:[self dequeuePlaceholderView]];
-    } else {
-        view = [_dataSource sliderNeighbor:self viewForItemAtIndex:index reusingView:[self dequeueItemView]];
-    }
-    
-    if (view == nil) {
-        view = [[UIView alloc] init];
-    }
-    
-    [self setItemView:view forIndex:index];
-    if (containerView) {
-        //get old item view
-        UIView *oldItemView = [containerView.subviews lastObject];
-        if (index < 0 || index >= _numberOfItems) {
-            [self queuePlaceholderView:oldItemView];
-        } else {
-            [self queueItemView:oldItemView];
-        }
-        
-        //set container frame
-        CGRect frame = containerView.bounds;
-        if(_vertical) {
-            frame.size.width = view.frame.size.width;
-            frame.size.height = MIN(_itemWidth, view.frame.size.height);
-        } else {
-            frame.size.width = MIN(_itemWidth, view.frame.size.width);
-            frame.size.height = view.frame.size.height;
-        }
-        containerView.bounds = frame;
-        
-        //set view frame
-        frame = view.frame;
-        frame.origin.x = (containerView.bounds.size.width - frame.size.width) / 2.0;
-        frame.origin.y = (containerView.bounds.size.height - frame.size.height) / 2.0;
-        view.frame = frame;
-        
-        //switch views
-        [oldItemView removeFromSuperview];
-        [containerView addSubview:view];
-    } else {
-        [_contentView addSubview:[self containView:view]];
-    }
-    view.superview.layer.opacity = 0.0;
-    [self transformItemView:view atIndex:index];
-    
-    [self popAnimationState];
-    
-    return view;
-}
-
-- (UIView *)loadViewAtIndex:(NSInteger)index
-{
-    return [self loadViewAtIndex:index withContainerView:nil];
-}
-
-- (void)loadUnloadViews
-{
-    //set item width
-    [self updateItemWidth];
-    
-    //update number of visible items
-    [self updateNumberOfVisibleItems];
-    
-    //calculate visible view indices
-    NSMutableSet *visibleIndices = [NSMutableSet setWithCapacity:_numberOfVisibleItems];
-    NSInteger min = -(NSInteger)(ceil((CGFloat)_numberOfPlaceholdersToShow/2.0));
-    NSInteger max = _numberOfItems - 1 + _numberOfPlaceholdersToShow/2;
-    NSInteger offset = self.currentItemIndex - _numberOfVisibleItems/2;
-    if (!_wrapEnabled) {
-        offset = MAX(min, MIN(max - _numberOfVisibleItems + 1, offset));
-    }
-    for (NSInteger i = 0; i < _numberOfVisibleItems; i++)
-    {
-        NSInteger index = i + offset;
-        if (_wrapEnabled) {
-            index = [self clampedIndex:index];
-        }
-        CGFloat alpha = [self alphaForItemWithOffset:[self offsetForItemAtIndex:index]];
-        if (alpha) {
-            //only add views with alpha > 0
-            [visibleIndices addObject:@(index)];
-        }
-    }
-    
-    //remove offscreen views
-    for (NSNumber *number in [_itemViews allKeys])
-    {
-        if (![visibleIndices containsObject:number]) {
-            UIView *view = _itemViews[number];
-            if ([number integerValue] < 0 || [number integerValue] >= _numberOfItems) {
-                [self queuePlaceholderView:view];
-            } else {
-                [self queueItemView:view];
-            }
-            [view.superview removeFromSuperview];
-            [(NSMutableDictionary *)_itemViews removeObjectForKey:number];
-        }
-    }
-    
-    //add onscreen views
-    for (NSNumber *number in visibleIndices)
-    {
-        UIView *view = _itemViews[number];
-        if (view == nil) {
-            [self loadViewAtIndex:[number integerValue]];
-        }
-    }
-}
-
-#pragma mark View queing
-
-- (void)queueItemView:(UIView *)view
-{
-    if (view) {
-        [_itemViewPool addObject:view];
-    }
-}
-
-- (void)queuePlaceholderView:(UIView *)view
-{
-    if (view) {
-        [_placeholderViewPool addObject:view];
-    }
-}
-
-- (UIView *)dequeueItemView
-{
-    UIView *view = [_itemViewPool anyObject];
-    if (view) {
-        [_itemViewPool removeObject:view];
-    }
-    return view;
-}
-
-- (UIView *)dequeuePlaceholderView
-{
-    UIView *view = [_placeholderViewPool anyObject];
-    if (view) {
-        [_placeholderViewPool removeObject:view];
-    }
-    return view;
-}
-
-- (void)setIndicator:(WXIndicatorView *)indicator
-{
-    _indicator = indicator;
-    [_indicator setPointCount:self.numberOfItems];
-    [_indicator setCurrentPoint:[self currentItemIndex]];
-}
-
-- (void)layoutSubviews
-{
-    [super layoutSubviews];
-    _contentView.frame = self.bounds;
-    [self layOutItemViews];
-}
-
-@end
-
-@implementation NSObject (WXSliderNeighborView)
-
-- (NSUInteger)numberOfPlaceholdersInSliderNeighborView:(__unused WXSliderNeighborView *)sliderNeighbor { return 0; }
-- (void)sliderNeighborWillBeginScrollingAnimation:(__unused WXSliderNeighborView *)sliderNeighbor {}
-- (void)sliderNeighborDidEndScrollingAnimation:(__unused WXSliderNeighborView *)sliderNeighbor {}
-- (void)sliderNeighborDidScroll:(__unused WXSliderNeighborView *)sliderNeighbor {}
-
-- (void)sliderNeighborCurrentItemIndexDidChange:(__unused WXSliderNeighborView *)sliderNeighbor {}
-- (void)sliderNeighborWillBeginDragging:(__unused WXSliderNeighborView *)sliderNeighbor {}
-- (void)sliderNeighborDidEndDragging:(__unused WXSliderNeighborView *)sliderNeighbor willDecelerate:(__unused BOOL)decelerate {}
-- (void)sliderNeighborWillBeginDecelerating:(__unused WXSliderNeighborView *)sliderNeighbor {}
-- (void)sliderNeighborDidEndDecelerating:(__unused WXSliderNeighborView *)sliderNeighbor {}
-
-- (BOOL)sliderNeighbor:(__unused WXSliderNeighborView *)sliderNeighbor shouldSelectItemAtIndex:(__unused NSInteger)index { return YES; }
-- (void)sliderNeighbor:(__unused WXSliderNeighborView *)sliderNeighbor didSelectItemAtIndex:(__unused NSInteger)index {}
-
-- (CGFloat)sliderNeighborItemWidth:(__unused WXSliderNeighborView *)sliderNeighbor { return 0; }
-- (CATransform3D)sliderNeighbor:(__unused WXSliderNeighborView *)sliderNeighbor
-   itemTransformForOffset:(__unused CGFloat)offset
-            baseTransform:(CATransform3D)transform { return transform; }
-- (CGFloat)sliderNeighbor:(__unused WXSliderNeighborView *)sliderNeighbor
-     valueForOption:(__unused WXSliderNeighborOption)option
-        withDefault:(CGFloat)value { return value; }
-
-@end
-
-@interface WXSliderNeighborComponent () <WXIndicatorComponentDelegate>{
-    WXPixelType neighborSpace;
-    CGFloat neighborAlpha;
-    CGFloat neighborScale;
-    CGFloat currentItemScale;
-}
-
-@property (nonatomic, strong) WXSliderNeighborView *sliderView;
-@property (nonatomic, assign) BOOL  autoPlay;
-@property (nonatomic, assign) NSUInteger interval;
-@property (nonatomic, assign) NSInteger index;
-@property (nonatomic, strong) NSMutableArray *items;
-@property (nonatomic, strong) NSTimer *autoTimer;
-@property (nonatomic, assign) BOOL  sliderChangeEvent;
-@property (nonatomic, assign) NSInteger currentIndex;
-@property (nonatomic) CGRect itemRect;
-@property (nonatomic, assign) BOOL scrollable;
-
-@end
-
-#define DEFAULT_NEIGHBOR_ITEM_SCALE 0.8
-#define DEFAULT_CURRENT_ITEM_SCALE 0.9
-#define DEFAULT_NEIGHBOR_ALPHA 0.6
-#define DEFAULT_ANIMATION_DURATION 0.3
-#define DEFAULT_NEIGHBOR_SPACE 25
-
-
-@implementation WXSliderNeighborComponent
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance {
-    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
-        _sliderChangeEvent = NO;
-        _interval = 3000;
-        _items = [NSMutableArray array];
-        _itemRect = CGRectNull;
-        self->neighborAlpha = DEFAULT_NEIGHBOR_ALPHA;
-        self->neighborScale = DEFAULT_NEIGHBOR_ITEM_SCALE;
-        self->currentItemScale = DEFAULT_CURRENT_ITEM_SCALE;
-        self->neighborSpace = [WXConvert WXPixelType:@(DEFAULT_NEIGHBOR_SPACE) scaleFactor:self.weexInstance.pixelScaleFactor];
-        _scrollable = YES;
-        [self setAttributes:attributes];
-    
-        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
-    }
-    self.cssNode->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
-    
-    return self;
-}
-
-
-#pragma mark life circle
-
-- (UIView *)loadView
-{
-    _sliderView = [[WXSliderNeighborView alloc] init];
-    return _sliderView;
-}
-
-- (void)dealloc
-{
-    _sliderView.delegate = nil;
-    _sliderView.dataSource = nil;
-    if (_autoPlay) {
-        [self _stopAutoPlayTimer];
-    }
-    _sliderView = nil;
-    [self.items removeAllObjects];
-}
-
-- (void)viewDidUnload
-{
-    [self.items removeAllObjects];
-}
-
-- (void)viewDidLoad
-{
-    _sliderView = (WXSliderNeighborView *)self.view;
-    _sliderView.delegate = self;
-    _sliderView.dataSource = self;
-    _sliderView.contentView.clipsToBounds = YES;
-    _sliderView.scrollEnabled = _scrollable;
-    UIAccessibilityTraits traits = UIAccessibilityTraitAdjustable;
-    
-    if (_autoPlay) {
-        traits |= UIAccessibilityTraitUpdatesFrequently;
-        [self _startAutoPlayTimer];
-    } else {
-        [self _stopAutoPlayTimer];
-    }
-    _sliderView.accessibilityTraits = traits;
-}
-
-- (void)layoutDidFinish {
-    
-    [_sliderView setCurrentItemIndex:_index];
-}
-
-- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    if (subcomponent->_positionType == WXPositionTypeFixed) {
-        [self.weexInstance.rootView addSubview:subcomponent.view];
-        return;
-    }
-    
-    // use _lazyCreateView to forbid component like cell's view creating
-    if(_lazyCreateView) {
-        subcomponent->_lazyCreateView = YES;
-    }
-    
-    if (!subcomponent->_lazyCreateView || (self->_lazyCreateView && [self isViewLoaded])) {
-        UIView *view = subcomponent.view;
-        
-        WXSliderNeighborView *sliderView = (WXSliderNeighborView *)self.view;
-        if ([view isKindOfClass:[WXIndicatorView class]]) {
-            ((WXIndicatorComponent *)subcomponent).delegate = self;
-            [sliderView addSubview:view];
-            return;
-        }
-        
-        if(index < 0) {
-            [self.items addObject:view];
-        } else {
-            [self.items insertObject:view atIndex:index];
-        }
-        
-        subcomponent.isViewFrameSyncWithCalculated = NO;
-        
-        if (index == -1) {
-            [sliderView insertView:view atIndex:index];
-        } else {
-            NSInteger offset = 0;
-            for (int i = 0; i < [self.items count]; ++i) {
-                if (index == i) break;
-                
-                if ([self.items[i] isKindOfClass:[WXIndicatorView class]]) {
-                    offset++;
-                }
-            }
-            [sliderView insertView:view atIndex:index - offset];
-        }
-        
-        [sliderView reloadData];
-    }
-}
-
-#pragma mark attributes update
-- (void)setAttributes:(NSDictionary *)attributes
-{
-    if (attributes[@"index"]) {
-        _index = [attributes[@"index"] integerValue];
-        _currentIndex = _index;
-    }
-    if (attributes[@"autoPlay"]) {
-        _autoPlay = [attributes[@"autoPlay"] boolValue];
-        if (_autoPlay) {
-            [self _startAutoPlayTimer];
-        } else {
-            [self _stopAutoPlayTimer];
-        }
-    }
-    if (attributes[@"interval"]) {
-        _interval = [attributes[@"interval"] integerValue];
-        
-        [self _stopAutoPlayTimer];
-        
-        if (_autoPlay) {
-            [self _startAutoPlayTimer];
-        }
-    }
-    if (attributes[@"neighborScale"]) {
-        [self setNeighborScale:attributes];
-    }
-    if (attributes[@"currentItemScale"]) {
-        [self setCurrentItemScale:attributes];
-    }
-    if (attributes[@"neighborAlpha"]) {
-        [self setNeighborAlpha:attributes];
-    }
-    if (attributes[@"neighborSpace"]) {
-        [self setNeighborSpace:attributes];
-    }
-    if (attributes[@"scrollable"]) {
-        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
-        ((WXSliderNeighborView *)self.view).scrollEnabled = _scrollable;
-    }
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    [self setAttributes:attributes];
-    [self.sliderView setCurrentItemIndex:_index];
-    [self updateSliderPage:YES];
-}
-
-#pragma mark styles update
-- (void)updateStyles:(NSDictionary *)styles {
-    
-}
-
-#pragma mark event
-- (void)addEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"change"]) {
-        _sliderChangeEvent = YES;
-    }
-}
-
-- (void)removeEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"change"]) {
-        _sliderChangeEvent = NO;
-    }
-}
-
-#pragma mark WXIndicatorComponentDelegate Methods
-
-- (void)setIndicatorView:(WXIndicatorView *)indicatorView
-{
-    NSAssert(_sliderView, @"");
-    [_sliderView setIndicator:indicatorView];
-}
-
-- (void)setNeighborSpace:(NSDictionary *)attributes{
-    if(attributes[@"neighborSpace"]) {
-        self->neighborSpace = [WXConvert WXPixelType:attributes[@"neighborSpace"] scaleFactor:self.weexInstance.pixelScaleFactor];
-    }
-}
-
-- (void)setNeighborAlpha:(NSDictionary *)attributes {
-    if (attributes[@"neighborAlpha"]) {
-        self->neighborAlpha = [WXConvert CGFloat:attributes[@"neighborAlpha"]];
-        self->neighborAlpha = self->neighborAlpha >= 0 ? self->neighborAlpha : 0;
-        self->neighborAlpha = self->neighborAlpha <= 1 ? self->neighborAlpha: 1;
-    }
-}
-
-- (void)setCurrentItemScale:(NSDictionary *)attributes {
-    if (attributes[@"currentItemScale"]) {
-        self->currentItemScale = [WXConvert CGFloat:attributes[@"currentItemScale"]];
-        self->currentItemScale = self->currentItemScale >= 0 ? self->currentItemScale : 0;
-        self->currentItemScale = self->currentItemScale <= 1 ? self->currentItemScale: 1;
-    }
-}
-
-- (void)setNeighborScale:(NSDictionary *)attributes
-{
-    if (attributes[@"neighborScale"]) {
-        self->neighborScale = [WXConvert CGFloat:attributes[@"neighborScale"]];
-        self->neighborScale = self->neighborScale >= 0? self->neighborScale : 0;
-        self->neighborScale = self->neighborScale <= 1? self->neighborScale :1;
-    }
-}
-
-#pragma mark Private Methods
-
-- (void)_startAutoPlayTimer
-{
-    if (!self.autoTimer || ![self.autoTimer isValid]) {
-        __weak __typeof__(self) weakSelf = self;
-        self.autoTimer = [NSTimer wx_scheduledTimerWithTimeInterval:_interval/1000.0f block:^() {
-            [weakSelf _autoPlayOnTimer];
-        } repeats:YES];
-        [[NSRunLoop currentRunLoop] addTimer:self.autoTimer forMode:NSRunLoopCommonModes];
-    }
-}
-
-- (void)_stopAutoPlayTimer
-{
-    if (self.autoTimer && [self.autoTimer isValid]) {
-        [self.autoTimer invalidate];
-        self.autoTimer = nil;
-    }
-}
-
-- (void)_autoPlayOnTimer
-{
-    WXSliderNeighborView *sliderNeighborView = (WXSliderNeighborView *)self.view;
-    
-    int indicatorCnt = 0;
-    for (int i = 0; i < [self.items count]; ++i) {
-        if ([self.items[i] isKindOfClass:[WXIndicatorView class]]) {
-            indicatorCnt++;
-        }
-    }
-    
-    self.currentIndex ++;
-    if (self.currentIndex >= self.items.count - indicatorCnt) {
-        self.currentIndex = 0;
-    }
-    
-    [sliderNeighborView setCurrentItemIndex:self.currentIndex];
-}
-
-#pragma mark sliderNeighbor Delegate && dataSource
-
-- (NSInteger)numberOfItemsInSliderNeighbor:(WXSliderNeighborView *)sliderNeighbor {
-    return [self.items count];
-}
-
-- (NSInteger)numberOfPlaceholdersInsliderNeighbor:(WXSliderNeighborView *)sliderNeighbor {
-    return 2;
-}
-
-- (UIView *)sliderNeighbor:(WXSliderNeighborView *)sliderNeighbor viewForItemAtIndex:(NSInteger)index reusingView:(UIView *)view {
-    
-    if (!view) {
-        if (index < [self.items count]) {
-            view = self.items[index];
-        }else {
-            return nil;
-        }
-    } else {
-        view.tag = 1;
-    }
-    
-    if (CGRectIsNull(_itemRect)) {
-        _itemRect = view.frame;
-    }
-    if (index == [self.items count] - 1) {
-        [self updateSliderPage:NO];
-    }
-    
-    return view;
-}
-
-- (BOOL)sliderNeighbor:(WXSliderNeighborView *)sliderNeighbor shouldSelectItemAtIndex:(NSInteger)index {
-    
-    return YES;
-}
-
-- (UIView *)sliderNeighbor:(WXSliderNeighborView *)sliderNeighbor placeholderViewAtIndex:(NSInteger)index reusingView:(UIView *)view
-{
-    
-    return view;
-}
-
-- (void)sliderNeighborDidEndScrollingAnimation:(WXSliderNeighborView *)sliderNeighbor
-{
-    [self updateSliderPage:YES];
-}
-
-- (void)sliderNeighbor:(WXSliderNeighborView *)sliderView didScrollToItemAtIndex:(NSInteger)index
-{
-    self.currentIndex = index;
-    
-    if (_sliderChangeEvent) {
-        [self fireEvent:@"change" params:@{@"index":@(index)} domChanges:@{@"attrs": @{@"index": @(index)}}];
-    }
-}
-
-- (void)sliderNeighborWillBeginDragging:(WXSliderNeighborView *)sliderNeighbor
-{
-    [self _stopAutoPlayTimer];
-}
-
-- (void)sliderNeighborDidEndDragging:(WXSliderNeighborView *)sliderNeighbor willDecelerate:(BOOL)decelerate {
-    if (_autoPlay) {
-        [self _startAutoPlayTimer];
-    }
-}
-
-- (void)updateSliderPage:(BOOL)animate
-{
-    __block UIView * currentView  = [self.sliderView itemViewAtIndex:[_sliderView currentItemIndex]];
-    __block UIView * lastView  = [self.sliderView itemViewAtIndex:[_sliderView lastItemIndex]];
-    __block UIView * nextView  = [self.sliderView itemViewAtIndex:[_sliderView nextItemIndex]];
-    
-    __block CGAffineTransform transfrom = CGAffineTransformIdentity;
-    float duration = 0;
-    __weak typeof(self) weakSelf = self;
-    if (animate) {
-        duration = DEFAULT_ANIMATION_DURATION;
-    }
-    
-    [UIView animateWithDuration:duration animations:^{
-        __strong typeof(self) strongSelf = weakSelf;
-        if (strongSelf) {
-            currentView.alpha = 1.0;
-            if (fabs(strongSelf->currentItemScale) > CGFLOAT_MIN) {
-                transfrom = CGAffineTransformConcat(transfrom,CGAffineTransformMakeScale(strongSelf->currentItemScale, strongSelf->currentItemScale));
-            }
-            currentView.transform = transfrom;
-            transfrom = CGAffineTransformIdentity;
-            if (fabs(strongSelf->neighborScale) <= CGFLOAT_MIN) {
-                strongSelf->neighborScale = DEFAULT_NEIGHBOR_ITEM_SCALE;
-            }
-            
-            CGFloat tx = 0.5*_itemRect.size.width*((1-self->neighborScale)+(1-self->currentItemScale))-self->neighborSpace;
-            transfrom = CGAffineTransformConcat(transfrom, CGAffineTransformMakeScale(strongSelf->neighborScale, strongSelf->neighborScale));
-            nextView.transform = CGAffineTransformConcat(transfrom,  CGAffineTransformMakeTranslation(-tx, 0));
-            lastView.transform = CGAffineTransformConcat(transfrom,  CGAffineTransformMakeTranslation(tx, 0));
-            lastView.alpha = strongSelf->neighborAlpha;
-            nextView.alpha = strongSelf->neighborAlpha;
-        }
-    }];
-}
-
-@end


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXEditComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXEditComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXEditComponent.m
deleted file mode 100644
index f2d6c99..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXEditComponent.m
+++ /dev/null
@@ -1,918 +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 "WXEditComponent.h"
-#import "WXConvert.h"
-#import "WXUtility.h"
-#import "WXSDKInstance.h"
-#import "WXSDKInstance_private.h"
-#import "WXDefine.h"
-#import "WXAssert.h"
-#import "WXComponent_internal.h"
-#import "WXComponent+PseudoClassManagement.h"
-#import "WXTextInputComponent.h"
-
-@interface WXEditComponent()
-
-//@property (nonatomic, strong) WXTextInputView *inputView;
-@property (nonatomic, strong) WXDatePickerManager *datePickerManager;
-@property (nonatomic, strong) NSDictionary *attr;
-//attribute
-@property (nonatomic) NSNumber *maxLength;
-@property (nonatomic) NSString * value;
-@property (nonatomic) BOOL autofocus;
-@property(nonatomic) UIReturnKeyType returnKeyType;
-@property (nonatomic) BOOL disabled;
-@property (nonatomic, copy) NSString *inputType;
-@property (nonatomic) NSUInteger rows;
-@property (nonatomic) BOOL hideDoneButton;
-
-//style
-@property (nonatomic) WXPixelType fontSize;
-@property (nonatomic) WXTextStyle fontStyle;
-@property (nonatomic) CGFloat fontWeight;
-@property (nonatomic, strong) NSString *fontFamily;
-@property (nonatomic, strong) UIColor *colorForStyle;
-@property (nonatomic)NSTextAlignment textAlignForStyle;
-
-//event
-@property (nonatomic) BOOL inputEvent;
-@property (nonatomic) BOOL clickEvent;
-@property (nonatomic) BOOL focusEvent;
-@property (nonatomic) BOOL blurEvent;
-@property (nonatomic) BOOL changeEvent;
-@property (nonatomic) BOOL returnEvent;
-@property (nonatomic) BOOL keyboardEvent;
-@property (nonatomic, strong) NSString *changeEventString;
-@property (nonatomic, assign) CGSize keyboardSize;
-
-// formatter
-@property (nonatomic, strong) NSString * formatRule;
-@property (nonatomic, strong) NSString * formatReplace;
-@property (nonatomic, strong) NSString * recoverRule;
-@property (nonatomic, strong) NSString * recoverReplace;
-@property (nonatomic, strong) NSDictionary * formaterData;
-
-// disable move rootView up as the keyboard show up.
-@property (nonatomic, assign) BOOL disableMoveViewUp;
-
-@end
-
-@implementation WXEditComponent
-{
-    UIEdgeInsets _border;
-    UIEdgeInsets _padding;
-}
-
-WX_EXPORT_METHOD(@selector(focus))
-WX_EXPORT_METHOD(@selector(blur))
-WX_EXPORT_METHOD(@selector(setSelectionRange:selectionEnd:))
-WX_EXPORT_METHOD(@selector(getSelectionRange:))
-WX_EXPORT_METHOD(@selector(setTextFormatter:))
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    if (self) {
-        _inputEvent = NO;
-        _focusEvent = NO;
-        _blurEvent = NO;
-        _changeEvent = NO;
-        _returnEvent = NO;
-        _clickEvent = NO;
-        _keyboardEvent = NO;
-        // handle attributes
-        _autofocus = [attributes[@"autofocus"] boolValue];
-        _disabled = [attributes[@"disabled"] boolValue];
-        _value = [WXConvert NSString:attributes[@"value"]]?:@"";
-        _placeholderString = [WXConvert NSString:attributes[@"placeholder"]]?:@"";
-        if(attributes[@"type"]) {
-            _inputType = [WXConvert NSString:attributes[@"type"]];
-            _attr = attributes;
-        }
-        if (attributes[@"maxlength"]) {
-            _maxLength = [NSNumber numberWithUnsignedInteger:[attributes[@"maxlength"] integerValue]];
-        }
-        if (attributes[@"returnKeyType"]) {
-            _returnKeyType = [WXConvert UIReturnKeyType:attributes[@"returnKeyType"]];
-        }
-        if (attributes[@"rows"]) {
-            _rows = [attributes[@"rows"] integerValue];
-        } else {
-            _rows = 2;
-        }
-        
-        if (attributes[@"hideDoneButton"]) {
-            _hideDoneButton = [attributes[@"hideDoneButton"] boolValue];
-        }
-        if (attributes[@"disableMoveViewUp"]) {
-            _disableMoveViewUp = [WXConvert BOOL:attributes[@"disableMoveViewUp"]];
-        }
-        
-        // handle styles
-        if (styles[@"color"]) {
-            _colorForStyle = [WXConvert UIColor:styles[@"color"]];
-        }
-        if (styles[@"fontSize"]) {
-            _fontSize = [WXConvert WXPixelType:styles[@"fontSize"] scaleFactor:self.weexInstance.pixelScaleFactor];
-        }
-        if (styles[@"fontWeight"]) {
-            _fontWeight = [WXConvert WXTextWeight:styles[@"fontWeight"]];
-        }
-        if (styles[@"fontStyle"]) {
-            _fontStyle = [WXConvert WXTextStyle:styles[@"fontStyle"]];
-        }
-        if (styles[@"fontFamily"]) {
-            _fontFamily = styles[@"fontFamily"];
-        }
-        if (styles[@"textAlign"]) {
-            _textAlignForStyle = [WXConvert NSTextAlignment:styles[@"textAlign"]];
-        }
-        if (styles[@"placeholderColor"]) {
-            _placeholderColor = [WXConvert UIColor:styles[@"placeholderColor"]];
-        }else {
-            _placeholderColor = [UIColor colorWithRed:0x99/255.0 green:0x99/255.0 blue:0x99/255.0 alpha:1.0];
-        }
-    }
-    
-    return self;
-}
-
-#pragma mark - lifeCircle
-
-- (void)viewDidLoad
-{
-    UIView * view = self.view;
-    if ([view isKindOfClass:[UITextField class]]){
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFiledEditChanged:)
-                                                     name:UITextFieldTextDidChangeNotification
-                                                   object:view];
-    }
-    _padding = UIEdgeInsetsZero;
-    _border = UIEdgeInsetsZero;
-    self.userInteractionEnabled = YES;
-    [self setType];
-    [self setAutofocus:_autofocus];
-    [self setTextFont];
-    [self setPlaceholderAttributedString];
-    [self setTextAlignment:_textAlignForStyle];
-    [self setTextColor:_colorForStyle];
-    [self setText:_value];
-    [self setEnabled:!_disabled];
-    [self setRows:_rows];
-    [self setReturnKeyType:_returnKeyType];
-    [self updatePattern];
-    
-    if (!self.hideDoneButton) {
-        UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(closeKeyboard)];
-        UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
-        UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 0, 44)];
-        toolbar.items = [NSArray arrayWithObjects:space, barButton, nil];
-        
-        self.inputAccessoryView = toolbar;
-    }
-
-    [self handlePseudoClass];
-}
-
-- (void)viewWillLoad
-{
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(keyboardWasShown:)
-                                                 name:UIKeyboardWillShowNotification
-                                               object:nil];
-    
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(keyboardWillHide:)
-                                                 name:UIKeyboardWillHideNotification
-                                               object:nil];
-}
-
-- (void)dealloc
-{
-    [[NSNotificationCenter defaultCenter] removeObserver:self];
-}
-
--(void)focus
-{
-    if(self.view) {
-        [self.view becomeFirstResponder];
-    }
-}
-
--(void)blur
-{
-    if(self.view) {
-        [self.view resignFirstResponder];
-    }
-}
-
--(void)setSelectionRange:(NSInteger)selectionStart selectionEnd:(NSInteger)selectionEnd
-{
-    if(selectionStart>self.text.length || selectionEnd>self.text.length) {
-        return;
-    }
-    [self.view becomeFirstResponder];
-    [self setEditSelectionRange:selectionStart selectionEnd:selectionEnd];
-}
-
--(void)getSelectionRange:(WXKeepAliveCallback)callback
-{
-    NSDictionary *res = [self getEditSelectionRange];
-    if(callback) {
-        callback(res,NO);
-    }
-}
-
-- (void)setTextFormatter:(NSDictionary*)formater
-{
-    _formaterData = formater;
-    if (formater[@"formatRule"]) {;
-        _formatRule = [self _preProcessInputTextFormatter:[WXConvert NSString:formater[@"formatRule"]]];
-    }
-    if (formater[@"formatReplace"]) {
-        _formatReplace = [self _preProcessInputTextFormatter:[WXConvert NSString:formater[@"formatReplace"]]];
-    }
-    if (formater[@"recoverRule"]) {
-        _recoverRule = [self _preProcessInputTextFormatter:[WXConvert NSString:formater[@"recoverRule"]]];
-    }
-    if (formater[@"recoverReplace"]) {
-        _recoverReplace = [self _preProcessInputTextFormatter:[WXConvert NSString:formater[@"recoverReplace"]]];
-    }
-}
-
-- (NSString*)_preProcessInputTextFormatter:(NSString*)formater
-{
-    NSRange start = [formater rangeOfString:@"/"];
-    NSRange end = [formater rangeOfString:@"/g"];
-    if (start.location == NSNotFound || end.location == NSNotFound || end.location < start.location) {
-        return formater;
-    }
-    NSRange subStringRange = NSMakeRange(start.location+1, end.location - start.location-1);
-    
-    return [formater substringWithRange:subStringRange];
-}
-
-#pragma mark - Overwrite Method
--(NSString *)text
-{
-    return @"";
-}
-
-- (void)setText:(NSString *)text
-{
-}
-
--(void)setTextColor:(UIColor *)color
-{
-}
-
--(void)setTextAlignment:(NSTextAlignment)textAlignForStyle
-{
-}
-
--(void)setUserInteractionEnabled:(BOOL)userInteractionEnabled
-{
-}
-
--(void)setEnabled:(BOOL)enabled
-{
-}
-
--(void)setReturnKeyType:(UIReturnKeyType)returnKeyType
-{
-}
-
--(void)setInputAccessoryView:(UIView *)inputAccessoryView
-{
-}
-
--(void)setEditSelectionRange:(NSInteger)selectionStart selectionEnd:(NSInteger)selectionEnd
-{
-}
-
--(NSDictionary *)getEditSelectionRange
-{
-    return @{};
-}
-
--(void)setKeyboardType:(UIKeyboardType)keyboardType
-{
-}
-
--(void)setSecureTextEntry:(BOOL)secureTextEntry
-{
-}
-
--(void)setEditPadding:(UIEdgeInsets)padding
-{
-}
-
--(void)setEditBorder:(UIEdgeInsets)border
-{
-}
-
--(void)setAttributedPlaceholder:(NSMutableAttributedString *)attributedString font:(UIFont *)font
-{
-}
-
--(void)setFont:(UIFont *)font
-{
-}
-
--(void)setRows:(NSUInteger)rows
-{
-}
-
-#pragma mark - Add Event
-- (void)addEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"input"]) {
-        _inputEvent = YES;
-    }
-    if ([eventName isEqualToString:@"focus"]) {
-        _focusEvent = YES;
-    }
-    if ([eventName isEqualToString:@"blur"]) {
-        _blurEvent = YES;
-    }
-    if ([eventName isEqualToString:@"change"]) {
-        _changeEvent = YES;
-    }
-    if ([eventName isEqualToString:@"return"]) {
-        _returnEvent = YES;
-    }
-    if ([eventName isEqualToString:@"click"]) {
-        _clickEvent = YES;
-    }
-    if ([eventName isEqualToString:@"keyboard"]) {
-        _keyboardEvent = YES;
-    }
-}
-
-#pragma Remove Event
-
--(void)removeEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"input"]) {
-        _inputEvent = NO;
-    }
-    if ([eventName isEqualToString:@"focus"]) {
-        _focusEvent = NO;
-    }
-    if ([eventName isEqualToString:@"blur"]) {
-        _blurEvent = NO;
-    }
-    if ([eventName isEqualToString:@"change"]) {
-        _changeEvent = NO;
-    }
-    if ([eventName isEqualToString:@"return"]) {
-        _returnEvent = NO;
-    }
-    if ([eventName isEqualToString:@"click"]) {
-        _clickEvent = NO;
-    }
-    if ([eventName isEqualToString:@"keyboard"]) {
-        _keyboardEvent = NO;
-    }
-}
-
-#pragma mark - upate attributes
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    _attr = attributes;
-    if (attributes[@"type"]) {
-        _inputType = [WXConvert NSString:attributes[@"type"]];
-        [self setType];
-    }
-    if (attributes[@"autofocus"]) {
-        self.autofocus = [attributes[@"autofocus"] boolValue];
-    }
-    if (attributes[@"disabled"]) {
-        _disabled = [attributes[@"disabled"] boolValue];
-        [self setEnabled:!_disabled];
-    }
-    if (attributes[@"maxlength"]) {
-        _maxLength = [NSNumber numberWithInteger:[attributes[@"maxlength"] integerValue]];
-    }
-    
-    if (attributes[@"disableMoveViewUp"]) {
-        _disableMoveViewUp = [WXConvert BOOL:attributes[@"disableMoveViewUp"]];
-    }
-    if (attributes[@"value"]) {
-        _value = [WXConvert NSString:attributes[@"value"]]?:@"";
-        if (_maxLength && [_value length] > [_maxLength integerValue]&& [_maxLength integerValue] >= 0) {
-            _value = [_value substringToIndex:([_maxLength integerValue])];
-        }
-        [self setText:_value];
-    }
-    if (attributes[@"placeholder"]) {
-        _placeholderString = [WXConvert NSString:attributes[@"placeholder"]]?:@"";
-        [self setPlaceholderAttributedString];
-        if(_value.length > 0){
-            _placeHolderLabel.text = @"";
-        }
-    }
-    if (attributes[@"returnKeyType"]) {
-        _returnKeyType = [WXConvert UIReturnKeyType:attributes[@"returnKeyType"]];
-        [self setReturnKeyType:_returnKeyType];
-    }
-    if (attributes[@"rows"]) {
-        _rows = [attributes[@"rows"] integerValue];
-        [self setRows:_rows];
-    } else {
-        _rows = 2;
-        [self setRows:_rows];
-    }
-}
-
-#pragma mark - upate styles
-
-- (void)updateStyles:(NSDictionary *)styles
-{
-    if (styles[@"color"]) {
-        _colorForStyle = [WXConvert UIColor:styles[@"color"]];
-        [self setTextColor:_colorForStyle];
-    }
-    if (styles[@"fontSize"]) {
-        _fontSize = [WXConvert WXPixelType:styles[@"fontSize"] scaleFactor:self.weexInstance.pixelScaleFactor];
-    }
-    if (styles[@"fontWeight"]) {
-        _fontWeight = [WXConvert WXTextWeight:styles[@"fontWeight"]];
-    }
-    if (styles[@"fontStyle"]) {
-        _fontStyle = [WXConvert WXTextStyle:styles[@"fontStyle"]];
-    }
-    if (styles[@"fontFamily"]) {
-        _fontFamily = [WXConvert NSString:styles[@"fontFamily"]];
-    }
-    [self setTextFont];
-    
-    if (styles[@"textAlign"]) {
-        _textAlignForStyle = [WXConvert NSTextAlignment:styles[@"textAlign"]];
-        [self setTextAlignment:_textAlignForStyle] ;
-    }
-    if (styles[@"placeholderColor"]) {
-        _placeholderColor = [WXConvert UIColor:styles[@"placeholderColor"]];
-    }else {
-        _placeholderColor = [UIColor colorWithRed:0x99/255.0 green:0x99/255.0 blue:0x99/255.0 alpha:1.0];
-    }
-    [self setPlaceholderAttributedString];
-    [self updatePattern];
-}
-
--(void)updatePattern
-{
-    UIEdgeInsets padding = UIEdgeInsetsMake(self.cssNode->style.padding[CSS_TOP], self.cssNode->style.padding[CSS_LEFT], self.cssNode->style.padding[CSS_BOTTOM], self.cssNode->style.padding[CSS_RIGHT]);
-    if (!UIEdgeInsetsEqualToEdgeInsets(padding, _padding)) {
-        [self setPadding:padding];
-    }
-    
-    UIEdgeInsets border = UIEdgeInsetsMake(self.cssNode->style.border[CSS_TOP], self.cssNode->style.border[CSS_LEFT], self.cssNode->style.border[CSS_BOTTOM], self.cssNode->style.border[CSS_RIGHT]);
-    if (!UIEdgeInsetsEqualToEdgeInsets(border, _border)) {
-        [self setBorder:border];
-    }
-}
-
-- (CGSize (^)(CGSize))measureBlock
-{
-    __weak typeof(self) weakSelf = self;
-    return ^CGSize (CGSize constrainedSize) {
-        
-        CGSize computedSize = [[[NSString alloc] init]sizeWithAttributes:nil];
-        //TODO:more elegant way to use max and min constrained size
-        if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
-            computedSize.width = MAX(computedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
-            computedSize.width = MIN(computedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_HEIGHT])) {
-            computedSize.height = MAX(computedSize.height, weakSelf.cssNode->style.minDimensions[CSS_HEIGHT]);
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT])) {
-            computedSize.height = MIN(computedSize.height, weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT]);
-        }
-        
-        return (CGSize) {
-            WXCeilPixelValue(computedSize.width),
-            WXCeilPixelValue(computedSize.height)
-        };
-    };
-}
-
-#pragma mark WXDatePickerManagerDelegate
-
--(void)fetchDatePickerValue:(NSString *)value
-{
-    self.text = value;
-    if (_changeEvent) {
-        if (![[self text] isEqualToString:_changeEventString]) {
-            [self fireEvent:@"change" params:@{@"value":[self text]} domChanges:@{@"attrs":@{@"value":[self text]}}];
-        }
-    }
-}
-
-#pragma mark UITextFieldDelegate
-
-- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
-    if([self isDateType])
-    {
-        [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
-        _changeEventString = [textField text];
-        [_datePickerManager show];
-        return NO;
-    }
-    return  YES;
-}
-
-#pragma mark UITextFieldDelegate
-
-- (void)textFieldDidBeginEditing:(UITextField *)textField
-{
-    _changeEventString = [textField text];
-    if (_focusEvent) {
-        [self fireEvent:@"focus" params:nil];
-    }
-    [self handlePseudoClass];
-}
-
-- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
-{
-    if (!string.length) {
-        ((WXTextInputView*)textField).deleteWords = YES;
-        ((WXTextInputView*)textField).editWords = [textField.text substringWithRange:range];
-    } else {
-        ((WXTextInputView*)textField).deleteWords = FALSE;
-        ((WXTextInputView*)textField).editWords = string;
-    }
-    
-    if (_maxLength) {
-        NSUInteger oldLength = [textField.text length];
-        NSUInteger replacementLength = [string length];
-        NSUInteger rangeLength = range.length;
-        
-        NSUInteger newLength = oldLength - rangeLength + replacementLength;
-        
-        return newLength <= [_maxLength integerValue] ;
-    }
-    
-    return YES;
-}
-
-- (void)textFieldDidEndEditing:(UITextField *)textField
-{
-    if (_changeEvent) {
-        if (![[textField text] isEqualToString:_changeEventString]) {
-            [self fireEvent:@"change" params:@{@"value":[textField text]} domChanges:@{@"attrs":@{@"value":[textField text]}}];
-        }
-    }
-    if (_blurEvent) {
-        [self fireEvent:@"blur" params:nil];
-    }
-    if(self.pseudoClassStyles && [self.pseudoClassStyles count]>0){
-        [self recoveryPseudoStyles:self.styles];
-    }
-}
-
-- (BOOL)textFieldShouldReturn:(UITextField *)textField
-{
-    if (_returnEvent) {
-        NSString *typeStr = [WXUtility returnKeyType:_returnKeyType];
-        [self fireEvent:@"return" params:@{@"value":[textField text],@"returnKeyType":typeStr} domChanges:@{@"attrs":@{@"value":[textField text]}}];
-    }
-    [self blur];
-    return YES;
-}
-
-- (void)textFiledEditChanged:(NSNotification *)notifi
-{
-    WXTextInputView *textField = (WXTextInputView *)notifi.object;
-    if (_formaterData && _recoverRule && _recoverReplace && _formatRule && _formatReplace) {
-        UITextRange * textRange = textField.selectedTextRange;
-        NSInteger cursorPosition = [textField offsetFromPosition:textField.beginningOfDocument toPosition:textRange.start];
-        NSMutableString * preText = [[textField.text substringToIndex:cursorPosition] mutableCopy];
-        NSMutableString * lastText = [[textField.text substringFromIndex:cursorPosition] mutableCopy];
-        
-        NSRegularExpression *recoverRule = [NSRegularExpression regularExpressionWithPattern:_recoverRule options:NSRegularExpressionCaseInsensitive error:NULL];
-        [recoverRule replaceMatchesInString:preText options:0 range:NSMakeRange(0, preText.length) withTemplate:_recoverReplace];
-        [recoverRule replaceMatchesInString:lastText options:0 range:NSMakeRange(0, lastText.length) withTemplate:_recoverReplace];
-        NSMutableString * newString = [NSMutableString stringWithFormat:@"%@%@", preText, lastText];
-        NSRegularExpression *formatRule = [NSRegularExpression regularExpressionWithPattern:_formatRule options:NSRegularExpressionCaseInsensitive error:NULL];
-        [formatRule replaceMatchesInString:newString options:0 range:NSMakeRange(0, newString.length) withTemplate:_formatReplace];
-        NSString * oldText = textField.text;
-        NSInteger adjust = 0;
-        
-        if (cursorPosition == textField.text.length) {
-            adjust = newString.length-oldText.length;
-        }
-        if (textField.deleteWords &&[textField.editWords isKindOfClass:[NSString class]] && [_recoverRule isEqualToString:textField.editWords]) {
-            // do nothing
-        } else {
-            textField.text = [newString copy];
-            UITextPosition * newPosition = [textField positionFromPosition:textField.beginningOfDocument offset:cursorPosition+adjust];
-            
-            textField.selectedTextRange = [textField textRangeFromPosition:newPosition toPosition:newPosition];
-        }
-
-    }
-    if (_inputEvent) {
-        // bind each other , the key must be attrs
-        [self fireEvent:@"input" params:@{@"value":[textField text]} domChanges:@{@"attrs":@{@"value":[textField text]}}];
-    }
-}
-
-- (void)setViewMovedUp:(BOOL)movedUp
-{
-    UIView *rootView = self.weexInstance.rootView;
-    CGRect rect = self.weexInstance.frame;
-    CGRect rootViewFrame = rootView.frame;
-    CGRect inputFrame = [self.view.superview convertRect:self.view.frame toView:rootView];
-    if (movedUp) {
-        CGFloat offset = inputFrame.origin.y-(rootViewFrame.size.height-_keyboardSize.height-inputFrame.size.height);
-        if (offset > 0) {
-            rect = (CGRect){
-                .origin.x = 0.f,
-                .origin.y = rect.origin.y - offset,
-                .size = rootViewFrame.size
-            };
-        }
-    }
-    self.weexInstance.rootView.frame = rect;
-}
-
-#pragma mark textview Delegate
-- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
-{
-    if([self isDateType])
-    {
-        [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
-        _changeEventString = [textView text];
-        [_datePickerManager show];
-        return NO;
-    }
-    return  YES;
-}
-
-- (void)textViewDidBeginEditing:(UITextView *)textView
-{
-    _changeEventString = [textView text];
-    if (_focusEvent) {
-        [self fireEvent:@"focus" params:nil];
-    }
-    if (_clickEvent) {
-        [self fireEvent:@"click" params:nil];
-    }
-    [textView becomeFirstResponder];
-    [self handlePseudoClass];
-}
-
-- (void)textViewDidChange:(UITextView *)textView
-{
-    if(textView.text && [textView.text length] > 0) {
-        self.placeHolderLabel.text = @"";
-    }else{
-        [self setPlaceholderAttributedString];
-    }
-    if (_inputEvent) {
-        [self fireEvent:@"input" params:@{@"value":[textView text]} domChanges:@{@"attrs":@{@"value":[textView text]}}];
-    }
-}
-
-- (void)textViewDidEndEditing:(UITextView *)textView
-{
-    if (![textView.text length]) {
-        [self setPlaceholderAttributedString];
-    }
-    if (_changeEvent) {
-        if (![[textView text] isEqualToString:_changeEventString]) {
-            [self fireEvent:@"change" params:@{@"value":[textView text]} domChanges:@{@"attrs":@{@"value":[textView text]}}];
-        }
-    }
-    if (_blurEvent) {
-        [self fireEvent:@"blur" params:nil];
-    }
-    if(self.pseudoClassStyles && [self.pseudoClassStyles count]>0){
-        [self recoveryPseudoStyles:self.styles];
-    }
-}
-
-- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
-{
-    if ([text isEqualToString:@"\n"]) {
-        NSString *typeStr = [WXUtility returnKeyType:_returnKeyType];
-        if (_returnEvent) {
-            [self fireEvent:@"return" params:@{@"value":[textView text],@"returnKeyType":typeStr} domChanges:@{@"attrs":@{@"value":[textView text]}}];
-        }
-        if(typeStr.length > 0 && ![@"default" isEqualToString:typeStr]){
-            [self blur];
-            return NO;
-        }
-    }
-    
-    if (_maxLength) {
-        NSUInteger oldLength = [textView.text length];
-        NSUInteger replacementLength = [text length];
-        NSUInteger rangeLength = range.length;
-        NSUInteger newLength = oldLength - rangeLength + replacementLength;
-        return newLength <= [_maxLength integerValue] ;
-    }
-    
-    return YES;
-}
-
-#pragma mark private method
-
-- (BOOL)isDateType
-{
-    if([_inputType isEqualToString:@"date"] || [_inputType isEqualToString:@"time"])
-        return YES;
-    return NO;
-}
-
-- (void)setPlaceholderAttributedString
-{
-    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:_placeholderString];
-    [attributedString addAttribute:NSForegroundColorAttributeName value:_placeholderColor range:NSMakeRange(0, _placeholderString.length)];
-    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
-    [self setAttributedPlaceholder:attributedString font:font];
-}
-
-- (void)setTextFont
-{
-    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
-    [self setFont:font];
-}
-
-- (void)setAutofocus:(BOOL)b
-{
-    if (b) {
-        if([self isDateType])
-        {
-            [_datePickerManager show];
-        }else
-        {
-            [self.view becomeFirstResponder];
-        }
-    } else {
-        if([self isDateType])
-        {
-            [_datePickerManager hide];
-        }else
-        {
-            [self.view resignFirstResponder];
-        }
-    }
-}
-
-- (void)setType
-{
-    [self setKeyboardType:UIKeyboardTypeDefault];
-    [self setSecureTextEntry:NO];
-    if ([_inputType isEqualToString:@"text"]) {
-        [self setKeyboardType:UIKeyboardTypeDefault];
-    }else if ([_inputType isEqualToString:@"password"]) {
-        [self setSecureTextEntry:YES];
-    }else if ([_inputType isEqualToString:@"tel"]) {
-        [self setKeyboardType:UIKeyboardTypePhonePad];
-    }else if ([_inputType isEqualToString:@"email"]) {
-        [self setKeyboardType:UIKeyboardTypeEmailAddress];
-    }else if ([_inputType isEqualToString:@"url"]) {
-        [self setKeyboardType:UIKeyboardTypeURL];
-    }else if ([_inputType isEqualToString:@"number"]) {
-        [self setKeyboardType:UIKeyboardTypeDecimalPad];
-    }else if ([self isDateType]) {
-        if (!_datePickerManager) {
-            _datePickerManager = [[WXDatePickerManager alloc] init];
-            _datePickerManager.delegate = self;
-        }
-        [_datePickerManager updateDatePicker:_attr];
-    }
-}
-
-- (void)setPadding:(UIEdgeInsets)padding
-{
-    _padding = padding;
-    [self setEditPadding:padding];
-}
-
-- (void)setBorder:(UIEdgeInsets)border
-{
-    _border = border;
-    [self setEditBorder:border];
-}
-
-#pragma mark update touch styles
--(void)handlePseudoClass
-{
-    NSMutableDictionary *styles = [NSMutableDictionary new];
-    NSMutableDictionary *recordStyles = [NSMutableDictionary new];
-    if(_disabled){
-        recordStyles = [self getPseudoClassStylesByKeys:@[@"disabled"]];
-        [styles addEntriesFromDictionary:recordStyles];
-    }else {
-        recordStyles = [NSMutableDictionary new];
-        recordStyles = [self getPseudoClassStylesByKeys:@[@"enabled"]];
-        [styles addEntriesFromDictionary:recordStyles];
-    }
-    if ([self.view isFirstResponder]){
-        recordStyles = [NSMutableDictionary new];
-        recordStyles = [self getPseudoClassStylesByKeys:@[@"focus"]];
-        [styles addEntriesFromDictionary:recordStyles];
-    }
-    NSString *disabledStr = @"enabled";
-    if (_disabled){
-        disabledStr = @"disabled";
-    }
-    if ([self.view isFirstResponder]) {
-        NSString *focusStr = @"focus";
-        recordStyles = [NSMutableDictionary new];
-        recordStyles = [self getPseudoClassStylesByKeys:@[focusStr,disabledStr]];
-        [styles addEntriesFromDictionary:recordStyles];
-    }
-    [self updatePseudoClassStyles:styles];
-}
-
-#pragma mark keyboard
-- (void)keyboardWasShown:(NSNotification*)notification
-{
-    if(![self.view isFirstResponder]) {
-        return;
-    }
-    if (!_disableMoveViewUp) {
-        CGRect end = [[[notification userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
-        _keyboardSize = end.size;
-        UIView * rootView = self.weexInstance.rootView;
-        CGRect screenRect = [[UIScreen mainScreen] bounds];
-        CGRect keyboardRect = (CGRect){
-            .origin.x = 0,
-            .origin.y = CGRectGetMaxY(screenRect) - _keyboardSize.height - 54,
-            .size = _keyboardSize
-        };
-        CGRect inputFrame = [self.view.superview convertRect:self.view.frame toView:rootView];
-        if (keyboardRect.origin.y - inputFrame.size.height <= inputFrame.origin.y) {
-            [self setViewMovedUp:YES];
-            self.weexInstance.isRootViewFrozen = YES;
-        }
-    }
-    
-    if (_keyboardEvent) {
-        [self fireEvent:@"keyboard" params:@{ @"isShow": @YES }];
-    }
-}
-
-- (void)keyboardWillHide:(NSNotification*)notification
-{
-    if (![self.view isFirstResponder]) {
-        return;
-    }
-    if (!_disableMoveViewUp) {
-        UIView * rootView = self.weexInstance.rootView;
-        if (!CGRectEqualToRect(self.weexInstance.frame, rootView.frame)) {
-            [self setViewMovedUp:NO];
-            self.weexInstance.isRootViewFrozen = NO;
-        }
-    }
-    if (_keyboardEvent) {
-        [self fireEvent:@"keyboard" params:@{ @"isShow": @NO }];
-    }
-}
-
-- (void)closeKeyboard
-{
-    [self.view resignFirstResponder];
-}
-
-#pragma mark -reset color
-- (void)resetStyles:(NSArray *)styles
-{
-    if ([styles containsObject:@"color"]) {
-        [self setTextColor:[UIColor blackColor]];
-    }
-    if ([styles containsObject:@"fontSize"]) {
-        _fontSize = WX_TEXT_FONT_SIZE;
-        [self setTextFont];
-    }
-}
-@end
-

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXEditComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXEditComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXEditComponent.mm
new file mode 100644
index 0000000..43e7538
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXEditComponent.mm
@@ -0,0 +1,971 @@
+/*
+ * 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 "WXEditComponent.h"
+#import "WXConvert.h"
+#import "WXUtility.h"
+#import "WXSDKInstance.h"
+#import "WXSDKInstance_private.h"
+#import "WXDefine.h"
+#import "WXAssert.h"
+#import "WXComponent_internal.h"
+#import "WXComponent+PseudoClassManagement.h"
+#import "WXTextInputComponent.h"
+#import "WXComponent+Layout.h"
+
+@interface WXEditComponent()
+
+//@property (nonatomic, strong) WXTextInputView *inputView;
+@property (nonatomic, strong) WXDatePickerManager *datePickerManager;
+@property (nonatomic, strong) NSDictionary *attr;
+//attribute
+@property (nonatomic) NSNumber *maxLength;
+@property (nonatomic) NSString * value;
+@property (nonatomic) BOOL autofocus;
+@property(nonatomic) UIReturnKeyType returnKeyType;
+@property (nonatomic) BOOL disabled;
+@property (nonatomic, copy) NSString *inputType;
+@property (nonatomic) NSUInteger rows;
+@property (nonatomic) BOOL hideDoneButton;
+
+//style
+@property (nonatomic) WXPixelType fontSize;
+@property (nonatomic) WXTextStyle fontStyle;
+@property (nonatomic) CGFloat fontWeight;
+@property (nonatomic, strong) NSString *fontFamily;
+@property (nonatomic, strong) UIColor *colorForStyle;
+@property (nonatomic)NSTextAlignment textAlignForStyle;
+
+//event
+@property (nonatomic) BOOL inputEvent;
+@property (nonatomic) BOOL clickEvent;
+@property (nonatomic) BOOL focusEvent;
+@property (nonatomic) BOOL blurEvent;
+@property (nonatomic) BOOL changeEvent;
+@property (nonatomic) BOOL returnEvent;
+@property (nonatomic) BOOL keyboardEvent;
+@property (nonatomic, strong) NSString *changeEventString;
+@property (nonatomic, assign) CGSize keyboardSize;
+
+// formatter
+@property (nonatomic, strong) NSString * formatRule;
+@property (nonatomic, strong) NSString * formatReplace;
+@property (nonatomic, strong) NSString * recoverRule;
+@property (nonatomic, strong) NSString * recoverReplace;
+@property (nonatomic, strong) NSDictionary * formaterData;
+
+// disable move rootView up as the keyboard show up.
+@property (nonatomic, assign) BOOL disableMoveViewUp;
+
+@end
+
+@implementation WXEditComponent
+{
+    UIEdgeInsets _border;
+    UIEdgeInsets _padding;
+}
+
+WX_EXPORT_METHOD(@selector(focus))
+WX_EXPORT_METHOD(@selector(blur))
+WX_EXPORT_METHOD(@selector(setSelectionRange:selectionEnd:))
+WX_EXPORT_METHOD(@selector(getSelectionRange:))
+WX_EXPORT_METHOD(@selector(setTextFormatter:))
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        _inputEvent = NO;
+        _focusEvent = NO;
+        _blurEvent = NO;
+        _changeEvent = NO;
+        _returnEvent = NO;
+        _clickEvent = NO;
+        _keyboardEvent = NO;
+        // handle attributes
+        _autofocus = [attributes[@"autofocus"] boolValue];
+        _disabled = [attributes[@"disabled"] boolValue];
+        _value = [WXConvert NSString:attributes[@"value"]]?:@"";
+        _placeholderString = [WXConvert NSString:attributes[@"placeholder"]]?:@"";
+        if(attributes[@"type"]) {
+            _inputType = [WXConvert NSString:attributes[@"type"]];
+            _attr = attributes;
+        }
+        if (attributes[@"maxlength"]) {
+            _maxLength = [NSNumber numberWithUnsignedInteger:[attributes[@"maxlength"] integerValue]];
+        }
+        if (attributes[@"returnKeyType"]) {
+            _returnKeyType = [WXConvert UIReturnKeyType:attributes[@"returnKeyType"]];
+        }
+        if (attributes[@"rows"]) {
+            _rows = [attributes[@"rows"] integerValue];
+        } else {
+            _rows = 2;
+        }
+        
+        if (attributes[@"hideDoneButton"]) {
+            _hideDoneButton = [attributes[@"hideDoneButton"] boolValue];
+        }
+        if (attributes[@"disableMoveViewUp"]) {
+            _disableMoveViewUp = [WXConvert BOOL:attributes[@"disableMoveViewUp"]];
+        }
+        
+        // handle styles
+        if (styles[@"color"]) {
+            _colorForStyle = [WXConvert UIColor:styles[@"color"]];
+        }
+        if (styles[@"fontSize"]) {
+            _fontSize = [WXConvert WXPixelType:styles[@"fontSize"] scaleFactor:self.weexInstance.pixelScaleFactor];
+        }
+        if (styles[@"fontWeight"]) {
+            _fontWeight = [WXConvert WXTextWeight:styles[@"fontWeight"]];
+        }
+        if (styles[@"fontStyle"]) {
+            _fontStyle = [WXConvert WXTextStyle:styles[@"fontStyle"]];
+        }
+        if (styles[@"fontFamily"]) {
+            _fontFamily = styles[@"fontFamily"];
+        }
+        if (styles[@"textAlign"]) {
+            _textAlignForStyle = [WXConvert NSTextAlignment:styles[@"textAlign"]];
+        }
+        if (styles[@"placeholderColor"]) {
+            _placeholderColor = [WXConvert UIColor:styles[@"placeholderColor"]];
+        }else {
+            _placeholderColor = [UIColor colorWithRed:0x99/255.0 green:0x99/255.0 blue:0x99/255.0 alpha:1.0];
+        }
+    }
+    
+    return self;
+}
+
+#pragma mark - lifeCircle
+
+- (void)viewDidLoad
+{
+    UIView * view = self.view;
+    if ([view isKindOfClass:[UITextField class]]){
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFiledEditChanged:)
+                                                     name:UITextFieldTextDidChangeNotification
+                                                   object:view];
+    }
+    _padding = UIEdgeInsetsZero;
+    _border = UIEdgeInsetsZero;
+    self.userInteractionEnabled = YES;
+    [self setType];
+    [self setAutofocus:_autofocus];
+    [self setTextFont];
+    [self setPlaceholderAttributedString];
+    [self setTextAlignment:_textAlignForStyle];
+    [self setTextColor:_colorForStyle];
+    [self setText:_value];
+    [self setEnabled:!_disabled];
+    [self setRows:_rows];
+    [self setReturnKeyType:_returnKeyType];
+    [self updatePattern];
+    
+    if (!self.hideDoneButton) {
+        UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(closeKeyboard)];
+        UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
+        UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 0, 44)];
+        toolbar.items = [NSArray arrayWithObjects:space, barButton, nil];
+        
+        self.inputAccessoryView = toolbar;
+    }
+
+    [self handlePseudoClass];
+}
+
+- (void)viewWillLoad
+{
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(keyboardWasShown:)
+                                                 name:UIKeyboardWillShowNotification
+                                               object:nil];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(keyboardWillHide:)
+                                                 name:UIKeyboardWillHideNotification
+                                               object:nil];
+}
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+-(void)focus
+{
+    if(self.view) {
+        [self.view becomeFirstResponder];
+    }
+}
+
+-(void)blur
+{
+    if(self.view) {
+        [self.view resignFirstResponder];
+    }
+}
+
+-(void)setSelectionRange:(NSInteger)selectionStart selectionEnd:(NSInteger)selectionEnd
+{
+    if(selectionStart>self.text.length || selectionEnd>self.text.length) {
+        return;
+    }
+    [self.view becomeFirstResponder];
+    [self setEditSelectionRange:selectionStart selectionEnd:selectionEnd];
+}
+
+-(void)getSelectionRange:(WXKeepAliveCallback)callback
+{
+    NSDictionary *res = [self getEditSelectionRange];
+    if(callback) {
+        callback(res,NO);
+    }
+}
+
+- (void)setTextFormatter:(NSDictionary*)formater
+{
+    _formaterData = formater;
+    if (formater[@"formatRule"]) {;
+        _formatRule = [self _preProcessInputTextFormatter:[WXConvert NSString:formater[@"formatRule"]]];
+    }
+    if (formater[@"formatReplace"]) {
+        _formatReplace = [self _preProcessInputTextFormatter:[WXConvert NSString:formater[@"formatReplace"]]];
+    }
+    if (formater[@"recoverRule"]) {
+        _recoverRule = [self _preProcessInputTextFormatter:[WXConvert NSString:formater[@"recoverRule"]]];
+    }
+    if (formater[@"recoverReplace"]) {
+        _recoverReplace = [self _preProcessInputTextFormatter:[WXConvert NSString:formater[@"recoverReplace"]]];
+    }
+}
+
+- (NSString*)_preProcessInputTextFormatter:(NSString*)formater
+{
+    NSRange start = [formater rangeOfString:@"/"];
+    NSRange end = [formater rangeOfString:@"/g"];
+    if (start.location == NSNotFound || end.location == NSNotFound || end.location < start.location) {
+        return formater;
+    }
+    NSRange subStringRange = NSMakeRange(start.location+1, end.location - start.location-1);
+    
+    return [formater substringWithRange:subStringRange];
+}
+
+#pragma mark - Overwrite Method
+-(NSString *)text
+{
+    return @"";
+}
+
+- (void)setText:(NSString *)text
+{
+}
+
+-(void)setTextColor:(UIColor *)color
+{
+}
+
+-(void)setTextAlignment:(NSTextAlignment)textAlignForStyle
+{
+}
+
+-(void)setUserInteractionEnabled:(BOOL)userInteractionEnabled
+{
+}
+
+-(void)setEnabled:(BOOL)enabled
+{
+}
+
+-(void)setReturnKeyType:(UIReturnKeyType)returnKeyType
+{
+}
+
+-(void)setInputAccessoryView:(UIView *)inputAccessoryView
+{
+}
+
+-(void)setEditSelectionRange:(NSInteger)selectionStart selectionEnd:(NSInteger)selectionEnd
+{
+}
+
+-(NSDictionary *)getEditSelectionRange
+{
+    return @{};
+}
+
+-(void)setKeyboardType:(UIKeyboardType)keyboardType
+{
+}
+
+-(void)setSecureTextEntry:(BOOL)secureTextEntry
+{
+}
+
+-(void)setEditPadding:(UIEdgeInsets)padding
+{
+}
+
+-(void)setEditBorder:(UIEdgeInsets)border
+{
+}
+
+-(void)setAttributedPlaceholder:(NSMutableAttributedString *)attributedString font:(UIFont *)font
+{
+}
+
+-(void)setFont:(UIFont *)font
+{
+}
+
+-(void)setRows:(NSUInteger)rows
+{
+}
+
+#pragma mark - Add Event
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"input"]) {
+        _inputEvent = YES;
+    }
+    if ([eventName isEqualToString:@"focus"]) {
+        _focusEvent = YES;
+    }
+    if ([eventName isEqualToString:@"blur"]) {
+        _blurEvent = YES;
+    }
+    if ([eventName isEqualToString:@"change"]) {
+        _changeEvent = YES;
+    }
+    if ([eventName isEqualToString:@"return"]) {
+        _returnEvent = YES;
+    }
+    if ([eventName isEqualToString:@"click"]) {
+        _clickEvent = YES;
+    }
+    if ([eventName isEqualToString:@"keyboard"]) {
+        _keyboardEvent = YES;
+    }
+}
+
+#pragma Remove Event
+
+-(void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"input"]) {
+        _inputEvent = NO;
+    }
+    if ([eventName isEqualToString:@"focus"]) {
+        _focusEvent = NO;
+    }
+    if ([eventName isEqualToString:@"blur"]) {
+        _blurEvent = NO;
+    }
+    if ([eventName isEqualToString:@"change"]) {
+        _changeEvent = NO;
+    }
+    if ([eventName isEqualToString:@"return"]) {
+        _returnEvent = NO;
+    }
+    if ([eventName isEqualToString:@"click"]) {
+        _clickEvent = NO;
+    }
+    if ([eventName isEqualToString:@"keyboard"]) {
+        _keyboardEvent = NO;
+    }
+}
+
+#pragma mark - upate attributes
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    _attr = attributes;
+    if (attributes[@"type"]) {
+        _inputType = [WXConvert NSString:attributes[@"type"]];
+        [self setType];
+    }
+    if (attributes[@"autofocus"]) {
+        self.autofocus = [attributes[@"autofocus"] boolValue];
+    }
+    if (attributes[@"disabled"]) {
+        _disabled = [attributes[@"disabled"] boolValue];
+        [self setEnabled:!_disabled];
+    }
+    if (attributes[@"maxlength"]) {
+        _maxLength = [NSNumber numberWithInteger:[attributes[@"maxlength"] integerValue]];
+    }
+    
+    if (attributes[@"disableMoveViewUp"]) {
+        _disableMoveViewUp = [WXConvert BOOL:attributes[@"disableMoveViewUp"]];
+    }
+    if (attributes[@"value"]) {
+        _value = [WXConvert NSString:attributes[@"value"]]?:@"";
+        if (_maxLength && [_value length] > [_maxLength integerValue]&& [_maxLength integerValue] >= 0) {
+            _value = [_value substringToIndex:([_maxLength integerValue])];
+        }
+        [self setText:_value];
+    }
+    if (attributes[@"placeholder"]) {
+        _placeholderString = [WXConvert NSString:attributes[@"placeholder"]]?:@"";
+        [self setPlaceholderAttributedString];
+        if(_value.length > 0){
+            _placeHolderLabel.text = @"";
+        }
+    }
+    if (attributes[@"returnKeyType"]) {
+        _returnKeyType = [WXConvert UIReturnKeyType:attributes[@"returnKeyType"]];
+        [self setReturnKeyType:_returnKeyType];
+    }
+    if (attributes[@"rows"]) {
+        _rows = [attributes[@"rows"] integerValue];
+        [self setRows:_rows];
+    } else {
+        _rows = 2;
+        [self setRows:_rows];
+    }
+}
+
+#pragma mark - upate styles
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+    if (styles[@"color"]) {
+        _colorForStyle = [WXConvert UIColor:styles[@"color"]];
+        [self setTextColor:_colorForStyle];
+    }
+    if (styles[@"fontSize"]) {
+        _fontSize = [WXConvert WXPixelType:styles[@"fontSize"] scaleFactor:self.weexInstance.pixelScaleFactor];
+    }
+    if (styles[@"fontWeight"]) {
+        _fontWeight = [WXConvert WXTextWeight:styles[@"fontWeight"]];
+    }
+    if (styles[@"fontStyle"]) {
+        _fontStyle = [WXConvert WXTextStyle:styles[@"fontStyle"]];
+    }
+    if (styles[@"fontFamily"]) {
+        _fontFamily = [WXConvert NSString:styles[@"fontFamily"]];
+    }
+    [self setTextFont];
+    
+    if (styles[@"textAlign"]) {
+        _textAlignForStyle = [WXConvert NSTextAlignment:styles[@"textAlign"]];
+        [self setTextAlignment:_textAlignForStyle] ;
+    }
+    if (styles[@"placeholderColor"]) {
+        _placeholderColor = [WXConvert UIColor:styles[@"placeholderColor"]];
+    }else {
+        _placeholderColor = [UIColor colorWithRed:0x99/255.0 green:0x99/255.0 blue:0x99/255.0 alpha:1.0];
+    }
+    [self setPlaceholderAttributedString];
+    [self updatePattern];
+}
+
+-(void)updatePattern
+{
+//#ifndef USE_FLEX
+    if (![WXComponent isUseFlex]) {
+        UIEdgeInsets padding = UIEdgeInsetsMake(self.cssNode->style.padding[CSS_TOP], self.cssNode->style.padding[CSS_LEFT], self.cssNode->style.padding[CSS_BOTTOM], self.cssNode->style.padding[CSS_RIGHT]);
+        if (!UIEdgeInsetsEqualToEdgeInsets(padding, _padding)) {
+            [self setPadding:padding];
+        }
+        
+        UIEdgeInsets border = UIEdgeInsetsMake(self.cssNode->style.border[CSS_TOP], self.cssNode->style.border[CSS_LEFT], self.cssNode->style.border[CSS_BOTTOM], self.cssNode->style.border[CSS_RIGHT]);
+        if (!UIEdgeInsetsEqualToEdgeInsets(border, _border)) {
+            [self setBorder:border];
+        }
+        
+    }
+//#else
+    else{
+        UIEdgeInsets padding_flex = UIEdgeInsetsMake(
+                                                     self.flexCssNode->getPaddingTop(),
+                                                     self.flexCssNode->getPaddingLeft(),
+                                                     self.flexCssNode->getPaddingBottom(),
+                                                     self.flexCssNode->getPaddingRight()
+                                                     );
+        
+        if (!UIEdgeInsetsEqualToEdgeInsets(padding_flex, _padding)) {
+            [self setPadding:padding_flex];
+        }
+        
+        
+        UIEdgeInsets border_flex = UIEdgeInsetsMake(self.flexCssNode->getBorderWidthTop(), self.flexCssNode->getBorderWidthLeft(), self.flexCssNode->getBorderWidthBottom(), self.flexCssNode->getBorderWidthRight());
+        
+        
+        
+        
+        if (!UIEdgeInsetsEqualToEdgeInsets(border_flex, _border)) {
+            [self setBorder:border_flex];
+        }
+    }
+//#endif
+}
+
+- (CGSize (^)(CGSize))measureBlock
+{
+    __weak typeof(self) weakSelf = self;
+    return ^CGSize (CGSize constrainedSize) {
+        
+        CGSize computedSize = [[[NSString alloc] init]sizeWithAttributes:nil];
+        
+//#ifndef USE_FLEX
+        if (![WXComponent isUseFlex]) {
+            //TODO:more elegant way to use max and min constrained size
+            if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
+                computedSize.width = MAX(computedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
+            }
+            
+            if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
+                computedSize.width = MIN(computedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
+            }
+            
+            if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_HEIGHT])) {
+                computedSize.height = MAX(computedSize.height, weakSelf.cssNode->style.minDimensions[CSS_HEIGHT]);
+            }
+            
+            if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT])) {
+                computedSize.height = MIN(computedSize.height, weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT]);
+            }
+        }
+//#else
+        else
+        {
+            if (!isnan(weakSelf.flexCssNode->getMinWidth())) {
+                computedSize.width = MAX(computedSize.width, weakSelf.flexCssNode->getMinWidth());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMaxWidth())) {
+                computedSize.width = MIN(computedSize.width, weakSelf.flexCssNode->getMaxWidth());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMinHeight())) {
+                computedSize.height = MAX(computedSize.height, weakSelf.flexCssNode->getMinHeight());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMaxHeight())) {
+                computedSize.height = MIN(computedSize.height, weakSelf.flexCssNode->getMaxHeight());
+            }
+        }
+       
+//#endif
+        return (CGSize) {
+            WXCeilPixelValue(computedSize.width),
+            WXCeilPixelValue(computedSize.height)
+        };
+    };
+}
+
+#pragma mark WXDatePickerManagerDelegate
+
+-(void)fetchDatePickerValue:(NSString *)value
+{
+    self.text = value;
+    if (_changeEvent) {
+        if (![[self text] isEqualToString:_changeEventString]) {
+            [self fireEvent:@"change" params:@{@"value":[self text]} domChanges:@{@"attrs":@{@"value":[self text]}}];
+        }
+    }
+}
+
+#pragma mark UITextFieldDelegate
+
+- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
+    if([self isDateType])
+    {
+        [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
+        _changeEventString = [textField text];
+        [_datePickerManager show];
+        return NO;
+    }
+    return  YES;
+}
+
+#pragma mark UITextFieldDelegate
+
+- (void)textFieldDidBeginEditing:(UITextField *)textField
+{
+    _changeEventString = [textField text];
+    if (_focusEvent) {
+        [self fireEvent:@"focus" params:nil];
+    }
+    [self handlePseudoClass];
+}
+
+- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
+{
+    if (!string.length) {
+        ((WXTextInputView*)textField).deleteWords = YES;
+        ((WXTextInputView*)textField).editWords = [textField.text substringWithRange:range];
+    } else {
+        ((WXTextInputView*)textField).deleteWords = FALSE;
+        ((WXTextInputView*)textField).editWords = string;
+    }
+    
+    if (_maxLength) {
+        NSUInteger oldLength = [textField.text length];
+        NSUInteger replacementLength = [string length];
+        NSUInteger rangeLength = range.length;
+        
+        NSUInteger newLength = oldLength - rangeLength + replacementLength;
+        
+        return newLength <= [_maxLength integerValue] ;
+    }
+    
+    return YES;
+}
+
+- (void)textFieldDidEndEditing:(UITextField *)textField
+{
+    if (_changeEvent) {
+        if (![[textField text] isEqualToString:_changeEventString]) {
+            [self fireEvent:@"change" params:@{@"value":[textField text]} domChanges:@{@"attrs":@{@"value":[textField text]}}];
+        }
+    }
+    if (_blurEvent) {
+        [self fireEvent:@"blur" params:nil];
+    }
+    if(self.pseudoClassStyles && [self.pseudoClassStyles count]>0){
+        [self recoveryPseudoStyles:self.styles];
+    }
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField *)textField
+{
+    if (_returnEvent) {
+        NSString *typeStr = [WXUtility returnKeyType:_returnKeyType];
+        [self fireEvent:@"return" params:@{@"value":[textField text],@"returnKeyType":typeStr} domChanges:@{@"attrs":@{@"value":[textField text]}}];
+    }
+    [self blur];
+    return YES;
+}
+
+- (void)textFiledEditChanged:(NSNotification *)notifi
+{
+    WXTextInputView *textField = (WXTextInputView *)notifi.object;
+    if (_formaterData && _recoverRule && _recoverReplace && _formatRule && _formatReplace) {
+        UITextRange * textRange = textField.selectedTextRange;
+        NSInteger cursorPosition = [textField offsetFromPosition:textField.beginningOfDocument toPosition:textRange.start];
+        NSMutableString * preText = [[textField.text substringToIndex:cursorPosition] mutableCopy];
+        NSMutableString * lastText = [[textField.text substringFromIndex:cursorPosition] mutableCopy];
+        
+        NSRegularExpression *recoverRule = [NSRegularExpression regularExpressionWithPattern:_recoverRule options:NSRegularExpressionCaseInsensitive error:NULL];
+        [recoverRule replaceMatchesInString:preText options:0 range:NSMakeRange(0, preText.length) withTemplate:_recoverReplace];
+        [recoverRule replaceMatchesInString:lastText options:0 range:NSMakeRange(0, lastText.length) withTemplate:_recoverReplace];
+        NSMutableString * newString = [NSMutableString stringWithFormat:@"%@%@", preText, lastText];
+        NSRegularExpression *formatRule = [NSRegularExpression regularExpressionWithPattern:_formatRule options:NSRegularExpressionCaseInsensitive error:NULL];
+        [formatRule replaceMatchesInString:newString options:0 range:NSMakeRange(0, newString.length) withTemplate:_formatReplace];
+        NSString * oldText = textField.text;
+        NSInteger adjust = 0;
+        
+        if (cursorPosition == textField.text.length) {
+            adjust = newString.length-oldText.length;
+        }
+        if (textField.deleteWords &&[textField.editWords isKindOfClass:[NSString class]] && [_recoverRule isEqualToString:textField.editWords]) {
+            // do nothing
+        } else {
+            textField.text = [newString copy];
+            UITextPosition * newPosition = [textField positionFromPosition:textField.beginningOfDocument offset:cursorPosition+adjust];
+            
+            textField.selectedTextRange = [textField textRangeFromPosition:newPosition toPosition:newPosition];
+        }
+
+    }
+    if (_inputEvent) {
+        // bind each other , the key must be attrs
+        [self fireEvent:@"input" params:@{@"value":[textField text]} domChanges:@{@"attrs":@{@"value":[textField text]}}];
+    }
+}
+
+- (void)setViewMovedUp:(BOOL)movedUp
+{
+    UIView *rootView = self.weexInstance.rootView;
+    CGRect rect = self.weexInstance.frame;
+    CGRect rootViewFrame = rootView.frame;
+    CGRect inputFrame = [self.view.superview convertRect:self.view.frame toView:rootView];
+    if (movedUp) {
+        CGFloat offset = inputFrame.origin.y-(rootViewFrame.size.height-_keyboardSize.height-inputFrame.size.height);
+        if (offset > 0) {
+            rect = (CGRect){
+                .origin.x = 0.f,
+                .origin.y = rect.origin.y - offset,
+                .size = rootViewFrame.size
+            };
+        }
+    }
+    self.weexInstance.rootView.frame = rect;
+}
+
+#pragma mark textview Delegate
+- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
+{
+    if([self isDateType])
+    {
+        [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
+        _changeEventString = [textView text];
+        [_datePickerManager show];
+        return NO;
+    }
+    return  YES;
+}
+
+- (void)textViewDidBeginEditing:(UITextView *)textView
+{
+    _changeEventString = [textView text];
+    if (_focusEvent) {
+        [self fireEvent:@"focus" params:nil];
+    }
+    if (_clickEvent) {
+        [self fireEvent:@"click" params:nil];
+    }
+    [textView becomeFirstResponder];
+    [self handlePseudoClass];
+}
+
+- (void)textViewDidChange:(UITextView *)textView
+{
+    if(textView.text && [textView.text length] > 0) {
+        self.placeHolderLabel.text = @"";
+    }else{
+        [self setPlaceholderAttributedString];
+    }
+    if (_inputEvent) {
+        [self fireEvent:@"input" params:@{@"value":[textView text]} domChanges:@{@"attrs":@{@"value":[textView text]}}];
+    }
+}
+
+- (void)textViewDidEndEditing:(UITextView *)textView
+{
+    if (![textView.text length]) {
+        [self setPlaceholderAttributedString];
+    }
+    if (_changeEvent) {
+        if (![[textView text] isEqualToString:_changeEventString]) {
+            [self fireEvent:@"change" params:@{@"value":[textView text]} domChanges:@{@"attrs":@{@"value":[textView text]}}];
+        }
+    }
+    if (_blurEvent) {
+        [self fireEvent:@"blur" params:nil];
+    }
+    if(self.pseudoClassStyles && [self.pseudoClassStyles count]>0){
+        [self recoveryPseudoStyles:self.styles];
+    }
+}
+
+- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
+{
+    if ([text isEqualToString:@"\n"]) {
+        NSString *typeStr = [WXUtility returnKeyType:_returnKeyType];
+        if (_returnEvent) {
+            [self fireEvent:@"return" params:@{@"value":[textView text],@"returnKeyType":typeStr} domChanges:@{@"attrs":@{@"value":[textView text]}}];
+        }
+        if(typeStr.length > 0 && ![@"default" isEqualToString:typeStr]){
+            [self blur];
+            return NO;
+        }
+    }
+    
+    if (_maxLength) {
+        NSUInteger oldLength = [textView.text length];
+        NSUInteger replacementLength = [text length];
+        NSUInteger rangeLength = range.length;
+        NSUInteger newLength = oldLength - rangeLength + replacementLength;
+        return newLength <= [_maxLength integerValue] ;
+    }
+    
+    return YES;
+}
+
+#pragma mark private method
+
+- (BOOL)isDateType
+{
+    if([_inputType isEqualToString:@"date"] || [_inputType isEqualToString:@"time"])
+        return YES;
+    return NO;
+}
+
+- (void)setPlaceholderAttributedString
+{
+    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:_placeholderString];
+    [attributedString addAttribute:NSForegroundColorAttributeName value:_placeholderColor range:NSMakeRange(0, _placeholderString.length)];
+    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
+    [self setAttributedPlaceholder:attributedString font:font];
+}
+
+- (void)setTextFont
+{
+    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
+    [self setFont:font];
+}
+
+- (void)setAutofocus:(BOOL)b
+{
+    if (b) {
+        if([self isDateType])
+        {
+            [_datePickerManager show];
+        }else
+        {
+            [self.view becomeFirstResponder];
+        }
+    } else {
+        if([self isDateType])
+        {
+            [_datePickerManager hide];
+        }else
+        {
+            [self.view resignFirstResponder];
+        }
+    }
+}
+
+- (void)setType
+{
+    [self setKeyboardType:UIKeyboardTypeDefault];
+    [self setSecureTextEntry:NO];
+    if ([_inputType isEqualToString:@"text"]) {
+        [self setKeyboardType:UIKeyboardTypeDefault];
+    }else if ([_inputType isEqualToString:@"password"]) {
+        [self setSecureTextEntry:YES];
+    }else if ([_inputType isEqualToString:@"tel"]) {
+        [self setKeyboardType:UIKeyboardTypePhonePad];
+    }else if ([_inputType isEqualToString:@"email"]) {
+        [self setKeyboardType:UIKeyboardTypeEmailAddress];
+    }else if ([_inputType isEqualToString:@"url"]) {
+        [self setKeyboardType:UIKeyboardTypeURL];
+    }else if ([_inputType isEqualToString:@"number"]) {
+        [self setKeyboardType:UIKeyboardTypeDecimalPad];
+    }else if ([self isDateType]) {
+        if (!_datePickerManager) {
+            _datePickerManager = [[WXDatePickerManager alloc] init];
+            _datePickerManager.delegate = self;
+        }
+        [_datePickerManager updateDatePicker:_attr];
+    }
+}
+
+- (void)setPadding:(UIEdgeInsets)padding
+{
+    _padding = padding;
+    [self setEditPadding:padding];
+}
+
+- (void)setBorder:(UIEdgeInsets)border
+{
+    _border = border;
+    [self setEditBorder:border];
+}
+
+#pragma mark update touch styles
+-(void)handlePseudoClass
+{
+    NSMutableDictionary *styles = [NSMutableDictionary new];
+    NSMutableDictionary *recordStyles = [NSMutableDictionary new];
+    if(_disabled){
+        recordStyles = [self getPseudoClassStylesByKeys:@[@"disabled"]];
+        [styles addEntriesFromDictionary:recordStyles];
+    }else {
+        recordStyles = [NSMutableDictionary new];
+        recordStyles = [self getPseudoClassStylesByKeys:@[@"enabled"]];
+        [styles addEntriesFromDictionary:recordStyles];
+    }
+    if ([self.view isFirstResponder]){
+        recordStyles = [NSMutableDictionary new];
+        recordStyles = [self getPseudoClassStylesByKeys:@[@"focus"]];
+        [styles addEntriesFromDictionary:recordStyles];
+    }
+    NSString *disabledStr = @"enabled";
+    if (_disabled){
+        disabledStr = @"disabled";
+    }
+    if ([self.view isFirstResponder]) {
+        NSString *focusStr = @"focus";
+        recordStyles = [NSMutableDictionary new];
+        recordStyles = [self getPseudoClassStylesByKeys:@[focusStr,disabledStr]];
+        [styles addEntriesFromDictionary:recordStyles];
+    }
+    [self updatePseudoClassStyles:styles];
+}
+
+#pragma mark keyboard
+- (void)keyboardWasShown:(NSNotification*)notification
+{
+    if(![self.view isFirstResponder]) {
+        return;
+    }
+    if (!_disableMoveViewUp) {
+        CGRect end = [[[notification userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
+        _keyboardSize = end.size;
+        UIView * rootView = self.weexInstance.rootView;
+        CGRect screenRect = [[UIScreen mainScreen] bounds];
+        CGRect keyboardRect = (CGRect){
+            .origin.x = 0,
+            .origin.y = CGRectGetMaxY(screenRect) - _keyboardSize.height - 54,
+            .size = _keyboardSize
+        };
+        CGRect inputFrame = [self.view.superview convertRect:self.view.frame toView:rootView];
+        if (keyboardRect.origin.y - inputFrame.size.height <= inputFrame.origin.y) {
+            [self setViewMovedUp:YES];
+            self.weexInstance.isRootViewFrozen = YES;
+        }
+    }
+    
+    if (_keyboardEvent) {
+        [self fireEvent:@"keyboard" params:@{ @"isShow": @YES }];
+    }
+}
+
+- (void)keyboardWillHide:(NSNotification*)notification
+{
+    if (![self.view isFirstResponder]) {
+        return;
+    }
+    if (!_disableMoveViewUp) {
+        UIView * rootView = self.weexInstance.rootView;
+        if (!CGRectEqualToRect(self.weexInstance.frame, rootView.frame)) {
+            [self setViewMovedUp:NO];
+            self.weexInstance.isRootViewFrozen = NO;
+        }
+    }
+    if (_keyboardEvent) {
+        [self fireEvent:@"keyboard" params:@{ @"isShow": @NO }];
+    }
+}
+
+- (void)closeKeyboard
+{
+    [self.view resignFirstResponder];
+}
+
+#pragma mark -reset color
+- (void)resetStyles:(NSArray *)styles
+{
+    if ([styles containsObject:@"color"]) {
+        [self setTextColor:[UIColor blackColor]];
+    }
+    if ([styles containsObject:@"fontSize"]) {
+        _fontSize = WX_TEXT_FONT_SIZE;
+        [self setTextFont];
+    }
+}
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.m
deleted file mode 100644
index dbfe3dc..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.m
+++ /dev/null
@@ -1,87 +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 "WXHeaderComponent.h"
-#import "WXComponent_internal.h"
-
-@implementation WXHeaderComponent
-{
-    BOOL _isUseContainerWidth;
-}
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    
-    if (self) {
-        _async = YES;
-        _isNeedJoinLayoutSystem = NO;
-        _keepScrollPosition = attributes[@"keepScrollPosition"] ? [WXConvert BOOL:attributes[@"keepScrollPosition"]] : NO;
-    }
-    
-    return self;
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    if (attributes[@"keepScrollPosition"]) {
-        _keepScrollPosition = [WXConvert BOOL:attributes[@"keepScrollPosition"]];
-    }
-}
-
-- (BOOL)isSticky
-{
-    return _positionType == WXPositionTypeSticky;
-}
-
-- (void)_frameDidCalculated:(BOOL)isChanged
-{
-    [super _frameDidCalculated:isChanged];
-    
-    if (isChanged) {
-        [self.delegate headerDidLayout:self];
-    }
-}
-
-- (void)_removeFromSupercomponent
-{
-    [super _removeFromSupercomponent];
-    
-    [self.delegate headerDidRemove:self];
-}
-
-- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
-{
-    if (self.delegate && (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) || _isUseContainerWidth)) {
-        self.cssNode->style.dimensions[CSS_WIDTH] = [self.delegate headerWidthForLayout:self];
-        //TODO: set _isUseContainerWidth to NO if updateStyles have width
-        _isUseContainerWidth = YES;
-    }
-    
-    if ([self needsLayout]) {
-        layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
-        if ([WXLog logLevel] >= WXLogLevelDebug) {
-            print_css_node(self.cssNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
-        }
-    }
-    
-    [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.mm
new file mode 100644
index 0000000..97e4252
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.mm
@@ -0,0 +1,110 @@
+/*
+ * 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 "WXHeaderComponent.h"
+#import "WXComponent_internal.h"
+#import "WXComponent+Layout.h"
+
+@implementation WXHeaderComponent
+{
+    BOOL _isUseContainerWidth;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    
+    if (self) {
+        _async = YES;
+        _isNeedJoinLayoutSystem = NO;
+        _keepScrollPosition = attributes[@"keepScrollPosition"] ? [WXConvert BOOL:attributes[@"keepScrollPosition"]] : NO;
+    }
+    
+    return self;
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"keepScrollPosition"]) {
+        _keepScrollPosition = [WXConvert BOOL:attributes[@"keepScrollPosition"]];
+    }
+}
+
+- (BOOL)isSticky
+{
+    return _positionType == WXPositionTypeSticky;
+}
+
+- (void)_frameDidCalculated:(BOOL)isChanged
+{
+    [super _frameDidCalculated:isChanged];
+    
+    if (isChanged) {
+        [self.delegate headerDidLayout:self];
+    }
+}
+
+- (void)_removeFromSupercomponent
+{
+    [super _removeFromSupercomponent];
+    
+    [self.delegate headerDidRemove:self];
+}
+
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
+{
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex]){
+        if (self.delegate && (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) || _isUseContainerWidth)) {
+            self.cssNode->style.dimensions[CSS_WIDTH] = [self.delegate headerWidthForLayout:self];
+            //TODO: set _isUseContainerWidth to NO if updateStyles have width
+            _isUseContainerWidth = YES;
+        }
+        
+        if ([self needsLayout]) {
+            layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
+            if ([WXLog logLevel] >= WXLogLevelDebug) {
+                print_css_node(self.cssNode, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN));
+            }
+        }
+    }
+   
+//#else
+    else
+    {
+        if (self.delegate && ( isnan(self.flexCssNode->getStyleWidth()) || _isUseContainerWidth)) {
+            self.flexCssNode->setStyleWidth([self.delegate headerWidthForLayout:self],NO);
+            //TODO: set _isUseContainerWidth to NO if updateStyles have width
+            _isUseContainerWidth = YES;
+        }
+        
+        if ([self needsLayout]) {
+            std::pair<float, float> renderPageSize;
+            renderPageSize.first = self.weexInstance.frame.size.width;
+            renderPageSize.second = self.weexInstance.frame.size.height;
+            self.flexCssNode->calculateLayout(renderPageSize);
+        }
+    }
+    
+    
+//#endif
+    [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+}
+
+@end


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
deleted file mode 100644
index d73531c..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
+++ /dev/null
@@ -1,975 +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 "WXListComponent.h"
-#import "WXCellComponent.h"
-#import "WXHeaderComponent.h"
-#import "WXComponent.h"
-#import "WXComponent_internal.h"
-#import "NSArray+Weex.h"
-#import "WXAssert.h"
-#import "WXMonitor.h"
-#import "WXUtility.h"
-#import "NSObject+WXSwizzle.h"
-#import "WXSDKInstance_private.h"
-#import "WXRefreshComponent.h"
-#import "WXLoadingComponent.h"
-
-@interface WXTableView : UITableView
-
-@end
-
-@implementation WXTableView
-
-+ (BOOL)requiresConstraintBasedLayout
-{
-    return NO;
-}
-
-- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
-{
-    if ([(id <WXScrollerProtocol>) self.wx_component respondsToSelector:@selector(requestGestureShouldStopPropagation:shouldReceiveTouch:)]) {
-        return [(id <WXScrollerProtocol>) self.wx_component requestGestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
-    }
-    else{
-        return YES;
-    }
-}
-
-- (void)layoutSubviews
-{
-    [super layoutSubviews];
-    [self.wx_component layoutDidFinish];
-}
-
-- (void)setContentOffset:(CGPoint)contentOffset
-{
-    // FIXME: side effect caused by hooking _adjustContentOffsetIfNecessary.
-    // When UITableView is pulled down and finger releases,contentOffset will be set from -xxxx to about -0.5(greater than -0.5), then contentOffset will be reset to zero by calling _adjustContentOffsetIfNecessary.
-    // So hooking _adjustContentOffsetIfNecessary will always cause remaining 1px space between list's top and navigator.
-    // Demo: http://dotwe.org/895630945793a9a044e49abe39cbb77f
-    // Have to reset contentOffset to zero manually here.
-    if (fabs(contentOffset.y) < 0.5) {
-        contentOffset.y = 0;
-    }
-    if (isnan(contentOffset.x)) {
-        contentOffset.x = 0;
-    }
-    if(isnan(contentOffset.y)) {
-        contentOffset.y = 0;
-    }
-    
-    [super setContentOffset:contentOffset];
-}
-
-@end
-
-// WXText is a non-public is not permitted
-@interface WXSectionComponent : NSObject<NSCopying>
-
-@property (nonatomic, strong) WXHeaderComponent *header;
-@property (nonatomic, strong) NSMutableArray<WXCellComponent *> *rows;
-
-@end
-
-@implementation WXSectionComponent
-
-- (instancetype)init
-{
-    if (self = [super init]) {
-        _rows = [NSMutableArray array];
-    }
-    
-    return self;
-}
-
-- (id)copyWithZone:(NSZone *)zone
-{
-    WXSectionComponent *newSection = [[[self class] allocWithZone:zone] init];
-    newSection.header = _header;
-    newSection.rows = [_rows mutableCopyWithZone:zone];
-    
-    return newSection;
-}
-
-- (NSString *)description
-{
-    return [NSString stringWithFormat:@"%@\n%@", [_header description], [_rows description]];
-}
-@end
-
-@interface WXListComponent () <UITableViewDataSource, UITableViewDelegate, WXCellRenderDelegate, WXHeaderRenderDelegate>
-
-@property (nonatomic, assign) NSUInteger currentTopVisibleSection;
-
-@end
-
-@implementation WXListComponent
-{
-    __weak UITableView * _tableView;
-
-    // Only accessed on component thread
-    NSMutableArray<WXSectionComponent *> *_sections;
-    // Only accessed on main thread
-    NSMutableArray<WXSectionComponent *> *_completedSections;
-    NSUInteger _previousLoadMoreRowNumber;
-    // insert & reload & batch
-    NSString *_updataType;
-    
-    BOOL _isUpdating;
-    NSMutableArray<void(^)(void)> *_updates;
-    NSTimeInterval _reloadInterval;
-}
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
-        _sections = [NSMutableArray array];
-        _completedSections = [NSMutableArray array];
-        _reloadInterval = attributes[@"reloadInterval"] ? [WXConvert CGFloat:attributes[@"reloadInterval"]]/1000 : 0;
-        _updataType = [WXConvert NSString:attributes[@"updataType"]]?:@"insert";
-        [self fixFlicker];
-    }
-    
-    return self;
-}
-
-- (void)dealloc
-{
-    if (_tableView) {
-        _tableView.delegate = nil;
-        _tableView.dataSource = nil;
-    }
-}
-
-- (UIView *)loadView
-{
-    return [[WXTableView alloc] init];
-}
-
-- (void)viewDidLoad
-{
-    [super viewDidLoad];
-    
-    _tableView = (UITableView *)self.view;
-    _tableView.allowsSelection = NO;
-    _tableView.allowsMultipleSelection = NO;
-    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
-    _tableView.delegate = self;
-    _tableView.dataSource = self;
-    _tableView.userInteractionEnabled = YES;
-    
-    _tableView.estimatedRowHeight = 0;
-    _tableView.estimatedSectionFooterHeight = 0;
-    _tableView.estimatedSectionHeaderHeight = 0;
-}
-
-- (void)viewWillUnload
-{
-    [super viewWillUnload];
-    
-    _tableView.delegate = nil;
-    _tableView.dataSource = nil;
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    [super updateAttributes:attributes];
-    
-    if (attributes[@"reloadInterval"]) {
-        _reloadInterval = [WXConvert CGFloat:attributes[@"reloadInterval"]] / 1000;
-    }
-    if (attributes[@"updataType"]) {
-        _updataType = [WXConvert NSString:attributes[@"updataType"]];
-    }
-}
-
-- (void)setContentSize:(CGSize)contentSize
-{
-    // Do Nothing
-}
-
-- (void)_handleFirstScreenTime
-{
-    // Do Nothing, firstScreenTime is set by cellDidRendered:
-}
-
-- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset animated:(BOOL)animated
-{
-    CGPoint contentOffset = _tableView.contentOffset;
-    CGFloat contentOffsetY = 0;
-    
-    WXComponent *cellComponent = component;
-    CGRect cellRect;
-    while (cellComponent) {
-        if ([cellComponent isKindOfClass:[WXCellComponent class]]) {
-            NSIndexPath *toIndexPath = [self indexPathForCell:(WXCellComponent*)cellComponent sections:_completedSections];
-            cellRect = [_tableView rectForRowAtIndexPath:toIndexPath];
-            break;
-        }
-        if ([cellComponent isKindOfClass:[WXHeaderComponent class]]) {
-            NSUInteger toIndex = [self indexForHeader:(WXHeaderComponent *)cellComponent sections:_completedSections];
-            cellRect = [_tableView rectForSection:toIndex];
-            break;
-        }
-        contentOffsetY += cellComponent.calculatedFrame.origin.y;
-        cellComponent = cellComponent.supercomponent;
-    }
-    
-    contentOffsetY += cellRect.origin.y;
-    contentOffsetY += offset * self.weexInstance.pixelScaleFactor;
-    
-    if (_tableView.contentSize.height >= _tableView.frame.size.height && contentOffsetY > _tableView.contentSize.height - _tableView.frame.size.height) {
-        contentOffset.y = _tableView.contentSize.height - _tableView.frame.size.height;
-    } else {
-        contentOffset.y = contentOffsetY;
-    }
-    
-    [_tableView setContentOffset:contentOffset animated:animated];
-}
-
-
-#pragma mark - Inheritance
-
-- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    if ([subcomponent isKindOfClass:[WXCellComponent class]]) {
-        ((WXCellComponent *)subcomponent).delegate = self;
-    } else if ([subcomponent isKindOfClass:[WXHeaderComponent class]]) {
-        ((WXHeaderComponent *)subcomponent).delegate = self;
-    } else if (![subcomponent isKindOfClass:[WXRefreshComponent class]]
-               && ![subcomponent isKindOfClass:[WXLoadingComponent class]]
-               && subcomponent->_positionType != WXPositionTypeFixed) {
-        WXLogError(@"list only support cell/header/refresh/loading/fixed-component as child.");
-        return;
-    }
-    
-    [super _insertSubcomponent:subcomponent atIndex:index];
-    
-    if (![subcomponent isKindOfClass:[WXHeaderComponent class]]
-        && ![subcomponent isKindOfClass:[WXCellComponent class]]) {
-        // Don't insert section if subcomponent is not header or cell
-        return;
-    }
-    
-    NSIndexPath *indexPath = [self indexPathForSubIndex:index];
-    
-    if ([subcomponent isKindOfClass:[WXHeaderComponent class]] || _sections.count <= indexPath.section) {
-        // conditions to insert section: insert a header or insert first cell of table view
-        // this will be updated by recycler's update controller in the future
-        WXSectionComponent *insertSection = [WXSectionComponent new];
-        BOOL keepScrollPosition = NO;
-        if ([subcomponent isKindOfClass:[WXHeaderComponent class]]) {
-            WXHeaderComponent *header = (WXHeaderComponent*)subcomponent;
-            insertSection.header = header;
-            keepScrollPosition = header.keepScrollPosition;
-        }
-        
-        NSUInteger insertIndex = indexPath.section;
-        WXSectionComponent *reloadSection;
-        if (insertIndex > 0 && insertIndex <= _sections.count
-            && [subcomponent isKindOfClass:[WXHeaderComponent class]]) {
-            // insert a header in the middle, one section may divide into two
-            // so the original section need to be reloaded
-            NSIndexPath *indexPathBeforeHeader = [self indexPathForSubIndex:index - 1];
-            if (_sections[insertIndex - 1].rows.count != 0 && indexPathBeforeHeader.row < _sections[insertIndex - 1].rows.count - 1) {
-                reloadSection = _sections[insertIndex - 1];
-                NSArray *rowsToSeparate = reloadSection.rows;
-                insertSection.rows = [[rowsToSeparate subarrayWithRange:NSMakeRange(indexPathBeforeHeader.row + 1, rowsToSeparate.count - indexPathBeforeHeader.row - 1)] mutableCopy];
-                reloadSection.rows = [[rowsToSeparate subarrayWithRange:NSMakeRange(0, indexPathBeforeHeader.row + 1)]  mutableCopy];
-            }
-        }
-    
-        [_sections insertObject:insertSection atIndex:insertIndex];
-        WXSectionComponent *completedInsertSection = [insertSection copy];
-        WXSectionComponent *completedReloadSection;
-        if (reloadSection) {
-            completedReloadSection = [reloadSection copy];
-        }
-        
-        [self.weexInstance.componentManager _addUITask:^{
-            WXLogDebug(@"Insert section:%ld", (unsigned long)insertIndex);
-            
-            [UIView performWithoutAnimation:^{
-                
-                @try {
-                    [_tableView beginUpdates];
-                    
-                    [_completedSections insertObject:completedInsertSection atIndex:insertIndex];
-                    if (completedReloadSection) {
-                        WXLogDebug(@"Reload section:%lu", (unsigned long)(insertIndex - 1));
-                        _completedSections[insertIndex - 1] = completedReloadSection;
-                    }
-                    
-                    [self _insertTableViewSectionAtIndex:insertIndex keepScrollPosition:keepScrollPosition animation:UITableViewRowAnimationNone];
-                    
-                    if (completedReloadSection) {
-                        [_tableView reloadSections:[NSIndexSet indexSetWithIndex:insertIndex - 1] withRowAnimation:UITableViewRowAnimationNone];
-                    }
-                    
-                    [_tableView endUpdates];
-                } @catch (NSException *exception) {
-                    WXLogError(@"list insert component occurs exception %@", exception);
-                } @finally {
-                     // nothing
-                }
-                
-            }];
-            
-        }];
-        
-    }
-}
-
-- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    //Here will not insert cell or header's view again
-    if (![subcomponent isKindOfClass:[WXCellComponent class]]
-        && ![subcomponent isKindOfClass:[WXHeaderComponent class]]) {
-        [super insertSubview:subcomponent atIndex:index];
-    }
-}
-
-#pragma mark - WXHeaderRenderDelegate
-
-- (float)headerWidthForLayout:(WXHeaderComponent *)cell
-{
-    return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
-}
-
-- (void)headerDidLayout:(WXHeaderComponent *)header
-{
-    [self.weexInstance.componentManager _addUITask:^{
-        // trigger section header update
-        [UIView performWithoutAnimation:^{
-            [_tableView beginUpdates];
-            
-            NSUInteger reloadIndex = [self indexForHeader:header sections:_completedSections];
-            [_tableView reloadSections:[NSIndexSet indexSetWithIndex:reloadIndex] withRowAnimation:UITableViewRowAnimationNone];
-            
-            [_tableView endUpdates];
-        }];
-    }];
-}
-
-- (void)headerDidRemove:(WXHeaderComponent *)header
-{
-    NSUInteger headerIndex = [self indexForHeader:header sections:_sections];
-    // this will be updated by recycler's update controller in the future
-    WXSectionComponent *headerSection = _sections[headerIndex];
-    WXSectionComponent *reloadSection;
-    NSUInteger reloadIndex = -1;
-    BOOL isDeleteSection = NO;
-    if (headerIndex == 0 && headerSection.rows.count > 0) {
-        // delete a header in the first section and the section still has cells
-        // reload the first section
-        reloadIndex = 0;
-        reloadSection = _sections[reloadIndex];
-        _sections[reloadIndex].header = nil;
-    } else if (headerIndex > 0 && headerSection.rows.count > 0) {
-        // delete a header in the middle, two sections merge into one
-        // so one section need to be deleted and the other should be relo
-        isDeleteSection = YES;
-        reloadIndex = headerIndex - 1;
-        reloadSection = _sections[reloadIndex];
-        reloadSection.rows = [[reloadSection.rows arrayByAddingObjectsFromArray:headerSection.rows] mutableCopy];
-        [_sections removeObjectAtIndex:headerIndex];
-    } else {
-        // delete a header with no cell in that section
-        // just delete the section
-        isDeleteSection = YES;
-        [_sections removeObjectAtIndex:headerIndex];
-    }
-    
-    WXSectionComponent *completedReloadSection;
-    if (reloadSection) {
-        completedReloadSection = [reloadSection copy];
-    }
-    BOOL keepScrollPosition = header.keepScrollPosition;
-    
-    [self.weexInstance.componentManager _addUITask:^{
-        if (isDeleteSection) {
-            WXLogDebug(@"delete section:%lu", (unsigned long)headerIndex);
-            [_completedSections removeObjectAtIndex:headerIndex];
-        }
-        
-        if (reloadIndex == 0 && !isDeleteSection) {
-            _completedSections[reloadIndex].header = nil;
-        }
-        
-        if (completedReloadSection) {
-            WXLogDebug(@"Reload section:%lu", (unsigned long)reloadIndex);
-            _completedSections[reloadIndex] = completedReloadSection;
-        }
-        
-        [UIView performWithoutAnimation:^{
-            [_tableView beginUpdates];
-            if (isDeleteSection) {
-                [self _deleteTableViewSectionAtIndex:headerIndex keepScrollPosition:keepScrollPosition animation:UITableViewRowAnimationNone];
-            }
-            
-            if (completedReloadSection) {
-                [_tableView reloadSections:[NSIndexSet indexSetWithIndex:reloadIndex] withRowAnimation:UITableViewRowAnimationNone];
-            }
-            
-            [_tableView endUpdates];
-        }];
-        
-    }];
-}
-
-#pragma mark - WXCellRenderDelegate
-
-- (float)containerWidthForLayout:(WXCellComponent *)cell
-{
-    return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
-}
-
-- (void)cellDidRemove:(WXCellComponent *)cell
-{
-    WXAssertComponentThread();
-    
-    NSIndexPath *indexPath = [self indexPathForCell:cell sections:_sections];
-    [self removeCellForIndexPath:indexPath withSections:_sections];
-    
-    [self.weexInstance.componentManager _addUITask:^{
-        [self removeCellForIndexPath:indexPath withSections:_completedSections];
-        
-        WXLogDebug(@"Delete cell:%@ at indexPath:%@", cell.ref, indexPath);
-        if (cell.deleteAnimation == UITableViewRowAnimationNone) {
-            [UIView performWithoutAnimation:^{
-                [self _deleteTableViewCellAtIndexPath:indexPath keepScrollPosition:cell.keepScrollPosition animation:UITableViewRowAnimationNone];
-            }];
-        } else {
-            [self _deleteTableViewCellAtIndexPath:indexPath keepScrollPosition:cell.keepScrollPosition animation:cell.deleteAnimation];
-        }
-    }];
-}
-
-- (void)cellDidLayout:(WXCellComponent *)cell
-{
-    WXAssertComponentThread() ;
-    
-    NSUInteger index = [self.subcomponents indexOfObject:cell];
-    NSIndexPath *indexPath = [self indexPathForSubIndex:index];
-
-    NSInteger sectionNum = indexPath.section;
-    if (sectionNum >= [_sections count] || sectionNum < 0) {
-        // try to protect sectionNum out of range.
-        return;
-    }
-    NSInteger row = indexPath.row;
-    NSMutableArray *sections = _sections;
-    WXSectionComponent *section = sections[sectionNum];
-    WXAssert(section, @"no section found for section number:%ld", sectionNum);
-    NSMutableArray *completedSections;
-    BOOL isReload = [section.rows containsObject:cell];
-    if (!isReload && row > [section.rows count]) {
-        // protect crash when row out of bounds
-        return ;
-    }
-    if (!isReload) {
-        [section.rows insertObject:cell atIndex:row];
-        // deep copy
-        completedSections = [[NSMutableArray alloc] initWithArray:sections copyItems:YES];;
-    }
-    
-    [self.weexInstance.componentManager _addUITask:^{
-        if (!isReload) {
-            WXLogDebug(@"Insert cell:%@ at indexPath:%@", cell.ref, indexPath);
-            _completedSections = completedSections;
-            if (cell.insertAnimation == UITableViewRowAnimationNone) {
-                [UIView performWithoutAnimation:^{
-                    [self _insertTableViewCellAtIndexPath:indexPath keepScrollPosition:cell.keepScrollPosition animation:UITableViewRowAnimationNone];
-                }];
-            } else {
-                [self _insertTableViewCellAtIndexPath:indexPath keepScrollPosition:cell.keepScrollPosition animation:cell.insertAnimation];
-            }
-        } else {
-            WXLogInfo(@"Reload cell:%@ at indexPath:%@", cell.ref, indexPath);
-            [UIView performWithoutAnimation:^{
-                [_tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
-                [self handleAppear];
-            }];
-        }
-    }];
-}
-
-- (void)cellDidRendered:(WXCellComponent *)cell
-{
-    WXAssertMainThread();
-    
-    if (WX_MONITOR_INSTANCE_PERF_IS_RECORDED(WXPTFirstScreenRender, self.weexInstance) && !self.weexInstance.onRenderProgress) {
-        // improve performance
-        return;
-    }
-    
-    NSIndexPath *indexPath = [self indexPathForCell:cell sections:_completedSections];
-    if (!indexPath || indexPath.section >= [_tableView numberOfSections] ||
-        indexPath.row < 0 || indexPath.row >= [_tableView numberOfRowsInSection:indexPath.section]) {
-        WXLogWarning(@"Rendered cell:%@ out of range, sections:%@", cell, _completedSections);
-        return;
-    }
-    
-    CGRect cellRect = [_tableView rectForRowAtIndexPath:indexPath];
-    if (cellRect.origin.y + cellRect.size.height >= _tableView.frame.size.height) {
-        WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, self.weexInstance);
-    }
-    
-    if (self.weexInstance.onRenderProgress) {
-        CGRect renderRect = [_tableView convertRect:cellRect toView:self.weexInstance.rootView];
-        self.weexInstance.onRenderProgress(renderRect);
-    }
-}
-
-- (void)cell:(WXCellComponent *)cell didMoveToIndex:(NSUInteger)index
-{
-    WXAssertComponentThread();
-    
-    NSIndexPath *fromIndexPath = [self indexPathForCell:cell sections:_sections];
-    NSIndexPath *toIndexPath = [self indexPathForSubIndex:index];
-    if (toIndexPath.row > [_sections[toIndexPath.section].rows count] || toIndexPath.row < 0) {
-        WXLogError(@"toIndexPath %@ is out of range as the current is %lu",toIndexPath ,(unsigned long)[_sections[toIndexPath.section].rows count]);
-        return;
-    }
-    [self removeCellForIndexPath:fromIndexPath withSections:_sections];
-    [self insertCell:cell forIndexPath:toIndexPath withSections:_sections];
-    
-    [self.weexInstance.componentManager _addUITask:^{
-        if (_reloadInterval > 0) {
-            // use [UITableView reloadData] to do batch updates, will move to recycler's update controller
-            __weak typeof(self) weakSelf = self;
-            if (!_updates) {
-                _updates = [NSMutableArray array];
-            }
-            [_updates addObject:^{
-                __strong typeof(weakSelf) strongSelf = weakSelf;
-                [strongSelf removeCellForIndexPath:fromIndexPath withSections:strongSelf->_completedSections];
-                [strongSelf insertCell:cell forIndexPath:toIndexPath withSections:strongSelf->_completedSections];
-            }];
-            
-            [self checkReloadData];
-        } else {
-            [self removeCellForIndexPath:fromIndexPath withSections:_completedSections];
-            [self insertCell:cell forIndexPath:toIndexPath withSections:_completedSections];
-            [UIView performWithoutAnimation:^{
-                @try {
-                    [_tableView beginUpdates];
-                    [_tableView moveRowAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
-                    [self handleAppear];
-                    [_tableView endUpdates];
-                }@catch(NSException * exception){
-                    WXLogDebug(@"move cell exception: %@", [exception description]);
-                }@finally {
-                    // do nothing
-                }
-            }];
-        }
-    }];
-}
-
-- (void)checkReloadData
-{
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_reloadInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-        if (_isUpdating || _updates.count == 0) {
-            return ;
-        }
-        
-        _isUpdating = YES;
-        NSArray *updates = [_updates copy];
-        [_updates removeAllObjects];
-        for (void(^update)(void) in updates) {
-            update();
-        }
-        [_tableView reloadData];
-        _isUpdating = NO;
-        
-        [self checkReloadData];
-    });
-}
-
-- (void)addStickyComponent:(WXComponent *)sticky
-{
-    
-}
-
-- (void)removeStickyComponent:(WXComponent *)sticky
-{
-
-}
-#pragma mark - TableView delegate
-
-- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
-{
-    
-}
-
-- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
-{
-    WXLogDebug(@"Did end displaying cell:%@, at index path:%@", cell, indexPath);
-    NSArray *visibleIndexPaths = [tableView indexPathsForVisibleRows];
-    if (![visibleIndexPaths containsObject:indexPath]) {
-        if (cell.contentView.subviews.count > 0) {
-            UIView *wxCellView = [cell.contentView.subviews firstObject];
-            // Must invoke synchronously otherwise it will remove the view just added.
-            WXCellComponent *cellComponent = (WXCellComponent *)wxCellView.wx_component;
-            if (cellComponent.isRecycle) {
-                [wxCellView.wx_component _unloadViewWithReusing:YES];
-            }
-        }
-    }
-}
-
-- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
-{
-    WXCellComponent *cell = [self cellForIndexPath:indexPath];
-    return cell.calculatedFrame.size.height;
-}
-
-- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
-{
-    WXHeaderComponent *header = ((WXSectionComponent *)[_completedSections wx_safeObjectAtIndex:section]).header;
-    if (header) {
-        return header.calculatedFrame.size.height;
-    } else {
-        return 0.0;
-    }
-}
-
-- (void)scrollViewDidScroll:(UIScrollView *)scrollView
-{
-    [super scrollViewDidScroll:scrollView];
-    if ([[_tableView indexPathsForVisibleRows] count] > 0) {
-        NSIndexPath *topCellPath = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
-        if (self.currentTopVisibleSection != topCellPath.section) {
-            if (self.currentTopVisibleSection) {
-                WXSectionComponent *removeSection = [_sections wx_safeObjectAtIndex:self.currentTopVisibleSection];
-                if (removeSection.header && [removeSection.header.events containsObject:@"unsticky"]) {
-                    [removeSection.header fireEvent:@"unsticky" params:nil];
-                }
-            }
-            self.currentTopVisibleSection = topCellPath.section;
-            WXSectionComponent *showSection = [_sections wx_safeObjectAtIndex:topCellPath.section];
-            if (showSection.header && [showSection.header.events containsObject:@"sticky"]) {
-                [showSection.header fireEvent:@"sticky" params:nil];
-            }
-        }
-    }
-}
-
-- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
-{
-    WXHeaderComponent *header = ((WXSectionComponent *)_completedSections[section]).header;
-    WXLogDebug(@"header view for section %ld:%@", (long)section, header.view);
-    return header.view;
-}
-
-#pragma mark - TableView Data Source
-
-- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
-{
-    return _completedSections.count;
-}
-
-- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-{
-    return ((WXSectionComponent *)[_completedSections wx_safeObjectAtIndex:section]).rows.count;
-}
-
-- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-{
-    WXLogDebug(@"Getting cell at indexPath:%@", indexPath);
-    static NSString *reuseIdentifier = @"WXTableViewCell";
-    
-    UITableViewCell *cellView = [_tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
-    if (!cellView) {
-        cellView = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
-        cellView.backgroundColor = [UIColor clearColor];
-    }
-    
-    WXCellComponent *cell = [self cellForIndexPath:indexPath];
-    
-    if (cell.zIndex) {
-        cellView.layer.zPosition = [WXConvert CGFloat:cell.zIndex];
-    }
-    
-    if (!cell) {
-        return cellView;
-    }
-    
-    if (cell.view.superview == cellView.contentView) {
-        return cellView;
-    }
-    
-    for (UIView *view in cellView.contentView.subviews) {
-        [view removeFromSuperview];
-    }
-    
-    [cellView.contentView addSubview:cell.view];
-    
-    [cellView setAccessibilityIdentifier:cell.view.accessibilityIdentifier];
-    
-    WXLogDebug(@"Created cell:%@ view:%@ cellView:%@ at indexPath:%@", cell.ref, cell.view, cellView, indexPath);
-    return cellView;
-}
-
-#pragma mark - Load More Event
-
-- (void)setLoadmoreretry:(NSUInteger)loadmoreretry
-{
-    if (loadmoreretry != self.loadmoreretry) {
-        _previousLoadMoreRowNumber = 0;
-    }
-    
-    [super setLoadmoreretry:loadmoreretry];
-}
-
-- (void)loadMore
-{
-    [super loadMore];
-    
-    _previousLoadMoreRowNumber = [self totalNumberOfRows];
-}
-
-- (BOOL)isNeedLoadMore
-{
-    BOOL superNeedLoadMore = [super isNeedLoadMore];
-    return superNeedLoadMore && _previousLoadMoreRowNumber != [self totalNumberOfRows];
-}
-
-- (NSUInteger)totalNumberOfRows
-{
-    NSUInteger rowNumber = 0;
-    NSUInteger sectionCount = [_tableView numberOfSections];
-    for (int section = 0; section < sectionCount; section ++) {
-        rowNumber += [_tableView numberOfRowsInSection:section];
-    }
-    
-    return rowNumber;
-}
-
-- (void)resetLoadmore{
-    [super resetLoadmore];
-    _previousLoadMoreRowNumber=0;
-}
-
-#pragma mark Private
-
-- (WXCellComponent *)cellForIndexPath:(NSIndexPath *)indexPath
-{
-    WXSectionComponent *section = [_completedSections wx_safeObjectAtIndex:indexPath.section];
-    if (!section) {
-        WXLogError(@"No section found for num:%ld, completed sections:%ld", (long)indexPath.section, (unsigned long)_completedSections.count);
-        return nil;
-    }
-    
-    WXCellComponent *cell = [section.rows wx_safeObjectAtIndex:indexPath.row];
-    if (!cell) {
-        WXLogError(@"No cell found for num:%ld, completed rows:%ld", (long)indexPath.row, (unsigned long)section.rows.count);
-        return nil;
-    }
-    
-    return cell;
-}
-
-- (void)insertCell:(WXCellComponent *)cell forIndexPath:(NSIndexPath *)indexPath withSections:(NSMutableArray *)sections
-{
-    WXSectionComponent *section = [sections wx_safeObjectAtIndex:indexPath.section];
-    if (indexPath.row > [section.rows count] || indexPath.row < 0) {
-        WXLogError(@"inserting cell at indexPath:%@ outof range, sections:%@", indexPath, sections);
-        return;
-    }
-    WXAssert(section, @"inserting cell at indexPath:%@ section has not been inserted to list before, sections:%@", indexPath, sections);
-    WXAssert(indexPath.row <= section.rows.count, @"inserting cell at indexPath:%@ outof range, sections:%@", indexPath, sections);
-    [section.rows insertObject:cell atIndex:indexPath.row];
-}
-
-- (void)removeCellForIndexPath:(NSIndexPath *)indexPath withSections:(NSMutableArray *)sections
-{
-    WXSectionComponent *section = [sections wx_safeObjectAtIndex:indexPath.section];
-    if (0 == [section.rows count]) {
-        return;
-    }
-    WXAssert(section, @"Removing cell at indexPath:%@ has not been inserted to cell list before, sections:%@", indexPath, sections);
-    WXAssert(indexPath.row < section.rows.count, @"Removing cell at indexPath:%@ outof range, sections:%@", indexPath, sections);
-    [section.rows removeObjectAtIndex:indexPath.row];
-}
-
-- (NSIndexPath *)indexPathForCell:(WXCellComponent *)cell sections:(NSMutableArray<WXSectionComponent *> *)sections
-{
-    __block NSIndexPath *indexPath;
-    [sections enumerateObjectsUsingBlock:^(WXSectionComponent * _Nonnull section, NSUInteger sectionIndex, BOOL * _Nonnull sectionStop) {
-        [section.rows enumerateObjectsUsingBlock:^(WXCellComponent * _Nonnull row, NSUInteger rowIndex, BOOL * _Nonnull stop) {
-            if (row == cell) {
-                indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
-                *stop = YES;
-                *sectionStop = YES;
-            }
-        }];
-    }];
-    
-    return indexPath;
-}
-
-- (NSUInteger)indexForHeader:(WXHeaderComponent *)header sections:(NSMutableArray<WXSectionComponent *> *)sections
-{
-    __block NSUInteger index;
-    [sections enumerateObjectsUsingBlock:^(WXSectionComponent * _Nonnull section, NSUInteger sectionIndex, BOOL * _Nonnull stop) {
-        if (section.header == header) {
-            index = sectionIndex;
-            *stop = YES;
-        }
-    }];
-    
-    return index;
-}
-
-- (NSIndexPath *)indexPathForSubIndex:(NSUInteger)index
-{
-    NSInteger section = 0;
-    NSInteger row = -1;
-    WXComponent *firstComponent;
-    for (int i = 0; i <= index; i++) {
-        WXComponent* component = [self.subcomponents wx_safeObjectAtIndex:i];
-        if (!component) {
-            continue;
-        }
-        if (([component isKindOfClass:[WXHeaderComponent class]]
-            || [component isKindOfClass:[WXCellComponent class]])
-            && !firstComponent) {
-            firstComponent = component;
-        }
-        
-        if (component != firstComponent && [component isKindOfClass:[WXHeaderComponent class]]) {
-            section ++;
-            row = -1;
-        }
-        
-        if ([component isKindOfClass:[WXCellComponent class]]) {
-            row ++;
-        }
-    }
-
-    return [NSIndexPath indexPathForRow:row inSection:section];
-}
-
-- (void)_performUpdates:(void(^)(void))updates withKeepScrollPosition:(BOOL)keepScrollPosition adjustmentBlock:(CGFloat(^)(NSIndexPath *topVisibleCell))adjustmentBlock
-{
-    CGFloat adjustment = 0;
-    
-    // keep the scroll position when inserting or deleting sections/rows by adjusting the content offset
-    if (keepScrollPosition) {
-        NSIndexPath *top = _tableView.indexPathsForVisibleRows.firstObject;
-        adjustment = adjustmentBlock(top);
-    }
-    
-    updates();
-    
-    if (keepScrollPosition) {
-        CGPoint afterContentOffset = _tableView.contentOffset;
-        CGPoint newContentOffset = CGPointMake(afterContentOffset.x, afterContentOffset.y + adjustment);
-        _tableView.contentOffset = newContentOffset;
-    }
-    
-    [self handleAppear];
-}
-
-- (void)_insertTableViewSectionAtIndex:(NSUInteger)section keepScrollPosition:(BOOL)keepScrollPosition animation:(UITableViewRowAnimation)animation
-{
-    [self _performUpdates:^{
-        [_tableView insertSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:animation];
-    } withKeepScrollPosition:keepScrollPosition adjustmentBlock:^CGFloat(NSIndexPath *top) {
-        if (section <= top.section) {
-            return [self tableView:_tableView heightForHeaderInSection:section];
-        } else {
-            return 0.0;
-        }
-    }];
-}
-
-- (void)_deleteTableViewSectionAtIndex:(NSUInteger)section keepScrollPosition:(BOOL)keepScrollPosition animation:(UITableViewRowAnimation)animation
-{
-    [self _performUpdates:^{
-        [_tableView deleteSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:animation];
-    } withKeepScrollPosition:keepScrollPosition adjustmentBlock:^CGFloat(NSIndexPath *top) {
-        if (section <= top.section) {
-            return [self tableView:_tableView heightForHeaderInSection:section];
-        } else {
-            return 0.0;
-        }
-    }];
-}
-
-- (void)_insertTableViewCellAtIndexPath:(NSIndexPath *)indexPath keepScrollPosition:(BOOL)keepScrollPosition animation:(UITableViewRowAnimation)animation
-{
-    [self _performUpdates:^{
-        if ([_updataType  isEqual: @"reload"]) {
-            [_tableView reloadData];
-        } else {
-            [_tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:animation];
-        }
-    } withKeepScrollPosition:keepScrollPosition adjustmentBlock:^CGFloat(NSIndexPath *top) {
-        if (([indexPath compare:top] <= 0) || [_updataType  isEqual: @"reload"]) {
-            return [self tableView:_tableView heightForRowAtIndexPath:indexPath];
-        } else {
-            return 0.0;
-        }
-    }];
-}
-
-- (void)_deleteTableViewCellAtIndexPath:(NSIndexPath *)indexPath keepScrollPosition:(BOOL)keepScrollPosition animation:(UITableViewRowAnimation)animation
-{
-    if (!indexPath) {
-        return ;
-    }
-    [self _performUpdates:^{
-        [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:animation];
-    } withKeepScrollPosition:keepScrollPosition adjustmentBlock:^CGFloat(NSIndexPath *top) {
-        if ([indexPath compare:top] <= 0) {
-            return [self tableView:_tableView heightForRowAtIndexPath:indexPath];
-        } else {
-            return 0.0;
-        }
-    }];
-}
-
-- (void)fixFlicker
-{
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        // FIXME:(ง •̀_•́)ง┻━┻ Stupid scoll view, always reset content offset to zero by calling _adjustContentOffsetIfNecessary after insert cells.
-        // So if you pull down list while list is rendering, the list will be flickering.
-        // Demo:    
-        // Have to hook _adjustContentOffsetIfNecessary here.
-        // Any other more elegant way?
-        NSString *a = @"ntOffsetIfNe";
-        NSString *b = @"adjustConte";
-        
-        NSString *originSelector = [NSString stringWithFormat:@"_%@%@cessary", b, a];
-        [[self class] weex_swizzle:[WXTableView class] Method:NSSelectorFromString(originSelector) withMethod:@selector(fixedFlickerSelector)];
-    });
-}
-
-- (void)fixedFlickerSelector
-{
-    // DO NOT delete this method.
-}
-
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXListComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.mm
new file mode 100644
index 0000000..bd4eb64
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.mm
@@ -0,0 +1,997 @@
+/*
+ * 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 "WXListComponent.h"
+#import "WXCellComponent.h"
+#import "WXHeaderComponent.h"
+#import "WXComponent.h"
+#import "WXComponent_internal.h"
+#import "NSArray+Weex.h"
+#import "WXAssert.h"
+#import "WXMonitor.h"
+#import "WXUtility.h"
+#import "NSObject+WXSwizzle.h"
+#import "WXSDKInstance_private.h"
+#import "WXRefreshComponent.h"
+#import "WXLoadingComponent.h"
+#import "WXScrollerComponent+Layout.h"
+
+@interface WXTableView : UITableView
+
+@end
+
+@implementation WXTableView
+
++ (BOOL)requiresConstraintBasedLayout
+{
+    return NO;
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
+{
+    if ([(id <WXScrollerProtocol>) self.wx_component respondsToSelector:@selector(requestGestureShouldStopPropagation:shouldReceiveTouch:)]) {
+        return [(id <WXScrollerProtocol>) self.wx_component requestGestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
+    }
+    else{
+        return YES;
+    }
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    [self.wx_component layoutDidFinish];
+}
+
+- (void)setContentOffset:(CGPoint)contentOffset
+{
+    // FIXME: side effect caused by hooking _adjustContentOffsetIfNecessary.
+    // When UITableView is pulled down and finger releases,contentOffset will be set from -xxxx to about -0.5(greater than -0.5), then contentOffset will be reset to zero by calling _adjustContentOffsetIfNecessary.
+    // So hooking _adjustContentOffsetIfNecessary will always cause remaining 1px space between list's top and navigator.
+    // Demo: http://dotwe.org/895630945793a9a044e49abe39cbb77f
+    // Have to reset contentOffset to zero manually here.
+    if (fabs(contentOffset.y) < 0.5) {
+        contentOffset.y = 0;
+    }
+    if (isnan(contentOffset.x)) {
+        contentOffset.x = 0;
+    }
+    if(isnan(contentOffset.y)) {
+        contentOffset.y = 0;
+    }
+    
+    [super setContentOffset:contentOffset];
+}
+
+@end
+
+// WXText is a non-public is not permitted
+@interface WXSectionComponent : NSObject<NSCopying>
+
+@property (nonatomic, strong) WXHeaderComponent *header;
+@property (nonatomic, strong) NSMutableArray<WXCellComponent *> *rows;
+
+@end
+
+@implementation WXSectionComponent
+
+- (instancetype)init
+{
+    if (self = [super init]) {
+        _rows = [NSMutableArray array];
+    }
+    
+    return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    WXSectionComponent *newSection = [[[self class] allocWithZone:zone] init];
+    newSection.header = _header;
+    newSection.rows = [_rows mutableCopyWithZone:zone];
+    
+    return newSection;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@\n%@", [_header description], [_rows description]];
+}
+@end
+
+@interface WXListComponent () <UITableViewDataSource, UITableViewDelegate, WXCellRenderDelegate, WXHeaderRenderDelegate>
+
+@property (nonatomic, assign) NSUInteger currentTopVisibleSection;
+
+@end
+
+@implementation WXListComponent
+{
+    __weak UITableView * _tableView;
+
+    // Only accessed on component thread
+    NSMutableArray<WXSectionComponent *> *_sections;
+    // Only accessed on main thread
+    NSMutableArray<WXSectionComponent *> *_completedSections;
+    NSUInteger _previousLoadMoreRowNumber;
+    // insert & reload & batch
+    NSString *_updataType;
+    
+    BOOL _isUpdating;
+    NSMutableArray<void(^)(void)> *_updates;
+    NSTimeInterval _reloadInterval;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        _sections = [NSMutableArray array];
+        _completedSections = [NSMutableArray array];
+        _reloadInterval = attributes[@"reloadInterval"] ? [WXConvert CGFloat:attributes[@"reloadInterval"]]/1000 : 0;
+        _updataType = [WXConvert NSString:attributes[@"updataType"]]?:@"insert";
+        [self fixFlicker];
+    }
+    
+    return self;
+}
+
+- (void)dealloc
+{
+    if (_tableView) {
+        _tableView.delegate = nil;
+        _tableView.dataSource = nil;
+    }
+}
+
+- (UIView *)loadView
+{
+    return [[WXTableView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    
+    _tableView = (UITableView *)self.view;
+    _tableView.allowsSelection = NO;
+    _tableView.allowsMultipleSelection = NO;
+    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+    _tableView.delegate = self;
+    _tableView.dataSource = self;
+    _tableView.userInteractionEnabled = YES;
+    
+    _tableView.estimatedRowHeight = 0;
+    _tableView.estimatedSectionFooterHeight = 0;
+    _tableView.estimatedSectionHeaderHeight = 0;
+}
+
+- (void)viewWillUnload
+{
+    [super viewWillUnload];
+    
+    _tableView.delegate = nil;
+    _tableView.dataSource = nil;
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    [super updateAttributes:attributes];
+    
+    if (attributes[@"reloadInterval"]) {
+        _reloadInterval = [WXConvert CGFloat:attributes[@"reloadInterval"]] / 1000;
+    }
+    if (attributes[@"updataType"]) {
+        _updataType = [WXConvert NSString:attributes[@"updataType"]];
+    }
+}
+
+- (void)setContentSize:(CGSize)contentSize
+{
+    // Do Nothing
+}
+
+- (void)_handleFirstScreenTime
+{
+    // Do Nothing, firstScreenTime is set by cellDidRendered:
+}
+
+- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset animated:(BOOL)animated
+{
+    CGPoint contentOffset = _tableView.contentOffset;
+    CGFloat contentOffsetY = 0;
+    
+    WXComponent *cellComponent = component;
+    CGRect cellRect;
+    while (cellComponent) {
+        if ([cellComponent isKindOfClass:[WXCellComponent class]]) {
+            NSIndexPath *toIndexPath = [self indexPathForCell:(WXCellComponent*)cellComponent sections:_completedSections];
+            cellRect = [_tableView rectForRowAtIndexPath:toIndexPath];
+            break;
+        }
+        if ([cellComponent isKindOfClass:[WXHeaderComponent class]]) {
+            NSUInteger toIndex = [self indexForHeader:(WXHeaderComponent *)cellComponent sections:_completedSections];
+            cellRect = [_tableView rectForSection:toIndex];
+            break;
+        }
+        contentOffsetY += cellComponent.calculatedFrame.origin.y;
+        cellComponent = cellComponent.supercomponent;
+    }
+    
+    contentOffsetY += cellRect.origin.y;
+    contentOffsetY += offset * self.weexInstance.pixelScaleFactor;
+    
+    if (_tableView.contentSize.height >= _tableView.frame.size.height && contentOffsetY > _tableView.contentSize.height - _tableView.frame.size.height) {
+        contentOffset.y = _tableView.contentSize.height - _tableView.frame.size.height;
+    } else {
+        contentOffset.y = contentOffsetY;
+    }
+    
+    [_tableView setContentOffset:contentOffset animated:animated];
+}
+
+
+#pragma mark - Inheritance
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    if ([subcomponent isKindOfClass:[WXCellComponent class]]) {
+        ((WXCellComponent *)subcomponent).delegate = self;
+    } else if ([subcomponent isKindOfClass:[WXHeaderComponent class]]) {
+        ((WXHeaderComponent *)subcomponent).delegate = self;
+    } else if (![subcomponent isKindOfClass:[WXRefreshComponent class]]
+               && ![subcomponent isKindOfClass:[WXLoadingComponent class]]
+               && subcomponent->_positionType != WXPositionTypeFixed) {
+        WXLogError(@"list only support cell/header/refresh/loading/fixed-component as child.");
+        return;
+    }
+    
+    [super _insertSubcomponent:subcomponent atIndex:index];
+    
+    if (![subcomponent isKindOfClass:[WXHeaderComponent class]]
+        && ![subcomponent isKindOfClass:[WXCellComponent class]]) {
+        // Don't insert section if subcomponent is not header or cell
+        return;
+    }
+    
+    NSIndexPath *indexPath = [self indexPathForSubIndex:index];
+    
+    if ([subcomponent isKindOfClass:[WXHeaderComponent class]] || _sections.count <= indexPath.section) {
+        // conditions to insert section: insert a header or insert first cell of table view
+        // this will be updated by recycler's update controller in the future
+        WXSectionComponent *insertSection = [WXSectionComponent new];
+        BOOL keepScrollPosition = NO;
+        if ([subcomponent isKindOfClass:[WXHeaderComponent class]]) {
+            WXHeaderComponent *header = (WXHeaderComponent*)subcomponent;
+            insertSection.header = header;
+            keepScrollPosition = header.keepScrollPosition;
+        }
+        
+        NSUInteger insertIndex = indexPath.section;
+        WXSectionComponent *reloadSection;
+        if (insertIndex > 0 && insertIndex <= _sections.count
+            && [subcomponent isKindOfClass:[WXHeaderComponent class]]) {
+            // insert a header in the middle, one section may divide into two
+            // so the original section need to be reloaded
+            NSIndexPath *indexPathBeforeHeader = [self indexPathForSubIndex:index - 1];
+            if (_sections[insertIndex - 1].rows.count != 0 && indexPathBeforeHeader.row < _sections[insertIndex - 1].rows.count - 1) {
+                reloadSection = _sections[insertIndex - 1];
+                NSArray *rowsToSeparate = reloadSection.rows;
+                insertSection.rows = [[rowsToSeparate subarrayWithRange:NSMakeRange(indexPathBeforeHeader.row + 1, rowsToSeparate.count - indexPathBeforeHeader.row - 1)] mutableCopy];
+                reloadSection.rows = [[rowsToSeparate subarrayWithRange:NSMakeRange(0, indexPathBeforeHeader.row + 1)]  mutableCopy];
+            }
+        }
+    
+        [_sections insertObject:insertSection atIndex:insertIndex];
+        WXSectionComponent *completedInsertSection = [insertSection copy];
+        WXSectionComponent *completedReloadSection;
+        if (reloadSection) {
+            completedReloadSection = [reloadSection copy];
+        }
+        
+        [self.weexInstance.componentManager _addUITask:^{
+            WXLogDebug(@"Insert section:%ld", (unsigned long)insertIndex);
+            
+            [UIView performWithoutAnimation:^{
+                
+                @try {
+                    [_tableView beginUpdates];
+                    
+                    [_completedSections insertObject:completedInsertSection atIndex:insertIndex];
+                    if (completedReloadSection) {
+                        WXLogDebug(@"Reload section:%lu", (unsigned long)(insertIndex - 1));
+                        _completedSections[insertIndex - 1] = completedReloadSection;
+                    }
+                    
+                    [self _insertTableViewSectionAtIndex:insertIndex keepScrollPosition:keepScrollPosition animation:UITableViewRowAnimationNone];
+                    
+                    if (completedReloadSection) {
+                        [_tableView reloadSections:[NSIndexSet indexSetWithIndex:insertIndex - 1] withRowAnimation:UITableViewRowAnimationNone];
+                    }
+                    
+                    [_tableView endUpdates];
+                } @catch (NSException *exception) {
+                    WXLogError(@"list insert component occurs exception %@", exception);
+                } @finally {
+                     // nothing
+                }
+                
+            }];
+            
+        }];
+        
+    }
+}
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    //Here will not insert cell or header's view again
+    if (![subcomponent isKindOfClass:[WXCellComponent class]]
+        && ![subcomponent isKindOfClass:[WXHeaderComponent class]]) {
+        [super insertSubview:subcomponent atIndex:index];
+    }
+}
+
+#pragma mark - WXHeaderRenderDelegate
+
+- (float)headerWidthForLayout:(WXHeaderComponent *)cell
+{
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex]){
+        return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+    }
+//#else
+    else
+    {
+        return self.flexScrollerCSSNode->getStyleWidth();
+    }
+//#endif
+}
+
+- (void)headerDidLayout:(WXHeaderComponent *)header
+{
+    [self.weexInstance.componentManager _addUITask:^{
+        // trigger section header update
+        [UIView performWithoutAnimation:^{
+            [_tableView beginUpdates];
+            
+            NSUInteger reloadIndex = [self indexForHeader:header sections:_completedSections];
+            [_tableView reloadSections:[NSIndexSet indexSetWithIndex:reloadIndex] withRowAnimation:UITableViewRowAnimationNone];
+            
+            [_tableView endUpdates];
+        }];
+    }];
+}
+
+- (void)headerDidRemove:(WXHeaderComponent *)header
+{
+    NSUInteger headerIndex = [self indexForHeader:header sections:_sections];
+    // this will be updated by recycler's update controller in the future
+    WXSectionComponent *headerSection = _sections[headerIndex];
+    WXSectionComponent *reloadSection;
+    NSUInteger reloadIndex = -1;
+    BOOL isDeleteSection = NO;
+    if (headerIndex == 0 && headerSection.rows.count > 0) {
+        // delete a header in the first section and the section still has cells
+        // reload the first section
+        reloadIndex = 0;
+        reloadSection = _sections[reloadIndex];
+        _sections[reloadIndex].header = nil;
+    } else if (headerIndex > 0 && headerSection.rows.count > 0) {
+        // delete a header in the middle, two sections merge into one
+        // so one section need to be deleted and the other should be relo
+        isDeleteSection = YES;
+        reloadIndex = headerIndex - 1;
+        reloadSection = _sections[reloadIndex];
+        reloadSection.rows = [[reloadSection.rows arrayByAddingObjectsFromArray:headerSection.rows] mutableCopy];
+        [_sections removeObjectAtIndex:headerIndex];
+    } else {
+        // delete a header with no cell in that section
+        // just delete the section
+        isDeleteSection = YES;
+        [_sections removeObjectAtIndex:headerIndex];
+    }
+    
+    WXSectionComponent *completedReloadSection;
+    if (reloadSection) {
+        completedReloadSection = [reloadSection copy];
+    }
+    BOOL keepScrollPosition = header.keepScrollPosition;
+    
+    [self.weexInstance.componentManager _addUITask:^{
+        if (isDeleteSection) {
+            WXLogDebug(@"delete section:%lu", (unsigned long)headerIndex);
+            [_completedSections removeObjectAtIndex:headerIndex];
+        }
+        
+        if (reloadIndex == 0 && !isDeleteSection) {
+            _completedSections[reloadIndex].header = nil;
+        }
+        
+        if (completedReloadSection) {
+            WXLogDebug(@"Reload section:%lu", (unsigned long)reloadIndex);
+            _completedSections[reloadIndex] = completedReloadSection;
+        }
+        
+        [UIView performWithoutAnimation:^{
+            [_tableView beginUpdates];
+            if (isDeleteSection) {
+                [self _deleteTableViewSectionAtIndex:headerIndex keepScrollPosition:keepScrollPosition animation:UITableViewRowAnimationNone];
+            }
+            
+            if (completedReloadSection) {
+                [_tableView reloadSections:[NSIndexSet indexSetWithIndex:reloadIndex] withRowAnimation:UITableViewRowAnimationNone];
+            }
+            
+            [_tableView endUpdates];
+        }];
+        
+    }];
+}
+
+#pragma mark - WXCellRenderDelegate
+
+- (float)containerWidthForLayout:(WXCellComponent *)cell
+{
+//#ifndef USE_FLEX
+    if (![WXComponent isUseFlex]) {
+         return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+    }
+//#else
+    else{
+        return self.flexScrollerCSSNode->getStyleWidth();
+    }
+//#endif
+}
+
+- (void)cellDidRemove:(WXCellComponent *)cell
+{
+    WXAssertComponentThread();
+    
+    NSIndexPath *indexPath = [self indexPathForCell:cell sections:_sections];
+    if(!indexPath){
+        //protect when cell not exist in sections
+        return;
+    }
+    [self removeCellForIndexPath:indexPath withSections:_sections];
+    
+    [self.weexInstance.componentManager _addUITask:^{
+        [self removeCellForIndexPath:indexPath withSections:_completedSections];
+        
+        WXLogDebug(@"Delete cell:%@ at indexPath:%@", cell.ref, indexPath);
+        if (cell.deleteAnimation == UITableViewRowAnimationNone) {
+            [UIView performWithoutAnimation:^{
+                [self _deleteTableViewCellAtIndexPath:indexPath keepScrollPosition:cell.keepScrollPosition animation:UITableViewRowAnimationNone];
+            }];
+        } else {
+            [self _deleteTableViewCellAtIndexPath:indexPath keepScrollPosition:cell.keepScrollPosition animation:cell.deleteAnimation];
+        }
+    }];
+}
+
+- (void)cellDidLayout:(WXCellComponent *)cell
+{
+    WXAssertComponentThread() ;
+    
+    NSUInteger index = [self.subcomponents indexOfObject:cell];
+    NSIndexPath *indexPath = [self indexPathForSubIndex:index];
+
+    NSInteger sectionNum = indexPath.section;
+    if (sectionNum >= [_sections count] || sectionNum < 0) {
+        // try to protect sectionNum out of range.
+        return;
+    }
+    NSInteger row = indexPath.row;
+    NSMutableArray *sections = _sections;
+    WXSectionComponent *section = sections[sectionNum];
+    WXAssert(section, @"no section found for section number:%ld", sectionNum);
+    NSMutableArray *completedSections;
+    BOOL isReload = [section.rows containsObject:cell];
+    if (!isReload && row > [section.rows count]) {
+        // protect crash when row out of bounds
+        return ;
+    }
+    if (!isReload) {
+        [section.rows insertObject:cell atIndex:row];
+        // deep copy
+        completedSections = [[NSMutableArray alloc] initWithArray:sections copyItems:YES];;
+    }
+    
+    [self.weexInstance.componentManager _addUITask:^{
+        if (!isReload) {
+            WXLogDebug(@"Insert cell:%@ at indexPath:%@", cell.ref, indexPath);
+            _completedSections = completedSections;
+            if (cell.insertAnimation == UITableViewRowAnimationNone) {
+                [UIView performWithoutAnimation:^{
+                    [self _insertTableViewCellAtIndexPath:indexPath keepScrollPosition:cell.keepScrollPosition animation:UITableViewRowAnimationNone];
+                }];
+            } else {
+                [self _insertTableViewCellAtIndexPath:indexPath keepScrollPosition:cell.keepScrollPosition animation:cell.insertAnimation];
+            }
+        } else {
+            WXLogInfo(@"Reload cell:%@ at indexPath:%@", cell.ref, indexPath);
+            [UIView performWithoutAnimation:^{
+                [_tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
+                [self handleAppear];
+            }];
+        }
+    }];
+}
+
+- (void)cellDidRendered:(WXCellComponent *)cell
+{
+    WXAssertMainThread();
+    
+    if (WX_MONITOR_INSTANCE_PERF_IS_RECORDED(WXPTFirstScreenRender, self.weexInstance) && !self.weexInstance.onRenderProgress) {
+        // improve performance
+        return;
+    }
+    
+    NSIndexPath *indexPath = [self indexPathForCell:cell sections:_completedSections];
+    if (!indexPath || indexPath.section >= [_tableView numberOfSections] ||
+        indexPath.row < 0 || indexPath.row >= [_tableView numberOfRowsInSection:indexPath.section]) {
+        WXLogWarning(@"Rendered cell:%@ out of range, sections:%@", cell, _completedSections);
+        return;
+    }
+    
+    CGRect cellRect = [_tableView rectForRowAtIndexPath:indexPath];
+    if (cellRect.origin.y + cellRect.size.height >= _tableView.frame.size.height) {
+        WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, self.weexInstance);
+    }
+    
+    if (self.weexInstance.onRenderProgress) {
+        CGRect renderRect = [_tableView convertRect:cellRect toView:self.weexInstance.rootView];
+        self.weexInstance.onRenderProgress(renderRect);
+    }
+}
+
+- (void)cell:(WXCellComponent *)cell didMoveToIndex:(NSUInteger)index
+{
+    WXAssertComponentThread();
+    
+    NSIndexPath *fromIndexPath = [self indexPathForCell:cell sections:_sections];
+    NSIndexPath *toIndexPath = [self indexPathForSubIndex:index];
+    if (toIndexPath.row > [_sections[toIndexPath.section].rows count] || toIndexPath.row < 0) {
+        WXLogError(@"toIndexPath %@ is out of range as the current is %lu",toIndexPath ,(unsigned long)[_sections[toIndexPath.section].rows count]);
+        return;
+    }
+    [self removeCellForIndexPath:fromIndexPath withSections:_sections];
+    [self insertCell:cell forIndexPath:toIndexPath withSections:_sections];
+    
+    [self.weexInstance.componentManager _addUITask:^{
+        if (_reloadInterval > 0) {
+            // use [UITableView reloadData] to do batch updates, will move to recycler's update controller
+            __weak typeof(self) weakSelf = self;
+            if (!_updates) {
+                _updates = [NSMutableArray array];
+            }
+            [_updates addObject:^{
+                __strong typeof(weakSelf) strongSelf = weakSelf;
+                [strongSelf removeCellForIndexPath:fromIndexPath withSections:strongSelf->_completedSections];
+                [strongSelf insertCell:cell forIndexPath:toIndexPath withSections:strongSelf->_completedSections];
+            }];
+            
+            [self checkReloadData];
+        } else {
+            [self removeCellForIndexPath:fromIndexPath withSections:_completedSections];
+            [self insertCell:cell forIndexPath:toIndexPath withSections:_completedSections];
+            [UIView performWithoutAnimation:^{
+                @try {
+                    [_tableView beginUpdates];
+                    [_tableView moveRowAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
+                    [self handleAppear];
+                    [_tableView endUpdates];
+                }@catch(NSException * exception){
+                    WXLogDebug(@"move cell exception: %@", [exception description]);
+                }@finally {
+                    // do nothing
+                }
+            }];
+        }
+    }];
+}
+
+- (void)checkReloadData
+{
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_reloadInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        if (_isUpdating || _updates.count == 0) {
+            return ;
+        }
+        
+        _isUpdating = YES;
+        NSArray *updates = [_updates copy];
+        [_updates removeAllObjects];
+        for (void(^update)(void) in updates) {
+            update();
+        }
+        [_tableView reloadData];
+        _isUpdating = NO;
+        
+        [self checkReloadData];
+    });
+}
+
+- (void)addStickyComponent:(WXComponent *)sticky
+{
+    
+}
+
+- (void)removeStickyComponent:(WXComponent *)sticky
+{
+
+}
+#pragma mark - TableView delegate
+
+- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    
+}
+
+- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"Did end displaying cell:%@, at index path:%@", cell, indexPath);
+    NSArray *visibleIndexPaths = [tableView indexPathsForVisibleRows];
+    if (![visibleIndexPaths containsObject:indexPath]) {
+        if (cell.contentView.subviews.count > 0) {
+            UIView *wxCellView = [cell.contentView.subviews firstObject];
+            // Must invoke synchronously otherwise it will remove the view just added.
+            WXCellComponent *cellComponent = (WXCellComponent *)wxCellView.wx_component;
+            if (cellComponent.isRecycle) {
+                [wxCellView.wx_component _unloadViewWithReusing:YES];
+            }
+        }
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXCellComponent *cell = [self cellForIndexPath:indexPath];
+    return cell.calculatedFrame.size.height;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
+{
+    WXHeaderComponent *header = ((WXSectionComponent *)[_completedSections wx_safeObjectAtIndex:section]).header;
+    if (header) {
+        return header.calculatedFrame.size.height;
+    } else {
+        return 0.0;
+    }
+}
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView
+{
+    [super scrollViewDidScroll:scrollView];
+    if ([[_tableView indexPathsForVisibleRows] count] > 0) {
+        NSIndexPath *topCellPath = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
+        if (self.currentTopVisibleSection != topCellPath.section) {
+            if (self.currentTopVisibleSection) {
+                WXSectionComponent *removeSection = [_sections wx_safeObjectAtIndex:self.currentTopVisibleSection];
+                if (removeSection.header && [removeSection.header.events containsObject:@"unsticky"]) {
+                    [removeSection.header fireEvent:@"unsticky" params:nil];
+                }
+            }
+            self.currentTopVisibleSection = topCellPath.section;
+            WXSectionComponent *showSection = [_sections wx_safeObjectAtIndex:topCellPath.section];
+            if (showSection.header && [showSection.header.events containsObject:@"sticky"]) {
+                [showSection.header fireEvent:@"sticky" params:nil];
+            }
+        }
+    }
+}
+
+- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
+{
+    WXHeaderComponent *header = ((WXSectionComponent *)_completedSections[section]).header;
+    WXLogDebug(@"header view for section %ld:%@", (long)section, header.view);
+    return header.view;
+}
+
+#pragma mark - TableView Data Source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+    return _completedSections.count;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+    return ((WXSectionComponent *)[_completedSections wx_safeObjectAtIndex:section]).rows.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"Getting cell at indexPath:%@", indexPath);
+    static NSString *reuseIdentifier = @"WXTableViewCell";
+    
+    UITableViewCell *cellView = [_tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
+    if (!cellView) {
+        cellView = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
+        cellView.backgroundColor = [UIColor clearColor];
+    }
+    
+    WXCellComponent *cell = [self cellForIndexPath:indexPath];
+    
+    if (cell.zIndex) {
+        cellView.layer.zPosition = [WXConvert CGFloat:cell.zIndex];
+    }
+    
+    if (!cell) {
+        return cellView;
+    }
+    
+    if (cell.view.superview == cellView.contentView) {
+        return cellView;
+    }
+    
+    for (UIView *view in cellView.contentView.subviews) {
+        [view removeFromSuperview];
+    }
+    
+    [cellView.contentView addSubview:cell.view];
+    
+    [cellView setAccessibilityIdentifier:cell.view.accessibilityIdentifier];
+    
+    WXLogDebug(@"Created cell:%@ view:%@ cellView:%@ at indexPath:%@", cell.ref, cell.view, cellView, indexPath);
+    return cellView;
+}
+
+#pragma mark - Load More Event
+
+- (void)setLoadmoreretry:(NSUInteger)loadmoreretry
+{
+    if (loadmoreretry != self.loadmoreretry) {
+        _previousLoadMoreRowNumber = 0;
+    }
+    
+    [super setLoadmoreretry:loadmoreretry];
+}
+
+- (void)loadMore
+{
+    [super loadMore];
+    
+    _previousLoadMoreRowNumber = [self totalNumberOfRows];
+}
+
+- (BOOL)isNeedLoadMore
+{
+    BOOL superNeedLoadMore = [super isNeedLoadMore];
+    return superNeedLoadMore && _previousLoadMoreRowNumber != [self totalNumberOfRows];
+}
+
+- (NSUInteger)totalNumberOfRows
+{
+    NSUInteger rowNumber = 0;
+    NSUInteger sectionCount = [_tableView numberOfSections];
+    for (int section = 0; section < sectionCount; section ++) {
+        rowNumber += [_tableView numberOfRowsInSection:section];
+    }
+    
+    return rowNumber;
+}
+
+- (void)resetLoadmore{
+    [super resetLoadmore];
+    _previousLoadMoreRowNumber=0;
+}
+
+#pragma mark Private
+
+- (WXCellComponent *)cellForIndexPath:(NSIndexPath *)indexPath
+{
+    WXSectionComponent *section = [_completedSections wx_safeObjectAtIndex:indexPath.section];
+    if (!section) {
+        WXLogError(@"No section found for num:%ld, completed sections:%ld", (long)indexPath.section, (unsigned long)_completedSections.count);
+        return nil;
+    }
+    
+    WXCellComponent *cell = [section.rows wx_safeObjectAtIndex:indexPath.row];
+    if (!cell) {
+        WXLogError(@"No cell found for num:%ld, completed rows:%ld", (long)indexPath.row, (unsigned long)section.rows.count);
+        return nil;
+    }
+    
+    return cell;
+}
+
+- (void)insertCell:(WXCellComponent *)cell forIndexPath:(NSIndexPath *)indexPath withSections:(NSMutableArray *)sections
+{
+    WXSectionComponent *section = [sections wx_safeObjectAtIndex:indexPath.section];
+    if (indexPath.row > [section.rows count] || indexPath.row < 0) {
+        WXLogError(@"inserting cell at indexPath:%@ outof range, sections:%@", indexPath, sections);
+        return;
+    }
+    WXAssert(section, @"inserting cell at indexPath:%@ section has not been inserted to list before, sections:%@", indexPath, sections);
+    WXAssert(indexPath.row <= section.rows.count, @"inserting cell at indexPath:%@ outof range, sections:%@", indexPath, sections);
+    [section.rows insertObject:cell atIndex:indexPath.row];
+}
+
+- (void)removeCellForIndexPath:(NSIndexPath *)indexPath withSections:(NSMutableArray *)sections
+{
+    WXSectionComponent *section = [sections wx_safeObjectAtIndex:indexPath.section];
+    if (0 == [section.rows count]) {
+        return;
+    }
+    WXAssert(section, @"Removing cell at indexPath:%@ has not been inserted to cell list before, sections:%@", indexPath, sections);
+    WXAssert(indexPath.row < section.rows.count, @"Removing cell at indexPath:%@ outof range, sections:%@", indexPath, sections);
+    [section.rows removeObjectAtIndex:indexPath.row];
+}
+
+- (NSIndexPath *)indexPathForCell:(WXCellComponent *)cell sections:(NSMutableArray<WXSectionComponent *> *)sections
+{
+    __block NSIndexPath *indexPath;
+    [sections enumerateObjectsUsingBlock:^(WXSectionComponent * _Nonnull section, NSUInteger sectionIndex, BOOL * _Nonnull sectionStop) {
+        [section.rows enumerateObjectsUsingBlock:^(WXCellComponent * _Nonnull row, NSUInteger rowIndex, BOOL * _Nonnull stop) {
+            if (row == cell) {
+                indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
+                *stop = YES;
+                *sectionStop = YES;
+            }
+        }];
+    }];
+    
+    return indexPath;
+}
+
+- (NSUInteger)indexForHeader:(WXHeaderComponent *)header sections:(NSMutableArray<WXSectionComponent *> *)sections
+{
+    __block NSUInteger index;
+    [sections enumerateObjectsUsingBlock:^(WXSectionComponent * _Nonnull section, NSUInteger sectionIndex, BOOL * _Nonnull stop) {
+        if (section.header == header) {
+            index = sectionIndex;
+            *stop = YES;
+        }
+    }];
+    
+    return index;
+}
+
+- (NSIndexPath *)indexPathForSubIndex:(NSUInteger)index
+{
+    NSInteger section = 0;
+    NSInteger row = -1;
+    WXComponent *firstComponent;
+    for (int i = 0; i <= index; i++) {
+        WXComponent* component = [self.subcomponents wx_safeObjectAtIndex:i];
+        if (!component) {
+            continue;
+        }
+        if (([component isKindOfClass:[WXHeaderComponent class]]
+            || [component isKindOfClass:[WXCellComponent class]])
+            && !firstComponent) {
+            firstComponent = component;
+        }
+        
+        if (component != firstComponent && [component isKindOfClass:[WXHeaderComponent class]]) {
+            section ++;
+            row = -1;
+        }
+        
+        if ([component isKindOfClass:[WXCellComponent class]]) {
+            row ++;
+        }
+    }
+
+    return [NSIndexPath indexPathForRow:row inSection:section];
+}
+
+- (void)_performUpdates:(void(^)(void))updates withKeepScrollPosition:(BOOL)keepScrollPosition adjustmentBlock:(CGFloat(^)(NSIndexPath *topVisibleCell))adjustmentBlock
+{
+    CGFloat adjustment = 0;
+    
+    // keep the scroll position when inserting or deleting sections/rows by adjusting the content offset
+    if (keepScrollPosition) {
+        NSIndexPath *top = _tableView.indexPathsForVisibleRows.firstObject;
+        adjustment = adjustmentBlock(top);
+    }
+    
+    updates();
+    
+    if (keepScrollPosition) {
+        CGPoint afterContentOffset = _tableView.contentOffset;
+        CGPoint newContentOffset = CGPointMake(afterContentOffset.x, afterContentOffset.y + adjustment);
+        _tableView.contentOffset = newContentOffset;
+    }
+    
+    [self handleAppear];
+}
+
+- (void)_insertTableViewSectionAtIndex:(NSUInteger)section keepScrollPosition:(BOOL)keepScrollPosition animation:(UITableViewRowAnimation)animation
+{
+    [self _performUpdates:^{
+        [_tableView insertSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:animation];
+    } withKeepScrollPosition:keepScrollPosition adjustmentBlock:^CGFloat(NSIndexPath *top) {
+        if (section <= top.section) {
+            return [self tableView:_tableView heightForHeaderInSection:section];
+        } else {
+            return 0.0;
+        }
+    }];
+}
+
+- (void)_deleteTableViewSectionAtIndex:(NSUInteger)section keepScrollPosition:(BOOL)keepScrollPosition animation:(UITableViewRowAnimation)animation
+{
+    [self _performUpdates:^{
+        [_tableView deleteSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:animation];
+    } withKeepScrollPosition:keepScrollPosition adjustmentBlock:^CGFloat(NSIndexPath *top) {
+        if (section <= top.section) {
+            return [self tableView:_tableView heightForHeaderInSection:section];
+        } else {
+            return 0.0;
+        }
+    }];
+}
+
+- (void)_insertTableViewCellAtIndexPath:(NSIndexPath *)indexPath keepScrollPosition:(BOOL)keepScrollPosition animation:(UITableViewRowAnimation)animation
+{
+    [self _performUpdates:^{
+        if ([_updataType  isEqual: @"reload"]) {
+            [_tableView reloadData];
+        } else {
+            [_tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:animation];
+        }
+    } withKeepScrollPosition:keepScrollPosition adjustmentBlock:^CGFloat(NSIndexPath *top) {
+        if (([indexPath compare:top] <= 0) || [_updataType  isEqual: @"reload"]) {
+            return [self tableView:_tableView heightForRowAtIndexPath:indexPath];
+        } else {
+            return 0.0;
+        }
+    }];
+}
+
+- (void)_deleteTableViewCellAtIndexPath:(NSIndexPath *)indexPath keepScrollPosition:(BOOL)keepScrollPosition animation:(UITableViewRowAnimation)animation
+{
+    if (!indexPath) {
+        return ;
+    }
+    [self _performUpdates:^{
+        [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:animation];
+    } withKeepScrollPosition:keepScrollPosition adjustmentBlock:^CGFloat(NSIndexPath *top) {
+        if ([indexPath compare:top] <= 0) {
+            return [self tableView:_tableView heightForRowAtIndexPath:indexPath];
+        } else {
+            return 0.0;
+        }
+    }];
+}
+
+- (void)fixFlicker
+{
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        // FIXME:(ง •̀_•́)ง┻━┻ Stupid scoll view, always reset content offset to zero by calling _adjustContentOffsetIfNecessary after insert cells.
+        // So if you pull down list while list is rendering, the list will be flickering.
+        // Demo:    
+        // Have to hook _adjustContentOffsetIfNecessary here.
+        // Any other more elegant way?
+        NSString *a = @"ntOffsetIfNe";
+        NSString *b = @"adjustConte";
+        
+        NSString *originSelector = [NSString stringWithFormat:@"_%@%@cessary", b, a];
+        [[self class] weex_swizzle:[WXTableView class] Method:NSSelectorFromString(originSelector) withMethod:@selector(fixedFlickerSelector)];
+    });
+}
+
+- (void)fixedFlickerSelector
+{
+    // DO NOT delete this method.
+}
+
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
deleted file mode 100644
index d57fa9a..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
+++ /dev/null
@@ -1,152 +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 "WXLoadingComponent.h"
-#import "WXScrollerComponent.h"
-#import "WXLoadingIndicator.h"
-#import "WXComponent_internal.h"
-#import "WXLog.h"
-
-@interface WXLoadingComponent()
-
-@property (nonatomic) BOOL initFinished;
-@property (nonatomic) BOOL loadingEvent;
-@property (nonatomic) BOOL displayState;
-
-@property (nonatomic, weak) WXLoadingIndicator *indicator;
-
-@end
-
-@implementation WXLoadingComponent
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    if (self) {
-        if (attributes[@"display"]) {
-            if ([attributes[@"display"] isEqualToString:@"show"]) {
-                _displayState = YES;
-            } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
-                _displayState = NO;
-            } else {
-                WXLogError(@"");
-            }
-        }
-        self.cssNode->style.position_type = CSS_POSITION_ABSOLUTE;
-    }
-    return self;
-}
-
-- (void)viewWillUnload
-{
-    _displayState = NO;
-    _loadingEvent = NO;
-    _initFinished = NO;
-}
-
--(void)updateAttributes:(NSDictionary *)attributes
-{
-    if (attributes[@"display"]) {
-        if ([attributes[@"display"] isEqualToString:@"show"]) {
-            _displayState = YES;
-        } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
-            _displayState = NO;
-        } else {
-            WXLogError(@"");
-        }
-        [self setDisplay];
-    }
-}
-
-- (void)viewDidLoad
-{
-    _initFinished = YES;
-    
-    if (!_displayState) {
-        [_indicator.view setHidden:YES];
-    }
-}
-
-- (void)addEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"loading"]) {
-        _loadingEvent = YES;
-    }
-}
-
-- (void)removeEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"loading"]) {
-        _loadingEvent = NO;
-    }
-}
-
-- (void)loading
-{
-    if (!_loadingEvent || _displayState)
-        return;
-    
-    [self fireEvent:@"loading" params:nil];
-}
-
-- (void)setDisplay
-{
-    id<WXScrollerProtocol> scrollerProtocol = [self ancestorScroller];
-    if (scrollerProtocol == nil || !_initFinished)
-        return;
-    WXComponent *scroller = (WXComponent*)scrollerProtocol;
-    CGPoint contentOffset = [scrollerProtocol contentOffset];
-    if (_displayState) {
-        contentOffset.y = [scrollerProtocol contentSize].height - scroller.calculatedFrame.size.height + self.calculatedFrame.size.height;
-        [_indicator start];
-    } else {
-        contentOffset.y = contentOffset.y - self.calculatedFrame.size.height;
-        [_indicator stop];
-    }
-    [scrollerProtocol setContentOffset:contentOffset animated:YES];
-}
-
-- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    if (subcomponent) {
-        [super _insertSubcomponent:subcomponent atIndex:index];
-        if ([subcomponent isKindOfClass:[WXLoadingIndicator class]]) {
-            _indicator = (WXLoadingIndicator*)subcomponent;
-        }
-    }
-}
-
-- (BOOL)displayState
-{
-    return _displayState;
-}
-
-- (void)resizeFrame
-{
-    CGRect rect = self.calculatedFrame;
-    
-    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
-    if (scrollerProtocol) {
-        rect.origin.y = [scrollerProtocol contentSize].height;
-    }
-    
-    [self.view setFrame:rect];
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.mm
new file mode 100644
index 0000000..bb5024f
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.mm
@@ -0,0 +1,164 @@
+/*
+ * 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 "WXLoadingComponent.h"
+#import "WXScrollerComponent.h"
+#import "WXLoadingIndicator.h"
+#import "WXComponent_internal.h"
+#import "WXLog.h"
+#import "WXComponent+Layout.h"
+
+@interface WXLoadingComponent()
+
+@property (nonatomic) BOOL initFinished;
+@property (nonatomic) BOOL loadingEvent;
+@property (nonatomic) BOOL displayState;
+
+@property (nonatomic, weak) WXLoadingIndicator *indicator;
+
+@end
+
+@implementation WXLoadingComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        if (attributes[@"display"]) {
+            if ([attributes[@"display"] isEqualToString:@"show"]) {
+                _displayState = YES;
+            } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
+                _displayState = NO;
+            } else {
+                WXLogError(@"");
+            }
+        }
+//#ifndef USE_FLEX
+        if(![WXComponent isUseFlex])
+        {
+             self.cssNode->style.position_type = CSS_POSITION_ABSOLUTE;
+        }
+//#else
+        else
+        {
+             self.flexCssNode->setStylePositionType(WeexCore::kAbsolute);
+        }
+       
+//#endif
+    }
+    return self;
+}
+
+- (void)viewWillUnload
+{
+    _displayState = NO;
+    _loadingEvent = NO;
+    _initFinished = NO;
+}
+
+-(void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"display"]) {
+        if ([attributes[@"display"] isEqualToString:@"show"]) {
+            _displayState = YES;
+        } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
+            _displayState = NO;
+        } else {
+            WXLogError(@"");
+        }
+        [self setDisplay];
+    }
+}
+
+- (void)viewDidLoad
+{
+    _initFinished = YES;
+    
+    if (!_displayState) {
+        [_indicator.view setHidden:YES];
+    }
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"loading"]) {
+        _loadingEvent = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"loading"]) {
+        _loadingEvent = NO;
+    }
+}
+
+- (void)loading
+{
+    if (!_loadingEvent || _displayState)
+        return;
+    
+    [self fireEvent:@"loading" params:nil];
+}
+
+- (void)setDisplay
+{
+    id<WXScrollerProtocol> scrollerProtocol = [self ancestorScroller];
+    if (scrollerProtocol == nil || !_initFinished)
+        return;
+    WXComponent *scroller = (WXComponent*)scrollerProtocol;
+    CGPoint contentOffset = [scrollerProtocol contentOffset];
+    if (_displayState) {
+        contentOffset.y = [scrollerProtocol contentSize].height - scroller.calculatedFrame.size.height + self.calculatedFrame.size.height;
+        [_indicator start];
+    } else {
+        contentOffset.y = contentOffset.y - self.calculatedFrame.size.height;
+        [_indicator stop];
+    }
+    [scrollerProtocol setContentOffset:contentOffset animated:YES];
+}
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    if (subcomponent) {
+        [super _insertSubcomponent:subcomponent atIndex:index];
+        if ([subcomponent isKindOfClass:[WXLoadingIndicator class]]) {
+            _indicator = (WXLoadingIndicator*)subcomponent;
+        }
+    }
+}
+
+- (BOOL)displayState
+{
+    return _displayState;
+}
+
+- (void)resizeFrame
+{
+    CGRect rect = self.calculatedFrame;
+    
+    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
+    if (scrollerProtocol) {
+        rect.origin.y = [scrollerProtocol contentSize].height;
+    }
+    
+    [self.view setFrame:rect];
+}
+
+@end


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXTextAreaComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextAreaComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXTextAreaComponent.mm
new file mode 100644
index 0000000..bb263c8
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextAreaComponent.mm
@@ -0,0 +1,261 @@
+/*
+ * 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 "WXTextAreaComponent.h"
+#import "WXUtility.h"
+#import "WXComponent+Layout.h"
+#import "WXComponent_internal.h"
+#import "WXComponent+Layout.h"
+
+#define CorrectX 4 //textview fill text 4 pixel from left. so placeholderlabel have 4 pixel too
+#define CorrectY 8 // textview fill text 8 pixel from top
+typedef UITextView WXTextAreaView;
+
+@interface WXTextAreaComponent()
+
+@property (nonatomic, strong) WXTextAreaView *textView;
+@property (nonatomic) NSUInteger rows;
+
+@end
+
+@implementation WXTextAreaComponent {
+    UIEdgeInsets _border;
+    UIEdgeInsets _padding;
+}
+
+-(void)viewDidLoad
+{
+    _padding = UIEdgeInsetsZero;
+    _border = UIEdgeInsetsZero;
+    if (self.placeholderString) {
+        self.placeHolderLabel = [[UILabel alloc] init];
+        self.placeHolderLabel.numberOfLines = 0;
+        [_textView addSubview:self.placeHolderLabel];
+    }
+    // default placeholder hide from voice over
+    self.placeHolderLabel.isAccessibilityElement = NO;
+    _textView.isAccessibilityElement = YES;
+    _textView.delegate = self;
+    [_textView setNeedsDisplay];
+    [_textView setClipsToBounds:YES];
+    [super viewDidLoad];
+}
+
+- (void)viewWillUnload
+{
+    _textView = nil;
+}
+
+- (UIView *)loadView
+{
+    _textView = [[WXTextAreaView alloc] init];
+    return _textView;
+}
+
+#pragma mark measure frame
+- (CGSize (^)(CGSize))measureBlock
+{
+    __weak typeof(self) weakSelf = self;
+    return ^CGSize (CGSize constrainedSize) {
+        
+        CGSize computedSize = [[[NSString alloc] init]sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:weakSelf.textView.font.pointSize]}];
+        computedSize.height = _rows? computedSize.height *weakSelf.rows + (CorrectY + CorrectY/2):0;
+//#ifndef USE_FLEX
+        
+         if (![WXComponent isUseFlex])
+         {
+             if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
+                 computedSize.width = MAX(computedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
+             }
+             
+             if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
+                 computedSize.width = MIN(computedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
+             }
+             
+             if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_HEIGHT])) {
+                 computedSize.height = MAX(computedSize.height, weakSelf.cssNode->style.minDimensions[CSS_HEIGHT]);
+             }
+             
+             if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT])) {
+                 computedSize.height = MIN(computedSize.height, weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT]);
+             }
+         }
+       
+//#else
+        
+        else
+        {
+            if (!isnan(weakSelf.flexCssNode->getMinWidth())) {
+                computedSize.width = MAX(computedSize.width, weakSelf.flexCssNode->getMinWidth());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMaxWidth())) {
+                computedSize.width = MIN(computedSize.width, weakSelf.flexCssNode->getMaxWidth());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMinHeight())) {
+                computedSize.height = MAX(computedSize.height, weakSelf.flexCssNode->getMinHeight());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMaxHeight())) {
+                computedSize.height = MIN(computedSize.height, weakSelf.flexCssNode->getMaxHeight());
+            }
+        }
+        
+//#endif
+        return (CGSize) {
+            WXCeilPixelValue(computedSize.width),
+            WXCeilPixelValue(computedSize.height)
+        };
+    };
+}
+
+#pragma mark -Overwrite method
+-(NSString *)text
+{
+    return _textView.text;
+}
+
+- (void)setText:(NSString *)text
+{
+    _textView.text = text;
+    if ([text length] >0) {
+        self.placeHolderLabel.text = @"";
+    }
+}
+
+-(void)setTextColor:(UIColor *)color
+{
+    [_textView setTextColor:color];
+}
+
+-(void)setTextAlignment:(NSTextAlignment)textAlignForStyle
+{
+    [_textView setTextAlignment:textAlignForStyle];
+}
+
+-(void)setUserInteractionEnabled:(BOOL)userInteractionEnabled
+{
+    [_textView setUserInteractionEnabled:userInteractionEnabled];
+}
+
+-(void)setEnabled:(BOOL)enabled
+{
+    _textView.editable = enabled;
+    _textView.selectable = enabled;
+}
+
+-(void)setReturnKeyType:(UIReturnKeyType)returnKeyType
+{
+    [_textView setReturnKeyType:returnKeyType];
+}
+
+-(void)setInputAccessoryView:(UIView *)inputAccessoryView
+{
+    [_textView setInputAccessoryView:inputAccessoryView];
+}
+
+-(void)setEditSelectionRange:(NSInteger)selectionStart selectionEnd:(NSInteger)selectionEnd
+{
+    [self.textView becomeFirstResponder];
+    UITextPosition *startPos =  [self.textView positionFromPosition:self.textView.beginningOfDocument offset:selectionStart];
+    UITextPosition *endPos = [self.textView positionFromPosition:self.textView.beginningOfDocument offset:selectionEnd];
+    UITextRange *textRange = [self.textView textRangeFromPosition:startPos
+                                                       toPosition:endPos];
+    self.textView.selectedTextRange = textRange;
+}
+
+-(NSDictionary *)getEditSelectionRange
+{
+    NSInteger selectionStart = [self.textView offsetFromPosition:self.textView.beginningOfDocument toPosition:self.textView.selectedTextRange.start];
+    NSInteger selectionEnd = [self.textView offsetFromPosition:self.textView.beginningOfDocument toPosition:self.textView.selectedTextRange.end];
+    NSDictionary *res = @{@"selectionStart":@(selectionStart),@"selectionEnd":@(selectionEnd)};
+    return res;
+}
+
+-(void)setKeyboardType:(UIKeyboardType)keyboardType
+{
+    [_textView setKeyboardType:keyboardType];
+}
+
+-(void)setSecureTextEntry:(BOOL)secureTextEntry
+{
+    [_textView setSecureTextEntry:secureTextEntry];
+}
+
+-(void)setEditPadding:(UIEdgeInsets)padding
+{
+    _padding = padding;
+    [self _updateTextContentInset];
+}
+
+-(void)setEditBorder:(UIEdgeInsets)border
+{
+    _border = border;
+    [self _updateTextContentInset];
+}
+
+-(void)setAttributedPlaceholder:(NSMutableAttributedString *)attributedString font:(UIFont *)font
+{
+    if (self.placeholderColor) {
+        [attributedString addAttribute:NSForegroundColorAttributeName value:self.placeholderColor range:NSMakeRange(0, self.placeholderString.length)];
+        [attributedString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, self.placeholderString.length)];
+    }
+    self.placeHolderLabel.backgroundColor = [UIColor clearColor];
+    CGRect expectedLabelSize = [attributedString boundingRectWithSize:(CGSize){self.view.frame.size.width, CGFLOAT_MAX}
+                                                              options:NSStringDrawingUsesLineFragmentOrigin
+                                                              context:nil];
+    
+    self.placeHolderLabel.clipsToBounds = NO;
+    CGRect newFrame = self.placeHolderLabel.frame;
+    newFrame.size.height = ceil(expectedLabelSize.size.height);
+    newFrame.size.width = _textView.frame.size.width- CorrectX*2;
+    newFrame.origin.x = CorrectX + _padding.left + _border.left; // the cursor origin.x
+    self.placeHolderLabel.frame = newFrame;
+    self.placeHolderLabel.attributedText = attributedString;
+}
+
+-(void)setFont:(UIFont *)font
+{
+    [_textView setFont:font];
+}
+
+-(void)setRows:(NSUInteger)rows
+{
+    _rows = rows;
+    [self setNeedsLayout];
+}
+
+#pragma mark -Private Method
+- (void)_updateTextContentInset
+{
+    [_textView setTextContainerInset:UIEdgeInsetsMake(_padding.top + _border.top,
+                                                      _padding.left + _border.left,
+                                                      _padding.bottom + _border.bottom,
+                                                      _border.right + _border.right)];
+    
+    //when textview update, placeHolderLabel update too
+    CGRect newFrame = self.placeHolderLabel.frame;
+    newFrame.size.width = self.textView.frame.size.width - (_padding.left + _border.left) -CorrectX*2;
+    newFrame.origin.x = CorrectX + _padding.left + _border.left; // the cursor origin.x
+    newFrame.origin.y = _padding.top + _border.top;
+    self.placeHolderLabel.frame = newFrame;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.m
deleted file mode 100644
index 2a948e2..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.m
+++ /dev/null
@@ -1,1076 +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 "WXTextComponent.h"
-#import "WXSDKInstance_private.h"
-#import "WXComponent_internal.h"
-#import "WXLayer.h"
-#import "WXUtility.h"
-#import "WXConvert.h"
-#import "WXRuleManager.h"
-#import "WXDefine.h"
-#import "WXView.h"
-#import <pthread/pthread.h>
-#import <CoreText/CoreText.h>
-
-// WXText is a non-public is not permitted
-@interface WXTextView : WXView
-@property (nonatomic, strong) NSTextStorage *textStorage;
-@end
-
-@implementation WXTextView
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
-    if ((self = [super initWithFrame:frame])) {
-        self.accessibilityTraits |= UIAccessibilityTraitStaticText;
-        
-        self.opaque = NO;
-        self.contentMode = UIViewContentModeRedraw;
-        self.textStorage = [NSTextStorage new];
-    }
-    return self;
-}
-
-+ (Class)layerClass
-{
-    return [WXLayer class];
-}
-
-- (void)copy:(id)sender
-{
-    [[UIPasteboard generalPasteboard] setString:((WXTextComponent*)self.wx_component).text];
-}
-
-- (void)setTextStorage:(NSTextStorage *)textStorage
-{
-    if (_textStorage != textStorage) {
-        _textStorage = textStorage;
-        [self.wx_component setNeedsDisplay];
-    }
-}
-
-- (BOOL)canBecomeFirstResponder
-{
-    return YES;
-}
-
-- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
-{
-    if (action == @selector(copy:)) {
-        return [[self.wx_component valueForKey:@"_enableCopy"] boolValue];
-    }
-    return [super canPerformAction:action withSender:sender];
-}
-
-- (NSString *)description
-{
-    NSString *superDescription = super.description;
-    NSRange semicolonRange = [superDescription rangeOfString:@";"];
-    NSString * content = _textStorage.string;
-    if ([(WXTextComponent*)self.wx_component useCoreText]) {
-        content = ((WXTextComponent*)self.wx_component).text;
-    }
-    NSString *replacement = [NSString stringWithFormat:@"; text: %@; frame:%f,%f,%f,%f", content, self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height];
-    return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement];
-}
-
-- (NSString *)accessibilityValue
-{
-    if (self.wx_component && self.wx_component->_ariaLabel) {
-        return [super accessibilityValue];
-    }
-    if (![(WXTextComponent*)self.wx_component useCoreText]) {
-        return _textStorage.string;
-    }
-    return ((WXTextComponent*)self.wx_component).text;
-}
-
-- (NSString *)accessibilityLabel
-{
-    if (self.wx_component) {
-        if (self.wx_component->_ariaLabel) {
-            return self.wx_component->_ariaLabel;
-        }
-    }
-    return [super accessibilityLabel];
-}
-
-@end
-
-static BOOL textRenderUsingCoreText = YES;
-
-NSString *const WXTextTruncationToken = @"\u2026";
-CGFloat WXTextDefaultLineThroughWidth = 1.2;
-
-@interface WXTextComponent()
-@property (nonatomic, strong) NSString *useCoreTextAttr;
-@end
-
-@implementation WXTextComponent
-{
-    UIEdgeInsets _border;
-    UIEdgeInsets _padding;
-    NSTextStorage *_textStorage;
-    CGFloat _textStorageWidth;
-    
-    UIColor *_color;
-    NSString *_fontFamily;
-    CGFloat _fontSize;
-    CGFloat _fontWeight;
-    WXTextStyle _fontStyle;
-    NSUInteger _lines;
-    NSTextAlignment _textAlign;
-    NSString *_direction;
-    WXTextDecoration _textDecoration;
-    NSString *_textOverflow;
-    CGFloat _lineHeight;
-    CGFloat _letterSpacing;
-    BOOL _truncationLine; // support trunk tail
-    
-    NSAttributedString * _ctAttributedString;
-    NSString *_wordWrap;
-    
-    pthread_mutex_t _ctAttributedStringMutex;
-    pthread_mutexattr_t _propertMutexAttr;
-    BOOL _observerIconfont;
-    BOOL _enableCopy;
-}
-
-+ (void)setRenderUsingCoreText:(BOOL)usingCoreText
-{
-    textRenderUsingCoreText = usingCoreText;
-}
-
-+ (BOOL)textRenderUsingCoreText
-{
-    return textRenderUsingCoreText;
-}
-
-- (instancetype)initWithRef:(NSString *)ref
-                       type:(NSString *)type
-                     styles:(NSDictionary *)styles
-                 attributes:(NSDictionary *)attributes
-                     events:(NSArray *)events
-               weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    if (self) {
-        // just for coretext and textkit render replacement
-        pthread_mutexattr_init(&(_propertMutexAttr));
-        pthread_mutexattr_settype(&(_propertMutexAttr), PTHREAD_MUTEX_RECURSIVE);
-        pthread_mutex_init(&(_ctAttributedStringMutex), &(_propertMutexAttr));
-        
-        if ([attributes objectForKey:@"coretext"]) {
-            _useCoreTextAttr = [WXConvert NSString:attributes[@"coretext"]];
-        } else {
-            _useCoreTextAttr = nil;
-        }
-        
-        [self fillCSSStyles:styles];
-        [self fillAttributes:attributes];
-    }
-    
-    return self;
-}
-
-- (BOOL)useCoreText
-{
-    if ([_useCoreTextAttr isEqualToString:@"true"]) {
-        return YES;
-    }
-    if ([_useCoreTextAttr isEqualToString:@"false"]) {
-        return NO;
-    }
-    
-    if ([WXTextComponent textRenderUsingCoreText]) {
-        return YES;
-    }
-    return NO;
-}
-
-- (void)dealloc
-{
-    if (_fontFamily && _observerIconfont) {
-        [[NSNotificationCenter defaultCenter] removeObserver:self name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
-    }
-    pthread_mutex_destroy(&_ctAttributedStringMutex);
-    pthread_mutexattr_destroy(&_propertMutexAttr);
-}
-
-#define WX_STYLE_FILL_TEXT(key, prop, type, needLayout)\
-do {\
-    id value = styles[@#key];\
-    if (value) {\
-        _##prop = [WXConvert type:value];\
-        [self setNeedsRepaint];\
-        if (needLayout) {\
-            [self setNeedsLayout];\
-        }\
-    }\
-} while(0);
-
-#define WX_STYLE_FILL_TEXT_WITH_DEFAULT_VALUE(key, prop, type, defaultValue,needLayout)\
-do {\
-    id value = styles[@#key];\
-    if (value) {\
-        if([WXUtility isBlankString:value]){\
-            _##prop = defaultValue;\
-        }else {\
-            _##prop = [WXConvert type:value];\
-        }\
-        [self setNeedsRepaint];\
-        if (needLayout) {\
-            [self setNeedsLayout];\
-        }\
-    }\
-} while(0);
-
-
-#define WX_STYLE_FILL_TEXT_PIXEL(key, prop, needLayout)\
-do {\
-    id value = styles[@#key];\
-    if (value) {\
-        _##prop = [WXConvert WXPixelType:value scaleFactor:self.weexInstance.pixelScaleFactor];\
-        [self setNeedsRepaint];\
-    if (needLayout) {\
-        [self setNeedsLayout];\
-    }\
-}\
-} while(0);
-
-- (void)fillCSSStyles:(NSDictionary *)styles
-{
-    WX_STYLE_FILL_TEXT_WITH_DEFAULT_VALUE(color, color, UIColor, [UIColor blackColor], NO)
-    WX_STYLE_FILL_TEXT(fontFamily, fontFamily, NSString, YES)
-    WX_STYLE_FILL_TEXT_PIXEL(fontSize, fontSize, YES)
-    WX_STYLE_FILL_TEXT(fontWeight, fontWeight, WXTextWeight, YES)
-    WX_STYLE_FILL_TEXT(fontStyle, fontStyle, WXTextStyle, YES)
-    WX_STYLE_FILL_TEXT(lines, lines, NSUInteger, YES)
-    WX_STYLE_FILL_TEXT(textAlign, textAlign, NSTextAlignment, NO)
-    WX_STYLE_FILL_TEXT(textDecoration, textDecoration, WXTextDecoration, YES)
-    WX_STYLE_FILL_TEXT(textOverflow, textOverflow, NSString, NO)
-    WX_STYLE_FILL_TEXT_PIXEL(lineHeight, lineHeight, YES)
-    WX_STYLE_FILL_TEXT_PIXEL(letterSpacing, letterSpacing, YES)
-    WX_STYLE_FILL_TEXT(wordWrap, wordWrap, NSString, YES);
-    WX_STYLE_FILL_TEXT(direction, direction, NSString, YES)
-    if (_fontFamily && !_observerIconfont) {
-        // notification received when custom icon font file download finish
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(repaintText:) name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
-        _observerIconfont = YES;
-    }
-    UIEdgeInsets padding = {
-        WXFloorPixelValue(self.cssNode->style.padding[CSS_TOP] + self.cssNode->style.border[CSS_TOP]),
-        WXFloorPixelValue(self.cssNode->style.padding[CSS_LEFT] + self.cssNode->style.border[CSS_LEFT]),
-        WXFloorPixelValue(self.cssNode->style.padding[CSS_BOTTOM] + self.cssNode->style.border[CSS_BOTTOM]),
-        WXFloorPixelValue(self.cssNode->style.padding[CSS_RIGHT] + self.cssNode->style.border[CSS_RIGHT])
-    };
-    
-    if (!UIEdgeInsetsEqualToEdgeInsets(padding, _padding)) {
-        _padding = padding;
-        [self setNeedsRepaint];
-    }
-}
-
-- (void)fillAttributes:(NSDictionary *)attributes
-{
-    id text = [WXConvert NSString:attributes[@"value"]];
-    if (text && ![self.text isEqualToString:text]) {
-        self.text = text;
-        [self setNeedsRepaint];
-        [self setNeedsLayout];
-    }
-    if (attributes[@"enableCopy"]) {
-        _enableCopy = [WXConvert BOOL:attributes[@"enableCopy"]];
-    }
-}
-
-- (void)setNeedsRepaint
-{
-    _textStorage = nil;
-    
-    pthread_mutex_lock(&(_ctAttributedStringMutex));
-    _ctAttributedString = nil;
-    pthread_mutex_unlock(&(_ctAttributedStringMutex));
-    
-}
-
-#pragma mark - Subclass
-
-- (void)setNeedsLayout
-{
-    [super setNeedsLayout];
-}
-
-- (void)viewDidLoad
-{
-    [super viewDidLoad];
-    BOOL useCoreText = NO;
-    if ([self.view.wx_component isKindOfClass:NSClassFromString(@"WXTextComponent")] && [self.view.wx_component respondsToSelector:@selector(useCoreText)]) {
-        useCoreText = [(WXTextComponent*)self.view.wx_component useCoreText];
-    }
-    if (!useCoreText) {
-        ((WXTextView *)self.view).textStorage = _textStorage;
-    }
-    if (_enableCopy) {
-        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(displayMenuController:)];
-        [self.view addGestureRecognizer:longPress];
-    }
-    self.view.isAccessibilityElement = YES;
-    
-    [self setNeedsDisplay];
-}
-
-- (void)displayMenuController:(id)sender
-{
-    if ([self.view becomeFirstResponder] && ((UILongPressGestureRecognizer*)sender).state == UIGestureRecognizerStateBegan) {
-        UIMenuController *theMenu = [UIMenuController sharedMenuController];
-        CGSize size = [self ctAttributedString].size;
-        CGRect selectionRect = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, size.width, size.height);
-        [theMenu setTargetRect:selectionRect inView:self.view.superview];
-        [theMenu setMenuVisible:YES animated:YES];
-    }
-}
-
-- (UIView *)loadView
-{
-    return [[WXTextView alloc] init];
-}
-
-- (BOOL)needsDrawRect
-{
-    return YES;
-}
-
-- (UIImage *)drawRect:(CGRect)rect;
-{
-    CGContextRef context = UIGraphicsGetCurrentContext();
-    if (_isCompositingChild) {
-        [self drawTextWithContext:context bounds:rect padding:_padding view:nil];
-    } else {
-        WXTextView *textView = (WXTextView *)_view;
-        [self drawTextWithContext:context bounds:rect padding:_padding view:textView];
-    }
-    
-    return nil;
-}
-
-- (CGSize (^)(CGSize))measureBlock
-{
-    __weak typeof(self) weakSelf = self;
-    return ^CGSize (CGSize constrainedSize) {
-        CGSize computedSize = CGSizeZero;
-        NSTextStorage *textStorage = nil;
-        
-        //TODO:more elegant way to use max and min constrained size
-        if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
-            constrainedSize.width = MAX(constrainedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
-            constrainedSize.width = MIN(constrainedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
-        }
-        
-        if (![self useCoreText]) {
-            textStorage = [weakSelf textStorageWithWidth:constrainedSize.width];
-            NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
-            NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
-            computedSize = [layoutManager usedRectForTextContainer:textContainer].size;
-        } else {
-            computedSize = [weakSelf calculateTextHeightWithWidth:constrainedSize.width];
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_HEIGHT])) {
-            computedSize.height = MAX(computedSize.height, weakSelf.cssNode->style.minDimensions[CSS_HEIGHT]);
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT])) {
-            computedSize.height = MIN(computedSize.height, weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT]);
-        }
-        if (textStorage && [WXUtility isBlankString:textStorage.string]) {
-            //  if the text value is empty or nil, then set the height is 0.
-            computedSize.height = 0;
-        }
-        
-        return (CGSize) {
-            WXCeilPixelValue(computedSize.width),
-            WXCeilPixelValue(computedSize.height)
-        };
-    };
-}
-
-#pragma mark Text Building
-
-- (NSAttributedString *)ctAttributedString
-{
-    if (!self.text) {
-        return nil;
-    }
-    NSAttributedString * attributedString = nil;
-    pthread_mutex_lock(&(_ctAttributedStringMutex));
-    if (!_ctAttributedString) {
-        _ctAttributedString = [self buildCTAttributeString];
-        WXPerformBlockOnComponentThread(^{
-            [self.weexInstance.componentManager startComponentTasks];
-        });
-    }
-    attributedString = [_ctAttributedString copy];
-    pthread_mutex_unlock(&(_ctAttributedStringMutex));
-    return attributedString;
-}
-
-- (void)repaintText:(NSNotification *)notification
-{
-    if (![_fontFamily isEqualToString:notification.userInfo[@"fontFamily"]]) {
-        return;
-    }
-    [self setNeedsRepaint];
-    WXPerformBlockOnComponentThread(^{
-        [self.weexInstance.componentManager startComponentTasks];
-        WXPerformBlockOnMainThread(^{
-            [self setNeedsLayout];
-            [self setNeedsDisplay];
-        });
-    });
-}
-
-- (NSMutableAttributedString *)buildCTAttributeString
-{
-    NSString * string = self.text;
-    if (![string isKindOfClass:[NSString class]]) {
-        WXLogError(@"text %@ is invalid", self.text);
-        string = @"";
-    }
-    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString: string];
-    if (_color) {
-        [attributedString addAttribute:NSForegroundColorAttributeName value:_color range:NSMakeRange(0, string.length)];
-    }
-    
-    // set font
-    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor useCoreText:[self useCoreText]];
-    CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)font.fontName,
-                                           font.pointSize,
-                                           NULL);
-    if (ctFont) {
-        [attributedString addAttribute:(id)kCTFontAttributeName value:(__bridge id)(ctFont) range:NSMakeRange(0, string.length)];
-        CFRelease(ctFont);
-    }
-    
-    if(_textDecoration == WXTextDecorationUnderline){
-        [attributedString addAttribute:(id)kCTUnderlineStyleAttributeName value:@(kCTUnderlinePatternSolid | kCTUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
-    } else if(_textDecoration == WXTextDecorationLineThrough){
-        [attributedString addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
-    }
-    
-    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
-    
-    // handle text direction style, default ltr
-    if (_cssNode->layout.direction == CSS_DIRECTION_RTL) {
-        if (0 == _textAlign) {
-            //force text right-align if don't specified any align.
-            _textAlign = NSTextAlignmentRight;
-        }
-        paragraphStyle.baseWritingDirection = NSWritingDirectionRightToLeft;
-    } else {
-        //if you specify NSWritingDirectionNaturalDirection, the receiver resolves the writing
-        //directionto eitherNSWritingDirectionLeftToRight or NSWritingDirectionRightToLeft,
-        //depending on the direction for the user’s language preference setting.
-        paragraphStyle.baseWritingDirection =  NSWritingDirectionNatural;
-    }
-    
-    if (_textAlign) {
-        paragraphStyle.alignment = _textAlign;
-    }
-    
-    if ([[_wordWrap lowercaseString] isEqualToString:@"break-word"]) {
-        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
-    } else if ([[_wordWrap lowercaseString] isEqualToString:@"normal"]){
-        paragraphStyle.lineBreakMode = NSLineBreakByClipping;
-    } else {
-         // set default lineBreakMode
-        paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
-    }
-    _truncationLine = NO;
-    if (_textOverflow && [_textOverflow length] > 0) {
-        if (_lines && [_textOverflow isEqualToString:@"ellipsis"])
-            _truncationLine = YES;
-    }
-    
-    if (_lineHeight) {
-        paragraphStyle.maximumLineHeight = _lineHeight;
-        paragraphStyle.minimumLineHeight = _lineHeight;
-    }
-    if (_lineHeight || _textAlign || [_textOverflow length] > 0) {
-        [attributedString addAttribute:NSParagraphStyleAttributeName
-                                 value:paragraphStyle
-                                 range:(NSRange){0, attributedString.length}];
-    }
-    
-    if (_letterSpacing) {
-        [attributedString addAttribute:NSKernAttributeName value:@(_letterSpacing) range:(NSRange){0, attributedString.length}];
-    }
-    
-    if ([self adjustLineHeight]) {
-        if (_lineHeight > font.lineHeight) {
-            [attributedString addAttribute:NSBaselineOffsetAttributeName
-                                     value:@((_lineHeight - font.lineHeight)/ 2)
-                                     range:(NSRange){0, attributedString.length}];
-        }
-    }
-    
-    return attributedString;
-}
-
-- (NSAttributedString *)buildAttributeString
-{
-    NSString *string = self.text ?: @"";
-    
-    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
-    
-    // set textColor
-    if(_color) {
-        [attributedString addAttribute:NSForegroundColorAttributeName value:_color range:NSMakeRange(0, string.length)];
-    }
-    
-    // set font
-    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
-    if (font) {
-        [attributedString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, string.length)];
-    }
-    
-    if(_textDecoration == WXTextDecorationUnderline){
-        [attributedString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
-    } else if(_textDecoration == WXTextDecorationLineThrough){
-        [attributedString addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
-    }
-    
-    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
-
-    // handle text direction style, default ltr
-    if (_cssNode->layout.direction == CSS_DIRECTION_RTL) {
-        if (0 == _textAlign) {
-            //force text right-align if don't specified any align.
-            _textAlign = NSTextAlignmentRight;
-        }
-        paragraphStyle.baseWritingDirection = NSWritingDirectionRightToLeft;
-    } else {
-        //if you specify NSWritingDirectionNaturalDirection, the receiver resolves the writing
-        //directionto eitherNSWritingDirectionLeftToRight or NSWritingDirectionRightToLeft,
-        //depending on the direction for the user’s language preference setting.
-        paragraphStyle.baseWritingDirection =  NSWritingDirectionNatural;
-    }
-    
-    if (_textAlign) {
-        paragraphStyle.alignment = _textAlign;
-    }
-    
-    if (_lineHeight) {
-        paragraphStyle.maximumLineHeight = _lineHeight;
-        paragraphStyle.minimumLineHeight = _lineHeight;
-    }
-    
-    if (_lineHeight || _textAlign) {
-        [attributedString addAttribute:NSParagraphStyleAttributeName
-                                 value:paragraphStyle
-                                 range:(NSRange){0, attributedString.length}];
-    }
-    if ([self adjustLineHeight]) {
-        if (_lineHeight > font.lineHeight) {
-            [attributedString addAttribute:NSBaselineOffsetAttributeName
-                                     value:@((_lineHeight - font.lineHeight)/ 2)
-                                     range:(NSRange){0, attributedString.length}];
-        }
-    }
-
-    return attributedString;
-}
-
-- (BOOL)adjustLineHeight
-{
-    if (WX_SYS_VERSION_LESS_THAN(@"10.0")) {
-        return true;
-    }
-    return ![self useCoreText];
-}
-
-- (NSTextStorage *)textStorageWithWidth:(CGFloat)width
-{
-    if (_textStorage && width == _textStorageWidth) {
-        return _textStorage;
-    }
-    
-    NSLayoutManager *layoutManager = [NSLayoutManager new];
-    
-    // build AttributeString
-    NSAttributedString *attributedString = [self buildAttributeString];
-    
-    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
-    [textStorage addLayoutManager:layoutManager];
-    
-    NSTextContainer *textContainer = [NSTextContainer new];
-    textContainer.lineFragmentPadding = 0.0;
-    
-    if ([[_wordWrap lowercaseString] isEqualToString:@"break-word"]) {
-        textContainer.lineBreakMode = NSLineBreakByWordWrapping;
-    } else if ([[_wordWrap lowercaseString] isEqualToString:@"normal"]){
-        textContainer.lineBreakMode = NSLineBreakByClipping;
-    } else {
-        // set default lineBreakMode
-        textContainer.lineBreakMode = NSLineBreakByCharWrapping;
-    }
-    
-    if (_textOverflow && [_textOverflow length] > 0) {
-        if ([_textOverflow isEqualToString:@"ellipsis"])
-            textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
-    }
-    textContainer.maximumNumberOfLines = _lines > 0 ? _lines : 0;
-    textContainer.size = (CGSize){isnan(width) ? CGFLOAT_MAX : width, CGFLOAT_MAX};
-
-    [layoutManager addTextContainer:textContainer];
-    [layoutManager ensureLayoutForTextContainer:textContainer];
-    
-    _textStorageWidth = width;
-    _textStorage = textStorage;
-    
-    return textStorage;
-}
-
-- (void)syncTextStorageForView
-{
-    CGFloat width = self.calculatedFrame.size.width - (_padding.left + _padding.right);
-    NSTextStorage *textStorage = nil;
-    if (![self useCoreText]) {
-        textStorage = [self textStorageWithWidth:width];
-    }
-    [self.weexInstance.componentManager  _addUITask:^{
-        if ([self isViewLoaded]) {
-            if (![self useCoreText]) {
-                ((WXTextView *)self.view).textStorage = textStorage;
-            }
-            [self readyToRender]; // notify super component
-            [self setNeedsDisplay];
-        }
-    }];
-}
-
-- (void)_frameDidCalculated:(BOOL)isChanged
-{
-    [super _frameDidCalculated:isChanged];
-    [self syncTextStorageForView];
-}
-
-- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles
-{
-    [super _updateStylesOnComponentThread:styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:isUpdateStyles];
-    NSMutableDictionary * newStyles = [styles mutableCopy];
-    for (NSString * key in [resetStyles copy]) {
-        [newStyles setObject:@"" forKey:key];
-    }
-    [self fillCSSStyles:newStyles];
-    
-    [self syncTextStorageForView];
-}
-
-- (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes
-{
-    [super _updateAttributesOnComponentThread:attributes];
-    
-    [self fillAttributes:attributes];
-    
-    [self syncTextStorageForView];
-}
-
-- (void)drawTextWithContext:(CGContextRef)context bounds:(CGRect)bounds padding:(UIEdgeInsets)padding view:(WXTextView *)view
-{
-    if (bounds.size.width <= 0 || bounds.size.height <= 0) {
-        return;
-    }
-    
-    if ([self _needsDrawBorder]) {
-        [self _drawBorderWithContext:context size:bounds.size];
-    } else {
-        WXPerformBlockOnMainThread(^{
-            [self _resetNativeBorderRadius];
-        });
-    }
-    if (![self useCoreText]) {
-        NSLayoutManager *layoutManager = _textStorage.layoutManagers.firstObject;
-        NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
-        
-        CGRect textFrame = UIEdgeInsetsInsetRect(bounds, padding);
-        NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
-        
-        [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:textFrame.origin];
-        [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:textFrame.origin];
-    } else {
-        CGRect textFrame = UIEdgeInsetsInsetRect(bounds, padding);
-        // sufficient height for text to draw, or frame lines will be empty
-        textFrame.size.height = bounds.size.height * 2;
-        CGContextSaveGState(context);
-        //flip the coordinate system
-        CGContextSetTextMatrix(context, CGAffineTransformIdentity);
-        CGContextTranslateCTM(context, 0, textFrame.size.height);
-        CGContextScaleCTM(context, 1.0, -1.0);
-        
-        NSAttributedString * attributedStringCopy = [self ctAttributedString];
-        //add path
-        CGPathRef cgPath = NULL;
-        cgPath = CGPathCreateWithRect(textFrame, NULL);
-        CTFrameRef _coreTextFrameRef = NULL;
-        if (_coreTextFrameRef) {
-            CFRelease(_coreTextFrameRef);
-            _coreTextFrameRef = NULL;
-        }
-        if(!attributedStringCopy) {
-            return;
-        }
-        CTFramesetterRef ctframesetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedStringCopy));
-        _coreTextFrameRef = CTFramesetterCreateFrame(ctframesetterRef, CFRangeMake(0, attributedStringCopy.length), cgPath, NULL);
-        CFArrayRef ctLines = NULL;
-        if (NULL == _coreTextFrameRef) {
-            // try to protect crash from frame is NULL
-            return;
-        }
-        CFRelease(ctframesetterRef);
-        ctframesetterRef = NULL;
-        ctLines = CTFrameGetLines(_coreTextFrameRef);
-        CFIndex lineCount = CFArrayGetCount(ctLines);
-        NSMutableArray * mutableLines = [NSMutableArray new];
-        CGPoint lineOrigins[lineCount];
-        NSUInteger rowCount = 0;
-        BOOL needTruncation = NO;
-        CTLineRef ctTruncatedLine = NULL;
-        CTFrameGetLineOrigins(_coreTextFrameRef, CFRangeMake(0, 0), lineOrigins);
-        for (CFIndex lineIndex = 0;(!_lines || _lines > lineIndex) && lineIndex < lineCount; lineIndex ++) {
-            CTLineRef lineRef = NULL;
-            lineRef = CFArrayGetValueAtIndex(ctLines, lineIndex);
-            if (!lineRef) {
-                break;
-            }
-            CGPoint lineOrigin = lineOrigins[lineIndex];
-            lineOrigin.x += padding.left;
-            lineOrigin.y -= padding.top;
-            CFArrayRef runs = CTLineGetGlyphRuns(lineRef);
-            [mutableLines addObject:(__bridge id _Nonnull)(lineRef)];
-            // lineIndex base 0
-            rowCount = lineIndex + 1;
-            if (_lines > 0 && _truncationLine) {
-                if (_truncationLine && rowCount > _lines) {
-                    needTruncation = YES;
-                    do {
-                        NSUInteger lastRow = [mutableLines count];
-                        if (lastRow < rowCount) {
-                           break;
-                        }
-                        [mutableLines removeLastObject];
-                    } while (1);
-
-                }
-            }
-            if (_lines > 0 && _truncationLine) {
-                if (rowCount >= _lines &&!needTruncation && (CTLineGetStringRange(lineRef).length + CTLineGetStringRange(lineRef).location) < attributedStringCopy.length) {
-                    needTruncation = YES;
-                }
-            }
-            
-            if (needTruncation) {
-                CGContextSetTextPosition(context, lineOrigin.x, lineOrigin.y);
-                ctTruncatedLine = [self buildTruncatedLineWithRuns:runs lines:mutableLines path:cgPath];
-                if (ctTruncatedLine) {
-                    CFArrayRef truncatedRuns = CTLineGetGlyphRuns(ctTruncatedLine);
-                    [self drawTextWithRuns:truncatedRuns context:context lineOrigin:lineOrigin];
-                    CFRelease(ctTruncatedLine);
-                    ctTruncatedLine = NULL;
-                    continue;
-                }
-            }else {
-                [self drawTextWithRuns:runs context:context lineOrigin:lineOrigin];
-            }
-        }
-        
-        [mutableLines removeAllObjects];
-        CGPathRelease(cgPath);
-        CFRelease(_coreTextFrameRef);
-        _coreTextFrameRef = NULL;
-        cgPath = NULL;
-        CGContextRestoreGState(context);
-    }
-}
-
-- (void)drawTextWithRuns:(CFArrayRef)runs context:(CGContextRef)context lineOrigin:(CGPoint)lineOrigin
-{
-    for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runs); runIndex ++) {
-        CTRunRef run = NULL;
-        run = CFArrayGetValueAtIndex(runs, runIndex);
-        CFDictionaryRef attr = NULL;
-        attr = CTRunGetAttributes(run);
-        if (0 == runIndex) {
-            NSNumber *baselineOffset = (NSNumber*)CFDictionaryGetValue(attr, NSBaselineOffsetAttributeName);
-            if (baselineOffset) {
-                lineOrigin.y += [baselineOffset doubleValue];
-            }
-        }
-        CGContextSetTextPosition(context, lineOrigin.x, lineOrigin.y);
-        CTRunDraw(run, context, CFRangeMake(0, 0));
-        CFIndex glyphCount = CTRunGetGlyphCount(run);
-        if (glyphCount <= 0) continue;
-        
-        NSUnderlineStyle strikethrough = (NSUnderlineStyle)CFDictionaryGetValue(attr, NSStrikethroughStyleAttributeName);
-        
-        if (strikethrough) {
-            // draw strikethrough
-            [self drawLineThroughWithRun:runs context:context index:runIndex origin:lineOrigin];
-        }
-    }
-}
-
-- (CTLineRef)buildTruncatedLineWithRuns:(CFArrayRef)runs lines:(NSMutableArray*)mutableLines path:(CGPathRef)cgPath
-{
-    NSAttributedString * truncationToken = nil;
-    CTLineRef ctTruncatedLine = NULL;
-    CTLineRef lastLine = (__bridge CTLineRef)(mutableLines.lastObject);
-   
-    CFArrayRef lastLineRuns = CTLineGetGlyphRuns(lastLine);
-    NSUInteger lastLineRunCount = CFArrayGetCount(lastLineRuns);
-    
-    CTLineRef truncationTokenLine = NULL;
-    NSMutableDictionary *attrs = nil;
-    if (lastLineRunCount > 0) {
-        CTRunRef run = CFArrayGetValueAtIndex(runs, lastLineRunCount - 1);
-        attrs = (id)CTRunGetAttributes(run);
-        attrs = attrs ? attrs.mutableCopy : [NSMutableDictionary new];
-        CTFontRef font = (__bridge CTFontRef)(attrs[(id)kCTFontAttributeName]);
-        CGFloat fontSize = font ? CTFontGetSize(font):32 * self.weexInstance.pixelScaleFactor;
-        UIFont * uiFont = [UIFont systemFontOfSize:fontSize];
-        if (uiFont) {
-            font = CTFontCreateWithName((__bridge CFStringRef)uiFont.fontName, uiFont.pointSize, NULL);
-        }
-        if (font) {
-            attrs[(id)kCTFontAttributeName] = (__bridge id)(font);
-            uiFont = nil;
-            CFRelease(font);
-        }
-        CGColorRef color = (__bridge CGColorRef)(attrs[(id)kCTForegroundColorAttributeName]);
-        if (color && CFGetTypeID(color) == CGColorGetTypeID() && CGColorGetAlpha(color) == 0) {
-            [attrs removeObjectForKey:(id)kCTForegroundColorAttributeName];
-        }
-        
-        attrs = attrs?:[NSMutableDictionary new];
-        truncationToken = [[NSAttributedString alloc] initWithString:WXTextTruncationToken attributes:attrs];
-        truncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)truncationToken);
-    }
-    
-    if (truncationTokenLine) {
-        // default truncationType is kCTLineTruncationEnd
-        CTLineTruncationType truncationType = kCTLineTruncationEnd;
-        NSAttributedString *attributedString = [self ctAttributedString];
-        NSAttributedString * lastLineText = nil;
-        NSRange lastLineTextRange = WXNSRangeFromCFRange(CTLineGetStringRange(lastLine));
-        NSRange attributeStringRange = NSMakeRange(0, attributedString.string.length);
-        NSRange interSectionRange = NSIntersectionRange(lastLineTextRange, attributeStringRange);
-        if (!NSEqualRanges(interSectionRange, lastLineTextRange)) {
-            // out of bounds
-            lastLineTextRange = interSectionRange;
-        }
-        lastLineText = [attributedString attributedSubstringFromRange: lastLineTextRange];
-        if (!lastLineText) {
-            lastLineText = attributedString;
-        }
-        NSMutableAttributedString *mutableLastLineText = lastLineText.mutableCopy;
-        [mutableLastLineText appendAttributedString:truncationToken];
-        CTLineRef ctLastLineExtend = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)[mutableLastLineText copy]);
-        if (ctLastLineExtend) {
-            CGRect cgPathRect = CGRectZero;
-            CGFloat truncatedWidth = 0;
-            if (CGPathIsRect(cgPath, &cgPathRect)) {
-                truncatedWidth = cgPathRect.size.width;
-            }
-            ctTruncatedLine = CTLineCreateTruncatedLine(ctLastLineExtend, truncatedWidth, truncationType, truncationTokenLine);
-            CFRelease(ctLastLineExtend);
-            ctLastLineExtend = NULL;
-            CFRelease(truncationTokenLine);
-            truncationTokenLine = NULL;
-        }
-    }
-    
-    return ctTruncatedLine;
-}
-
-- (void)drawLineThroughWithRun:(CFArrayRef)runs context:(CGContextRef)context index:(CFIndex)runIndex origin:(CGPoint)lineOrigin
-{
-    CFRetain(runs);
-    CGContextRetain(context);
-    
-    CGContextSaveGState(context);
-    CGFloat xHeight = 0, underLinePosition = 0, lineThickness = 0;
-    CTRunRef run = CFArrayGetValueAtIndex(runs, runIndex);
-    WXTextGetRunsMaxMetric(runs, &xHeight, &underLinePosition, &lineThickness);
-    
-    CGPoint strikethroughStart;
-    strikethroughStart.x =  lineOrigin.x - underLinePosition;
-    strikethroughStart.y = lineOrigin.y + xHeight/2;
-    CGPoint runPosition = CGPointZero;
-    CTRunGetPositions(run, CFRangeMake(0, 1), &runPosition);
-    strikethroughStart.x = lineOrigin.x + runPosition.x;
-    CGContextSetLineWidth(context, WXTextDefaultLineThroughWidth);
-    double length = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), NULL, NULL, NULL);
-    CGContextMoveToPoint(context, strikethroughStart.x, strikethroughStart.y);
-    CGContextAddLineToPoint(context, strikethroughStart.x + length, strikethroughStart.y);
-    CGContextStrokePath(context);
-    
-    CGContextRestoreGState(context);
-    CFRelease(runs);
-    CGContextRelease(context);
-}
-
-- (CGSize)calculateTextHeightWithWidth:(CGFloat)aWidth
-{
-    CGFloat totalHeight = 0;
-    CGSize suggestSize = CGSizeZero;
-    NSAttributedString * attributedStringCpy = [self ctAttributedString];
-    if (!attributedStringCpy) {
-        return CGSizeZero;
-    }
-    if (isnan(aWidth)) {
-        aWidth = CGFLOAT_MAX;
-    }
-    aWidth = [attributedStringCpy boundingRectWithSize:CGSizeMake(aWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading context:nil].size.width;
-    CTFramesetterRef ctframesetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedStringCpy));
-    suggestSize = CTFramesetterSuggestFrameSizeWithConstraints(ctframesetterRef, CFRangeMake(0, 0), NULL, CGSizeMake(aWidth, MAXFLOAT), NULL);
-    
-    CGMutablePathRef path = NULL;
-    path = CGPathCreateMutable();
-        // sufficient height to draw text
-    CGPathAddRect(path, NULL, CGRectMake(0, 0, aWidth, suggestSize.height * 10));
-        
-    CTFrameRef frameRef = NULL;
-    frameRef = CTFramesetterCreateFrame(ctframesetterRef, CFRangeMake(0, attributedStringCpy.length), path, NULL);
-    CGPathRelease(path);
-    
-    CFArrayRef lines = NULL;
-    if (NULL == frameRef) {
-        //try to protect unexpected crash.
-        return suggestSize;
-    }
-    CFRelease(ctframesetterRef);
-    ctframesetterRef = NULL;
-    lines = CTFrameGetLines(frameRef);
-    CFIndex lineCount = CFArrayGetCount(lines);
-    CGFloat ascent = 0;
-    CGFloat descent = 0;
-    CGFloat leading = 0;
-    
-    // height = ascent + descent + lineCount*leading
-    // ignore linespaing
-    NSUInteger actualLineCount = 0;
-    for (CFIndex lineIndex = 0; (!_lines|| lineIndex < _lines) && lineIndex < lineCount; lineIndex ++)
-    {
-        CTLineRef lineRef = NULL;
-        lineRef = CFArrayGetValueAtIndex(lines, lineIndex);
-        CTLineGetTypographicBounds(lineRef, &ascent, &descent, &leading);
-        totalHeight += ascent + descent;
-        actualLineCount ++;
-    }
-    
-    totalHeight = totalHeight + actualLineCount * leading;
-    CFRelease(frameRef);
-    frameRef = NULL;
-    
-    if (WX_SYS_VERSION_LESS_THAN(@"10.0")) {
-        // there is something wrong with coreText drawing text height, trying to fix this with more efficent way.
-        if(actualLineCount && actualLineCount < lineCount) {
-            suggestSize.height = suggestSize.height * actualLineCount / lineCount;
-        }
-        return CGSizeMake(aWidth, suggestSize.height);
-    }
-    return CGSizeMake(aWidth, totalHeight);
-}
-
-static void WXTextGetRunsMaxMetric(CFArrayRef runs, CGFloat *xHeight, CGFloat *underlinePosition, CGFloat *lineThickness)
-{
-    CFRetain(runs);
-    CGFloat maxXHeight = 0;
-    CGFloat maxUnderlinePos = 0;
-    CGFloat maxLineThickness = 0;
-    for (NSUInteger index = 0, runsCount = CFArrayGetCount(runs); index < runsCount; index ++) {
-        CTRunRef run = CFArrayGetValueAtIndex(runs, index);
-        CFDictionaryRef attrs = CTRunGetAttributes(run);
-        if (attrs) {
-            CTFontRef font = CFDictionaryGetValue(attrs, kCTFontAttributeName);
-            if (font) {
-                CGFloat xHeight = CTFontGetXHeight(font);
-                if (xHeight > maxXHeight) {
-                    maxXHeight = xHeight;
-                }
-                
-                CGFloat underlinePos = CTFontGetUnderlinePosition(font);
-                if (underlinePos < maxUnderlinePos) {
-                    maxUnderlinePos = underlinePos;
-                }
-                
-                CGFloat lineThickness = CTFontGetUnderlineThickness(font);
-                if (lineThickness > maxLineThickness) {
-                    maxLineThickness = lineThickness;
-                }
-            }
-        }
-    }
-    
-    if (xHeight) {
-        *xHeight = maxXHeight;
-    }
-    
-    if (underlinePosition) {
-        *underlinePosition = maxUnderlinePos;
-    }
-    
-    if (lineThickness) {
-        *lineThickness = maxLineThickness;
-    }
-    
-    CFRelease(runs);
-}
-                                                                                                                                       
-NS_INLINE NSRange WXNSRangeFromCFRange(CFRange range) {
-    return NSMakeRange(range.location, range.length);
-}
-
-#ifdef UITEST
-- (NSString *)description
-{
-    return super.description;
-}
-#endif
- 
-- (void)_resetCSSNodeStyles:(NSArray *)styles
-{
-    [super _resetCSSNodeStyles:styles];
-    if ([styles containsObject:@"color"]) {
-        _color = [UIColor blackColor];
-        [self setNeedsRepaint];
-    }
-    if ([styles containsObject:@"fontSize"]) {
-        _fontSize = WX_TEXT_FONT_SIZE;
-        [self setNeedsRepaint];
-        [self setNeedsLayout];
-    }
-}
-
-@end
-


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.m
deleted file mode 100644
index 585c9f3..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.m
+++ /dev/null
@@ -1,207 +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 "WXRefreshComponent.h"
-#import "WXScrollerComponent.h"
-#import "WXLoadingIndicator.h"
-#import "WXComponent_internal.h"
-#import "WXLog.h"
-
-@interface WXRefreshComponent()
-
-@property (nonatomic) BOOL displayState;
-@property (nonatomic) BOOL initFinished;
-@property (nonatomic) BOOL refreshEvent;
-@property (nonatomic) BOOL pullingdownEvent;
-
-@property (nonatomic, weak) WXLoadingIndicator *indicator;
-
-@end
-
-@implementation WXRefreshComponent
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    if (self) {
-        _refreshEvent = NO;
-        _pullingdownEvent = NO;
-        if (attributes[@"display"]) {
-            if ([attributes[@"display"] isEqualToString:@"show"]) {
-                _displayState = YES;
-            } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
-                _displayState = NO;
-            } else {
-                WXLogError(@"");
-            }
-        }
-        self.cssNode->style.position_type = CSS_POSITION_ABSOLUTE;
-    }
-    return self;
-}
-
-- (void)viewDidLoad
-{
-     _initFinished = YES;
-    
-    if (!_displayState) {
-        [_indicator.view setHidden:YES];
-    }
-}
-
-- (void)layoutDidFinish
-{
-    [self.view setFrame: (CGRect) {
-        .size = self.calculatedFrame.size,
-        .origin.x = self.calculatedFrame.origin.x,
-        .origin.y = self.view.frame.origin.y - CGRectGetHeight(self.calculatedFrame)
-    }];
-}
-
-- (void)viewWillUnload
-{
-    _displayState = NO;
-    _refreshEvent = NO;
-    _initFinished = NO;
-}
-
-- (void)refresh
-{
-    if (!_refreshEvent || _displayState) {
-        return;
-    }
-    [self fireEvent:@"refresh" params:nil];
-}
-
-- (void)pullingdown:(NSDictionary*)param
-{
-    if (!_pullingdownEvent) {
-        return ;
-    }
-    
-    [self fireEvent:@"pullingdown" params:param];
-}
-
-- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    if (subcomponent) {
-        [super _insertSubcomponent:subcomponent atIndex:index];
-        if ([subcomponent isKindOfClass:[WXLoadingIndicator class]]) {
-            _indicator = (WXLoadingIndicator*)subcomponent;
-        }
-    }
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    if (attributes[@"display"]) {
-        if ([attributes[@"display"] isEqualToString:@"show"]) {
-            _displayState = YES;
-        } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
-            _displayState = NO;
-        } else {
-            WXLogError(@"");
-        }
-        [self setDisplay];
-    }
-}
-
-- (void)addEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"refresh"]) {
-        _refreshEvent = YES;
-    }
-    if ([eventName isEqualToString:@"pullingdown"]) {
-        _pullingdownEvent = YES;
-    }
-}
-
-- (void)removeEvent:(NSString *)evetName
-{
-    if ([evetName isEqualToString:@"refresh"]) {
-        _refreshEvent = NO;
-    }
-    if ([evetName isEqualToString:@"pullingdown"]) {
-        _pullingdownEvent = NO;
-    }
-}
-
-- (void)setDisplay
-{
-    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
-    if (scrollerProtocol == nil || !_initFinished)
-        return;
-    
-    if ([scrollerProtocol respondsToSelector:@selector(refreshType)] &&
-        [[scrollerProtocol refreshType] isEqualToString:@"refreshForAppear"]) {
-        UIEdgeInsets inset = [scrollerProtocol contentInset];
-        if (_displayState) {
-            inset.top = self.calculatedFrame.size.height;
-            if ([_indicator.view isHidden]) {
-                [_indicator.view setHidden:NO];
-            }
-            [_indicator start];
-        } else {
-            inset.top = 0;
-            [_indicator stop];
-        }
-        [scrollerProtocol setContentInset:inset];
-    } else {
-        CGPoint offset = [scrollerProtocol contentOffset];
-        if (_displayState) {
-            offset.y = -self.calculatedFrame.size.height;
-            if ([_indicator.view isHidden]) {
-                [_indicator.view setHidden:NO];
-            }
-            [_indicator start];
-        } else {
-            offset.y = 0;
-            [_indicator stop];
-        }
-        [scrollerProtocol setContentOffset:offset animated:YES];
-    }
-  
-}
-
-- (BOOL)displayState
-{
-    return _displayState;
-}
-
-- (void)setIndicatorHidden:(BOOL)hidden {
-    [_indicator.view setHidden:hidden];
-    
-    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
-    if (scrollerProtocol == nil || !_initFinished)
-        return;
-    if ([scrollerProtocol respondsToSelector:@selector(refreshType)] &&
-        [[scrollerProtocol refreshType] isEqualToString:@"refreshForAppear"]) {
-        UIEdgeInsets inset = [scrollerProtocol contentInset];
-        if (!hidden) {
-            inset.top = self.calculatedFrame.size.height;
-            [_indicator start];
-        } else {
-            inset.top = 0;
-            [_indicator stop];
-        }
-        [scrollerProtocol setContentInset:inset];
-    }
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.mm
new file mode 100644
index 0000000..f940e3a
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.mm
@@ -0,0 +1,224 @@
+/*
+ * 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 "WXRefreshComponent.h"
+#import "WXScrollerComponent.h"
+#import "WXLoadingIndicator.h"
+#import "WXComponent_internal.h"
+#import "WXLog.h"
+#import "WXComponent+Layout.h"
+
+@interface WXRefreshComponent()
+
+@property (nonatomic) BOOL displayState;
+@property (nonatomic) BOOL initFinished;
+@property (nonatomic) BOOL refreshEvent;
+@property (nonatomic) BOOL pullingdownEvent;
+
+@property (nonatomic, weak) WXLoadingIndicator *indicator;
+
+@end
+
+@implementation WXRefreshComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        _refreshEvent = NO;
+        _pullingdownEvent = NO;
+        if (attributes[@"display"]) {
+            if ([attributes[@"display"] isEqualToString:@"show"]) {
+                _displayState = YES;
+            } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
+                _displayState = NO;
+            } else {
+                WXLogError(@"");
+            }
+        }
+//#ifndef USE_FLEX
+        if (![WXComponent isUseFlex]) {
+          self.cssNode->style.position_type = CSS_POSITION_ABSOLUTE;
+        }
+//#else
+        else
+        {
+            self.flexCssNode->setStylePositionType(WeexCore::kAbsolute);
+        }
+       
+//#endif
+    }
+    return self;
+}
+
+- (void)viewDidLoad
+{
+     _initFinished = YES;
+    
+    if (!_displayState) {
+        [_indicator.view setHidden:YES];
+    }
+}
+
+- (void)layoutDidFinish
+{
+    [self.view setFrame: (CGRect) {
+        .size = self.calculatedFrame.size,
+        .origin.x = self.calculatedFrame.origin.x,
+        .origin.y = self.view.frame.origin.y - CGRectGetHeight(self.calculatedFrame)
+    }];
+}
+
+- (void)viewWillUnload
+{
+    _displayState = NO;
+    _refreshEvent = NO;
+    _initFinished = NO;
+}
+
+- (void)refresh
+{
+    if (!_refreshEvent || _displayState) {
+        return;
+    }
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> refreshComponent : refresh ref:%@",self.ref);
+#endif
+    [self fireEvent:@"refresh" params:nil];
+}
+
+- (void)pullingdown:(NSDictionary*)param
+{
+    if (!_pullingdownEvent) {
+        return ;
+    }
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> refreshComponent : pullingdown ,ref:%@",self.ref);
+#endif
+    
+    [self fireEvent:@"pullingdown" params:param];
+}
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    if (subcomponent) {
+        [super _insertSubcomponent:subcomponent atIndex:index];
+        if ([subcomponent isKindOfClass:[WXLoadingIndicator class]]) {
+            _indicator = (WXLoadingIndicator*)subcomponent;
+        }
+    }
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"display"]) {
+        if ([attributes[@"display"] isEqualToString:@"show"]) {
+            _displayState = YES;
+        } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
+            _displayState = NO;
+        } else {
+            WXLogError(@"");
+        }
+        [self setDisplay];
+    }
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"refresh"]) {
+        _refreshEvent = YES;
+    }
+    if ([eventName isEqualToString:@"pullingdown"]) {
+        _pullingdownEvent = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)evetName
+{
+    if ([evetName isEqualToString:@"refresh"]) {
+        _refreshEvent = NO;
+    }
+    if ([evetName isEqualToString:@"pullingdown"]) {
+        _pullingdownEvent = NO;
+    }
+}
+
+- (void)setDisplay
+{
+    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
+    if (scrollerProtocol == nil || !_initFinished)
+        return;
+    
+    if ([scrollerProtocol respondsToSelector:@selector(refreshType)] &&
+        [[scrollerProtocol refreshType] isEqualToString:@"refreshForAppear"]) {
+        UIEdgeInsets inset = [scrollerProtocol contentInset];
+        if (_displayState) {
+            inset.top = self.calculatedFrame.size.height;
+            if ([_indicator.view isHidden]) {
+                [_indicator.view setHidden:NO];
+            }
+            [_indicator start];
+        } else {
+            inset.top = 0;
+            [_indicator stop];
+        }
+        [scrollerProtocol setContentInset:inset];
+    } else {
+        CGPoint offset = [scrollerProtocol contentOffset];
+        if (_displayState) {
+            offset.y = -self.calculatedFrame.size.height;
+            if ([_indicator.view isHidden]) {
+                [_indicator.view setHidden:NO];
+            }
+            [_indicator start];
+        } else {
+            offset.y = 0;
+            [_indicator stop];
+        }
+        [scrollerProtocol setContentOffset:offset animated:YES];
+    }
+  
+}
+
+- (BOOL)displayState
+{
+    return _displayState;
+}
+
+- (void)setIndicatorHidden:(BOOL)hidden {
+    [_indicator.view setHidden:hidden];
+    
+    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
+    if (scrollerProtocol == nil || !_initFinished)
+        return;
+    if ([scrollerProtocol respondsToSelector:@selector(refreshType)] &&
+        [[scrollerProtocol refreshType] isEqualToString:@"refreshForAppear"]) {
+        UIEdgeInsets inset = [scrollerProtocol contentInset];
+        if (!hidden) {
+            inset.top = self.calculatedFrame.size.height;
+            [_indicator start];
+        } else {
+            inset.top = 0;
+            [_indicator stop];
+        }
+        [scrollerProtocol setContentInset:inset];
+    }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.h
index db0c155..8f2b587 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.h
+++ b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.h
@@ -28,8 +28,6 @@
 
 @property (nonatomic, assign) CGSize contentSize;
 
-@property (nonatomic, readonly, assign) css_node_t *scrollerCSSNode;
-
 - (NSUInteger)childrenCountForScrollerLayout;
 
 - (void)handleAppear;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.m
deleted file mode 100644
index 5f197d1..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.m
+++ /dev/null
@@ -1,884 +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 "WXScrollerComponent.h"
-#import "WXComponent_internal.h"
-#import "WXComponent.h"
-#import "WXDefine.h"
-#import "WXConvert.h"
-#import "WXSDKInstance.h"
-#import "WXUtility.h"
-#import "WXLoadingComponent.h"
-#import "WXRefreshComponent.h"
-#import "WXConfigCenterProtocol.h"
-#import "WXSDKEngine.h"
-#import "WXComponent+Events.h"
-
-@interface WXScrollerComponentView:UIScrollView
-@end
-
-@implementation WXScrollerComponentView
-- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
-{
-    if ([(id <WXScrollerProtocol>) self.wx_component respondsToSelector:@selector(requestGestureShouldStopPropagation:shouldReceiveTouch:)]) {
-        return [(id <WXScrollerProtocol>) self.wx_component requestGestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
-    }
-    else{
-        return YES;
-    }
-}
-@end
-
-@interface WXScrollToTarget : NSObject
-
-@property (nonatomic, weak)   WXComponent *target;
-@property (nonatomic, assign) BOOL hasAppear;
-
-@end
-
-@implementation WXScrollToTarget
-
-@end
-
-
-@interface WXScrollerComponent()
-
-@property (nonatomic, strong) NSMutableArray *  stickyArray;
-@property (nonatomic, strong) NSMutableArray * listenerArray;
-@property (nonatomic, weak) WXRefreshComponent *refreshComponent;
-@property (nonatomic, weak) WXLoadingComponent *loadingComponent;
-
-@end
-
-@implementation WXScrollerComponent
-{
-    CGSize _contentSize;
-    BOOL _listenLoadMore;
-    BOOL _scrollEvent;
-    BOOL _scrollStartEvent;
-    BOOL _scrollEndEvent;
-    BOOL _isScrolling;
-    CGFloat _loadMoreOffset;
-    CGFloat _previousLoadMoreContentHeight;
-    CGFloat _offsetAccuracy;
-    CGPoint _lastContentOffset;
-    CGPoint _lastScrollEventFiredOffset;
-    BOOL _scrollable;
-    NSString * _alwaysScrollableVertical;
-    NSString * _alwaysScrollableHorizontal;
-    BOOL _bounces;
-    
-    // refreshForAppear: load more when refresh component begin appear(if scroll is dragging or decelerating, should delay)
-    // refreshForWholeVisible: load more until the whole refresh component visible
-    NSString *_refreshType;
-
-    // vertical & horizontal
-    WXScrollDirection _scrollDirection;
-    // left & right & up & down
-    NSString *_direction;
-    BOOL _showScrollBar;
-    BOOL _pagingEnabled;
-    
-    BOOL _shouldNotifiAppearDescendantView;
-    BOOL _shouldRemoveScrollerListener;
-
-    css_node_t *_scrollerCSSNode;
-    
-    NSHashTable* _delegates;
-}
-
-WX_EXPORT_METHOD(@selector(resetLoadmore))
-
-- (void)resetLoadmore
-{
-    _previousLoadMoreContentHeight=0;
-}
-
-- (css_node_t *)scrollerCSSNode
-{
-    return _scrollerCSSNode;
-}
-
-- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    [super _insertSubcomponent:subcomponent atIndex:index];
-    
-    if ([subcomponent isKindOfClass:[WXRefreshComponent class]]) {
-        _refreshComponent = (WXRefreshComponent*)subcomponent;
-    }
-    else if ([subcomponent isKindOfClass:[WXLoadingComponent class]]) {
-        _loadingComponent = (WXLoadingComponent*)subcomponent;
-    }
-}
-
--(instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    if (self) {
-        
-        _stickyArray = [NSMutableArray array];
-        _listenerArray = [NSMutableArray array];
-        _scrollEvent = NO;
-        _scrollStartEvent = NO;
-        _scrollEndEvent = NO;
-        _lastScrollEventFiredOffset = CGPointMake(0, 0);
-        _scrollDirection = attributes[@"scrollDirection"] ? [WXConvert WXScrollDirection:attributes[@"scrollDirection"]] : WXScrollDirectionVertical;
-        _showScrollBar = attributes[@"showScrollbar"] ? [WXConvert BOOL:attributes[@"showScrollbar"]] : YES;
-        
-        if (attributes[@"alwaysScrollableVertical"]) {
-            _alwaysScrollableVertical = [WXConvert NSString:attributes[@"alwaysScrollableVertical"]];
-        }
-        if (attributes[@"alwaysScrollableHorizontal"]) {
-            _alwaysScrollableHorizontal = [WXConvert NSString:attributes[@"alwaysScrollableHorizontal"]];
-        }
-        _bounces = attributes[@"bounce"]?[WXConvert BOOL:attributes[@"bounce"]]:YES;
-        _refreshType = [WXConvert NSString:attributes[@"refreshType"]]?:@"refreshForWholeVisible";
-        _pagingEnabled = attributes[@"pagingEnabled"] ? [WXConvert BOOL:attributes[@"pagingEnabled"]] : NO;
-        _loadMoreOffset = attributes[@"loadmoreoffset"] ? [WXConvert WXPixelType:attributes[@"loadmoreoffset"] scaleFactor:self.weexInstance.pixelScaleFactor] : 0;
-        _loadmoreretry = attributes[@"loadmoreretry"] ? [WXConvert NSUInteger:attributes[@"loadmoreretry"]] : 0;
-        _listenLoadMore = [events containsObject:@"loadmore"];
-        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
-        _offsetAccuracy = attributes[@"offsetAccuracy"] ? [WXConvert WXPixelType:attributes[@"offsetAccuracy"] scaleFactor:self.weexInstance.pixelScaleFactor] : 0;
-        _scrollerCSSNode = new_css_node();
-        
-        // let scroller fill the rest space if it is a child component and has no fixed height & width
-        if (((_scrollDirection == WXScrollDirectionVertical &&
-            isUndefined(self.cssNode->style.dimensions[CSS_HEIGHT])) ||
-            (_scrollDirection == WXScrollDirectionHorizontal &&
-              isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]))) &&
-             self.cssNode->style.flex <= 0.0) {
-            self.cssNode->style.flex = 1.0;
-        }
-        id configCenter = [WXSDKEngine handlerForProtocol:@protocol(WXConfigCenterProtocol)];
-        if ([configCenter respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) {
-            BOOL shouldNotifiAppearDescendantView = [[configCenter configForKey:@"iOS_weex_ext_config.shouldNotifiAppearDescendantView" defaultValue:@(YES) isDefault:NULL] boolValue];
-            _shouldNotifiAppearDescendantView = shouldNotifiAppearDescendantView;
-            BOOL shouldRemoveScrollerListener = [[configCenter configForKey:@"iOS_weex_ext_config.shouldRemoveScrollerListener" defaultValue:@(YES) isDefault:NULL] boolValue];
-            _shouldRemoveScrollerListener = shouldRemoveScrollerListener;
-            
-        }
-    }
-    
-    return self;
-}
-
-- (UIView *)loadView
-{
-    return [[WXScrollerComponentView alloc] init];
-}
-
-- (void)viewDidLoad
-{
-    [super viewDidLoad];
-    [self setContentSize:_contentSize];
-    WXScrollerComponentView* scrollView = (WXScrollerComponentView *)self.view;
-    scrollView.delegate = self;
-    scrollView.exclusiveTouch = YES;
-    scrollView.autoresizesSubviews = NO;
-    scrollView.clipsToBounds = YES;
-    scrollView.showsVerticalScrollIndicator = _showScrollBar;
-    scrollView.showsHorizontalScrollIndicator = _showScrollBar;
-    scrollView.scrollEnabled = _scrollable;
-    scrollView.pagingEnabled = _pagingEnabled;
-    
-    if (scrollView.bounces != _bounces) {
-        scrollView.bounces = _bounces;
-    }
-    
-    if (_alwaysScrollableHorizontal) {
-        scrollView.alwaysBounceHorizontal = [WXConvert BOOL:_alwaysScrollableHorizontal];
-    }
-    if (_alwaysScrollableVertical) {
-        scrollView.alwaysBounceVertical = [WXConvert BOOL:_alwaysScrollableVertical];
-    }
-    
-    if (@available(iOS 11.0, *)) {
-        if ([scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
-            scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
-        }
-    } else {
-        // Fallback on earlier versions
-    }
-    
-    if (self.ancestorScroller) {
-        scrollView.scrollsToTop = NO;
-    } else {
-        scrollView.scrollsToTop = YES;
-    }
-}
-
-- (void)layoutDidFinish
-{
-    if ([self isViewLoaded]) {
-        [self setContentSize:_contentSize];
-        [self adjustSticky];
-        [self handleAppear];
-    }
-    
-    [_loadingComponent resizeFrame];
-}
-
-- (void)viewWillUnload
-{
-    ((UIScrollView *)_view).delegate = nil;
-}
-
-- (void)dealloc
-{
-    ((UIScrollView *)_view).delegate = nil;
-    [self.stickyArray removeAllObjects];
-    [self.listenerArray removeAllObjects];
-    
-    free(_scrollerCSSNode);
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    if (attributes[@"showScrollbar"]) {
-        _showScrollBar = [WXConvert BOOL:attributes[@"showScrollbar"]];
-        ((UIScrollView *)self.view).showsHorizontalScrollIndicator = _showScrollBar;
-        ((UIScrollView *)self.view).showsVerticalScrollIndicator = _showScrollBar;
-    }
-    
-    if (attributes[@"pagingEnabled"]) {
-        _pagingEnabled = [WXConvert BOOL:attributes[@"pagingEnabled"]];
-        ((UIScrollView *)self.view).pagingEnabled = _pagingEnabled;
-    }
-    
-    if (attributes[@"loadmoreoffset"]) {
-        _loadMoreOffset = [WXConvert WXPixelType:attributes[@"loadmoreoffset"] scaleFactor:self.weexInstance.pixelScaleFactor];
-    }
-    if (attributes[@"bounce"]) {
-        _bounces = [WXConvert BOOL:attributes[@"bounce"]];
-        ((UIScrollView *)self.view).bounces = _bounces;
-    }
-    
-    if (attributes[@"loadmoreretry"]) {
-        NSUInteger loadmoreretry = [WXConvert NSUInteger:attributes[@"loadmoreretry"]];
-        if (loadmoreretry != _loadmoreretry) {
-            _previousLoadMoreContentHeight = 0;
-        }
-        self.loadmoreretry = loadmoreretry;
-    }
-    if (attributes[@"scrollable"]) {
-        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
-        ((UIScrollView *)self.view).scrollEnabled = _scrollable;
-    }
-    if (attributes[@"alwaysScrollableHorizontal"]) {
-        _alwaysScrollableHorizontal = [WXConvert NSString:attributes[@"alwaysScrollableHorizontal"]];
-        ((UIScrollView*)self.view).alwaysBounceHorizontal = [WXConvert BOOL:_alwaysScrollableHorizontal];
-    }
-    
-    if (attributes[@"alwaysScrollableVertical"]) {
-        _alwaysScrollableVertical = [WXConvert NSString:attributes[@"alwaysScrollableVertical"]];
-        ((UIScrollView*)self.view).alwaysBounceVertical = [WXConvert BOOL:_alwaysScrollableVertical];
-    }
-    
-    if (attributes[@"refreshType"]) {
-        _refreshType = [WXConvert NSString:attributes[@"refreshType"]];
-    }
-    
-    if (attributes[@"offsetAccuracy"]) {
-        _offsetAccuracy = [WXConvert WXPixelType:attributes[@"offsetAccuracy"] scaleFactor:self.weexInstance.pixelScaleFactor];
-    }
-    
-    if (attributes[@"scrollDirection"]) {
-        _scrollDirection = attributes[@"scrollDirection"] ? [WXConvert WXScrollDirection:attributes[@"scrollDirection"]] : WXScrollDirectionVertical;
-    }
-}
-
-- (void)addEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"loadmore"]) {
-        _listenLoadMore = YES;
-    }
-    if ([eventName isEqualToString:@"scroll"]) {
-        _scrollEvent = YES;
-    }
-    if ([eventName isEqualToString:@"scrollstart"]) {
-        _scrollStartEvent = YES;
-    }
-    if ([eventName isEqualToString:@"scrollend"]) {
-        _scrollEndEvent = YES;
-    }
-}
-
-- (void)removeEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"loadmore"]) {
-        _listenLoadMore = NO;
-    }
-    if ([eventName isEqualToString:@"scroll"]) {
-        _scrollEvent = NO;
-    }
-    if ([eventName isEqualToString:@"scrollstart"]) {
-        _scrollStartEvent = NO;
-    }
-    if ([eventName isEqualToString:@"scrollend"]) {
-        _scrollEndEvent = NO;
-    }
-}
-
-#pragma mark WXScrollerProtocol
-
-- (void)addStickyComponent:(WXComponent *)sticky
-{
-    if(![self.stickyArray containsObject:sticky]) {
-        [self.stickyArray addObject:sticky];
-        [self adjustSticky];
-    }
-}
-
-- (void)removeStickyComponent:(WXComponent *)sticky
-{
-    if([self.stickyArray containsObject:sticky]) {
-        [self.stickyArray removeObject:sticky];
-        [self adjustSticky];
-    }
-}
-
-- (void)adjustSticky
-{
-    if (![self isViewLoaded]) {
-        return;
-    }
-    CGFloat scrollOffsetY = ((UIScrollView *)self.view).contentOffset.y;
-    for(WXComponent *component in self.stickyArray) {
-        if (isnan(component->_absolutePosition.x) && isnan(component->_absolutePosition.y)) {
-            component->_absolutePosition = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view];
-        }
-        CGPoint relativePosition = component->_absolutePosition;
-        if (isnan(relativePosition.y)) {
-            continue;
-        }
-        
-        WXComponent *supercomponent = component.supercomponent;
-        if(supercomponent != self && component.view.superview != self.view) {
-            [component.view removeFromSuperview];
-            [self.view addSubview:component.view];
-        } else {
-            [self.view bringSubviewToFront:component.view];
-        }
-        
-        CGFloat relativeY = relativePosition.y;
-        BOOL needSticky = NO;
-        
-        if (scrollOffsetY >= relativeY) {
-            needSticky = YES;
-        } else {
-            // important: reset views' frame
-            component.view.frame = CGRectMake(relativePosition.x, relativePosition.y, component.calculatedFrame.size.width, component.calculatedFrame.size.height);
-        }
-        
-        if (!needSticky) {
-            continue;
-        }
-        
-        // The minimum Y sticky view can reach is its original position
-        CGFloat minY = relativeY;
-        CGPoint superRelativePosition = supercomponent == self ? CGPointZero : [supercomponent.supercomponent.view convertPoint:supercomponent.view.frame.origin toView:self.view];
-        CGFloat maxY = superRelativePosition.y + supercomponent.calculatedFrame.size.height - component.calculatedFrame.size.height;
-        
-        CGFloat stickyY = scrollOffsetY;
-        if (stickyY < minY) {
-            stickyY = minY;
-        } else if (stickyY > maxY && ![supercomponent conformsToProtocol:@protocol(WXScrollerProtocol)]) {
-            // Sticky component can not go beyond its parent's bounds when its parent is not scroller;
-            stickyY = maxY;
-        }
-        
-        UIView *stickyView = component.view;
-        CGPoint origin = stickyView.frame.origin;
-        origin.y = stickyY;
-        stickyView.frame = (CGRect){origin,stickyView.frame.size};
-    }
-}
-
-- (void)addScrollToListener:(WXComponent *)target
-{
-    BOOL has = NO;
-    NSMutableArray *listenerArray = [self.listenerArray copy];
-    for (WXScrollToTarget *targetData in listenerArray) {
-        if (targetData.target == target) {
-            has = YES;
-            break;
-        }
-    }
-    if (!has) {
-        WXScrollToTarget *scrollTarget = [[WXScrollToTarget alloc] init];
-        scrollTarget.target = target;
-        scrollTarget.hasAppear = NO;
-        [self.listenerArray addObject:scrollTarget];
-    }
-}
-
-- (void)removeScrollToListener:(WXComponent *)target
-{
-    if (_shouldRemoveScrollerListener) {
-        WXScrollToTarget *targetData = nil;
-        NSMutableArray *listenerArray = [self.listenerArray copy];
-        for (WXScrollToTarget *targetDataTemp in listenerArray) {
-            if (targetDataTemp.target == target) {
-                targetData = targetDataTemp;
-                break;
-            }
-        }
-        if(targetData) {
-            [self.listenerArray removeObject:targetData];
-        }
-    }
-}
-
-- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset animated:(BOOL)animated
-{
-    UIScrollView *scrollView = (UIScrollView *)self.view;
-
-    CGPoint contentOffset = scrollView.contentOffset;
-    CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
-    
-    if (_scrollDirection == WXScrollDirectionHorizontal) {
-        CGFloat contentOffetX = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view].x;
-        contentOffetX += offset * scaleFactor;
-        
-        if (scrollView.contentSize.width >= scrollView.frame.size.width && contentOffetX > scrollView.contentSize.width - scrollView.frame.size.width) {
-            contentOffset.x = scrollView.contentSize.width - scrollView.frame.size.width;
-        } else {
-            contentOffset.x = contentOffetX;
-        }
-    } else {
-        CGFloat contentOffetY = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view].y;
-        contentOffetY += offset * scaleFactor;
-        
-        if (scrollView.contentSize.height >= scrollView.frame.size.height && contentOffetY > scrollView.contentSize.height - scrollView.frame.size.height) {
-            contentOffset.y = scrollView.contentSize.height - scrollView.frame.size.height;
-        } else {
-            contentOffset.y = contentOffetY;
-        }
-    }
-    
-    [scrollView setContentOffset:contentOffset animated:animated];
-}
-
-- (BOOL)isNeedLoadMore
-{
-    if (WXScrollDirectionVertical == _scrollDirection) {
-        if (_loadMoreOffset >= 0.0 && ((UIScrollView *)self.view).contentOffset.y >= 0) {
-            return _previousLoadMoreContentHeight != ((UIScrollView *)self.view).contentSize.height && ((UIScrollView *)self.view).contentSize.height - ((UIScrollView *)self.view).contentOffset.y -  self.view.frame.size.height <= _loadMoreOffset;
-        }
-    } else if (WXScrollDirectionHorizontal == _scrollDirection) {
-        if (_loadMoreOffset >= 0.0 && ((UIScrollView *)self.view).contentOffset.x >= 0) {
-            return _previousLoadMoreContentHeight != ((UIScrollView *)self.view).contentSize.width && ((UIScrollView *)self.view).contentSize.width - ((UIScrollView *)self.view).contentOffset.x -  self.view.frame.size.width <= _loadMoreOffset;
-        }
-    }
-    
-    return NO;
-}
-
-- (void)loadMore
-{
-    [self fireEvent:@"loadmore" params:nil];
-    
-    if (WXScrollDirectionVertical == _scrollDirection) {
-        _previousLoadMoreContentHeight = ((UIScrollView *)self.view).contentSize.height;
-    } else if (WXScrollDirectionHorizontal == _scrollDirection) {
-        _previousLoadMoreContentHeight = ((UIScrollView *)self.view).contentSize.width;
-    }
-}
-
-- (CGPoint)contentOffset
-{
-    CGPoint rtv = CGPointZero;
-    UIScrollView *scrollView = (UIScrollView *)self.view;
-    if (scrollView) {
-        rtv = scrollView.contentOffset;
-    }
-    return rtv;
-}
-
-- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
-{
-    UIScrollView *scrollView = (UIScrollView *)self.view;
-    [scrollView setContentOffset:contentOffset animated:animated];
-}
-
-- (CGSize)contentSize
-{
-    return ((UIScrollView *)self.view).contentSize;
-}
-
-- (void)setContentSize:(CGSize)size
-{
-    UIScrollView *scrollView = (UIScrollView *)self.view;
-    scrollView.contentSize = size;
-}
-
-- (UIEdgeInsets)contentInset
-{
-    UIEdgeInsets rtv = UIEdgeInsetsZero;
-    UIScrollView *scrollView = (UIScrollView *)self.view;
-    if (scrollView) {
-        rtv = scrollView.contentInset;
-    }
-    return rtv;
-}
-
-- (void)setContentInset:(UIEdgeInsets)contentInset
-{
-    UIScrollView *scrollView = (UIScrollView *)self.view;
-    [scrollView setContentInset:contentInset];
-}
-
-- (void)addScrollDelegate:(id<UIScrollViewDelegate>)delegate
-{
-    if (delegate) {
-        if (!_delegates) {
-            _delegates = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
-        }
-        [_delegates addObject:delegate];
-    }
-}
-
-- (void)removeScrollDelegate:(id<UIScrollViewDelegate>)delegate
-{
-    if (delegate) {
-        [_delegates removeObject:delegate];
-    }
-}
-
-- (WXScrollDirection)scrollDirection
-{
-    return _scrollDirection;
-}
-
-- (NSString*)refreshType
-{
-    return _refreshType;
-}
-- (BOOL)requestGestureShouldStopPropagation:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
-{
-    return [self gestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
-}
-
-#pragma mark UIScrollViewDelegate
-- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
-{
-    if ([_refreshType isEqualToString:@"refreshForAppear"] && _refreshComponent) {
-        [_refreshComponent setIndicatorHidden:NO];
-    }
-    
-    if (_scrollStartEvent) {
-        CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
-        NSDictionary *contentSizeData = @{@"width":[NSNumber numberWithFloat:scrollView.contentSize.width / scaleFactor],@"height":[NSNumber numberWithFloat:scrollView.contentSize.height / scaleFactor]};
-        NSDictionary *contentOffsetData = @{@"x":[NSNumber numberWithFloat:-scrollView.contentOffset.x / scaleFactor],@"y":[NSNumber numberWithFloat:-scrollView.contentOffset.y / scaleFactor]};
-        [self fireEvent:@"scrollstart" params:@{@"contentSize":contentSizeData,@"contentOffset":contentOffsetData} domChanges:nil];
-    }
-}
-
-- (void)scrollViewDidScroll:(UIScrollView *)scrollView
-{
-    //apply block which are registered
-    WXSDKInstance *instance = self.weexInstance;
-    if ([self.ref isEqualToString:WX_SDK_ROOT_REF] &&
-        [self isKindOfClass:[WXScrollerComponent class]]) {
-        if (instance.onScroll) {
-            instance.onScroll(scrollView.contentOffset);
-        }
-    }
-    
-    if (_lastContentOffset.x > scrollView.contentOffset.x) {
-        _direction = @"right";
-    } else if (_lastContentOffset.x < scrollView.contentOffset.x) {
-        _direction = @"left";
-        if (WXScrollDirectionHorizontal == _scrollDirection) {
-            [self handleLoadMore];
-        }
-    } else if(_lastContentOffset.y > scrollView.contentOffset.y) {
-        _direction = @"down";
-    } else if(_lastContentOffset.y < scrollView.contentOffset.y) {
-        _direction = @"up";
-        if (WXScrollDirectionVertical == _scrollDirection) {
-            [self handleLoadMore];
-        }
-    }
-    
-    CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
-    [_refreshComponent pullingdown:@{
-             REFRESH_DISTANCE_Y: @(fabs((scrollView.contentOffset.y - _lastContentOffset.y)/scaleFactor)),
-             REFRESH_VIEWHEIGHT: @(_refreshComponent.view.frame.size.height/scaleFactor),
-             REFRESH_PULLINGDISTANCE: @(scrollView.contentOffset.y/scaleFactor),
-             @"type":@"pullingdown"
-    }];
-    _lastContentOffset = scrollView.contentOffset;
-    // check sticky
-    [self adjustSticky];
-    [self handleAppear];
-    
-    if (self.onScroll) {
-        self.onScroll(scrollView);
-    }
-    if (_scrollEvent) {
-        NSDictionary *contentSizeData = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:scrollView.contentSize.width / scaleFactor],@"width",[NSNumber numberWithFloat:scrollView.contentSize.height / scaleFactor],@"height", nil];
-        //contentOffset values are replaced by (-contentOffset.x,-contentOffset.y) ,in order to be consistent with Android client.
-        NSDictionary *contentOffsetData = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:-scrollView.contentOffset.x / scaleFactor],@"x",[NSNumber numberWithFloat:-scrollView.contentOffset.y / scaleFactor],@"y", nil];
-        CGFloat distance = 0;
-        if (_scrollDirection == WXScrollDirectionHorizontal) {
-            distance = scrollView.contentOffset.x - _lastScrollEventFiredOffset.x;
-        } else {
-            distance = scrollView.contentOffset.y - _lastScrollEventFiredOffset.y;
-        }
-        if (fabs(distance) >= _offsetAccuracy) {
-            [self fireEvent:@"scroll" params:@{@"contentSize":contentSizeData,@"contentOffset":contentOffsetData} domChanges:nil];
-            _lastScrollEventFiredOffset = scrollView.contentOffset;
-        }
-    }
-    NSHashTable *delegates = [_delegates copy];
-    for (id<UIScrollViewDelegate> delegate in delegates) {
-        if ([delegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
-            [delegate scrollViewDidScroll:scrollView];
-        }
-    }
-}
-
-- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
-{
-    UIEdgeInsets inset = [scrollView contentInset];
-    
-//  currently only set contentInset when loading
-//    if ([_refreshComponent displayState]) {
-//        inset.top = _refreshComponent.view.frame.size.height;
-//    }
-//    else {
-//        inset.top = 0;
-//    }
-    
-    if ([_loadingComponent displayState]) {
-        inset.bottom = _loadingComponent.view.frame.size.height;
-    } else {
-        inset.bottom = 0;
-    }
-    [scrollView setContentInset:inset];
-}
-
-- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
-{
-    if (_scrollEndEvent) {
-        if (!_isScrolling) {
-            CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
-            NSDictionary *contentSizeData = @{@"width":[NSNumber numberWithFloat:scrollView.contentSize.width / scaleFactor],@"height":[NSNumber numberWithFloat:scrollView.contentSize.height / scaleFactor]};
-            NSDictionary *contentOffsetData = @{@"x":[NSNumber numberWithFloat:-scrollView.contentOffset.x / scaleFactor],@"y":[NSNumber numberWithFloat:-scrollView.contentOffset.y / scaleFactor]};
-            [self fireEvent:@"scrollend" params:@{@"contentSize":contentSizeData,@"contentOffset":contentOffsetData} domChanges:nil];
-        }
-    }
-}
-
-- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
-{
-    if ([_refreshType isEqualToString:@"refreshForAppear"]) {
-        if(targetContentOffset == nil)
-            return;
-        CGPoint offset = *targetContentOffset;
-        if(velocity.y <= 0) {
-            // drop down
-            if( offset.y <= _refreshComponent.calculatedFrame.size.height ) {
-                [self loadMoreIfNeed];
-            }
-        } else if (velocity.y > 0) {
-            // drop up
-        }
-    }
-}
-
-- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
-{
-    [_loadingComponent.view setHidden:NO];
-    [_refreshComponent.view setHidden:NO];
-    
-    //refresh
-    if ([_refreshType isEqualToString:@"refreshForWholeVisible"]) {
-        if (_refreshComponent && scrollView.contentOffset.y < 0 && scrollView.contentOffset.y + _refreshComponent.calculatedFrame.size.height < _refreshComponent.calculatedFrame.origin.y) {
-            [_refreshComponent refresh];
-        }
-    }
-    
-    //loading
-    if (_loadingComponent && scrollView.contentOffset.y > 0 &&
-        scrollView.contentOffset.y + scrollView.frame.size.height > _loadingComponent.view.frame.origin.y + _loadingComponent.calculatedFrame.size.height) {
-        [_loadingComponent loading];
-    }
-    if (!decelerate) {
-        _isScrolling = NO;
-        [self performSelector:@selector(scrollViewDidEndDecelerating:) withObject:nil afterDelay:0.1];
-    }
-}
-
-- (void)loadMoreIfNeed
-{
-    WXScrollerComponentView* scrollView = (WXScrollerComponentView *)self.view;
-    if (scrollView.isDragging || scrollView.isTracking || scrollView.isDecelerating) {
-        [self performSelector:@selector(loadMoreIfNeed) withObject:nil afterDelay:0.1];
-        return;
-    }
-    [_refreshComponent refresh];
-}
-
-- (void)handleAppear
-{
-    if (![self isViewLoaded]) {
-        return;
-    }
-    UIScrollView *scrollView = (UIScrollView *)self.view;
-    CGFloat vx = scrollView.contentInset.left + scrollView.contentOffset.x;
-    CGFloat vy = scrollView.contentInset.top + scrollView.contentOffset.y;
-    CGFloat vw = scrollView.frame.size.width - scrollView.contentInset.left - scrollView.contentInset.right;
-    CGFloat vh = scrollView.frame.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom;
-    CGRect scrollRect = CGRectMake(vx, vy, vw, vh);;
-    
-    // notify action for appear
-    NSArray *listenerArrayCopy = [self.listenerArray copy];
-    for(WXScrollToTarget *target in listenerArrayCopy){
-        if (_shouldNotifiAppearDescendantView) {
-            // if target component is descendant of scrollerview, it should notify the appear event handler, or here will skip this appear calculation.
-            if ([target.target isViewLoaded] && [target.target.view isDescendantOfView:self.view]) {
-                [self scrollToTarget:target scrollRect:scrollRect];
-            }
-        } else {
-            [self scrollToTarget:target scrollRect:scrollRect];
-        }
-    }
-}
-
-- (CGPoint)absolutePositionForComponent:(WXComponent *)component
-{
-    return [component->_view.superview convertPoint:component->_view.frame.origin toView:_view];
-}
-
-#pragma mark  Private Methods
-
-- (void)scrollToTarget:(WXScrollToTarget *)target scrollRect:(CGRect)rect
-{
-    WXComponent *component = target.target;
-    if (![component isViewLoaded]) { 
-        return;
-    }
-    
-    CGFloat ctop;
-    if (component && component->_view && component->_view.superview) {
-        ctop = [self absolutePositionForComponent:component].y;
-    } else {
-        ctop = 0.0;
-    }
-    CGFloat cbottom = ctop + CGRectGetHeight(component.calculatedFrame);
-    CGFloat cleft;
-    if (component && component->_view && component->_view.superview) {
-        cleft = [self absolutePositionForComponent:component].x;
-    } else {
-        cleft = 0.0;
-    }
-    CGFloat cright = cleft + CGRectGetWidth(component.calculatedFrame);
-    
-    CGFloat vtop = CGRectGetMinY(rect), vbottom = CGRectGetMaxY(rect), vleft = CGRectGetMinX(rect), vright = CGRectGetMaxX(rect);
-    if(cbottom > vtop && ctop <= vbottom && cleft <= vright && cright > vleft){
-        if(!target.hasAppear && component){
-            target.hasAppear = YES;
-            if (component->_appearEvent) {
-//                NSLog(@"appear:%@, %.2f", component, ctop);
-                [component fireEvent:@"appear" params:_direction ? @{@"direction":_direction} : nil];
-            }
-        }
-    } else {
-        if(target.hasAppear && component){
-            target.hasAppear = NO;
-            if(component->_disappearEvent){
-//                NSLog(@"disappear:%@", component);
-                [component fireEvent:@"disappear" params:_direction ? @{@"direction":_direction} : nil];
-            }
-        }
-    }
-}
-
-- (void)handleLoadMore
-{
-    if (_listenLoadMore && [self isNeedLoadMore]) {
-        [self loadMore];
-    }
-}
-
-#pragma mark Layout
-
-- (NSUInteger)_childrenCountForLayout;
-{
-    return 0;
-}
-
-- (NSUInteger)childrenCountForScrollerLayout
-{
-    return [super _childrenCountForLayout];
-}
-
-- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition
-                          gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
-{
-    /**
-     *  Pretty hacky way
-     *  layout from root to scroller to get scroller's frame,
-     *  layout from children to scroller to get scroller's contentSize
-     */
-    if ([self needsLayout]) {
-        memcpy(_scrollerCSSNode, self.cssNode, sizeof(css_node_t));
-        _scrollerCSSNode->children_count = (int)[self childrenCountForScrollerLayout];
-        
-        _scrollerCSSNode->style.position[CSS_LEFT] = 0;
-        _scrollerCSSNode->style.position[CSS_TOP] = 0;
-        
-        if (_scrollDirection == WXScrollDirectionVertical) {
-            _scrollerCSSNode->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
-            _scrollerCSSNode->style.dimensions[CSS_WIDTH] = _cssNode->layout.dimensions[CSS_WIDTH];
-            _scrollerCSSNode->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
-        } else {
-            _scrollerCSSNode->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
-            _scrollerCSSNode->style.dimensions[CSS_HEIGHT] = _cssNode->layout.dimensions[CSS_HEIGHT];
-            _scrollerCSSNode->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
-        }
-        
-        _scrollerCSSNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
-        _scrollerCSSNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
-        
-        layoutNode(_scrollerCSSNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
-        if ([WXLog logLevel] >= WXLogLevelDebug) {
-            print_css_node(_scrollerCSSNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
-        }
-        CGSize size = {
-            WXRoundPixelValue(_scrollerCSSNode->layout.dimensions[CSS_WIDTH]),
-            WXRoundPixelValue(_scrollerCSSNode->layout.dimensions[CSS_HEIGHT])
-        };
-
-        if (!CGSizeEqualToSize(size, _contentSize)) {
-            // content size
-            _contentSize = size;
-            [dirtyComponents addObject:self];
-        }
-        
-        _scrollerCSSNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
-        _scrollerCSSNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
-    }
-    
-    [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
new file mode 100644
index 0000000..215d9ff
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
@@ -0,0 +1,951 @@
+/*
+ * 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 "WXScrollerComponent.h"
+#import "WXComponent_internal.h"
+#import "WXComponent.h"
+#import "WXDefine.h"
+#import "WXConvert.h"
+#import "WXSDKInstance.h"
+#import "WXUtility.h"
+#import "WXLoadingComponent.h"
+#import "WXRefreshComponent.h"
+#import "WXConfigCenterProtocol.h"
+#import "WXSDKEngine.h"
+#import "WXComponent+Events.h"
+#import "WXScrollerComponent+Layout.h"
+#import "WXCoreLayout.h"
+
+@interface WXScrollerComponentView:UIScrollView
+@end
+
+@implementation WXScrollerComponentView
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
+{
+    if ([(id <WXScrollerProtocol>) self.wx_component respondsToSelector:@selector(requestGestureShouldStopPropagation:shouldReceiveTouch:)]) {
+        return [(id <WXScrollerProtocol>) self.wx_component requestGestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
+    }
+    else{
+        return YES;
+    }
+}
+@end
+
+@interface WXScrollToTarget : NSObject
+
+@property (nonatomic, weak)   WXComponent *target;
+@property (nonatomic, assign) BOOL hasAppear;
+
+@end
+
+@implementation WXScrollToTarget
+
+@end
+
+
+@interface WXScrollerComponent()
+
+@property (nonatomic, strong) NSMutableArray *  stickyArray;
+@property (nonatomic, strong) NSMutableArray * listenerArray;
+@property (nonatomic, weak) WXRefreshComponent *refreshComponent;
+@property (nonatomic, weak) WXLoadingComponent *loadingComponent;
+
+@end
+
+@implementation WXScrollerComponent
+{
+    CGSize _contentSize;
+    BOOL _listenLoadMore;
+    BOOL _scrollEvent;
+    BOOL _scrollStartEvent;
+    BOOL _scrollEndEvent;
+    BOOL _isScrolling;
+    CGFloat _loadMoreOffset;
+    CGFloat _previousLoadMoreContentHeight;
+    CGFloat _offsetAccuracy;
+    CGPoint _lastContentOffset;
+    CGPoint _lastScrollEventFiredOffset;
+    BOOL _scrollable;
+    NSString * _alwaysScrollableVertical;
+    NSString * _alwaysScrollableHorizontal;
+    BOOL _bounces;
+    
+    // refreshForAppear: load more when refresh component begin appear(if scroll is dragging or decelerating, should delay)
+    // refreshForWholeVisible: load more until the whole refresh component visible
+    NSString *_refreshType;
+
+    // vertical & horizontal
+    WXScrollDirection _scrollDirection;
+    // left & right & up & down
+    NSString *_direction;
+    BOOL _showScrollBar;
+    BOOL _pagingEnabled;
+    
+    BOOL _shouldNotifiAppearDescendantView;
+    BOOL _shouldRemoveScrollerListener;
+
+    //css_node_t *_scrollerCSSNode;
+    
+    NSHashTable* _delegates;
+}
+
+WX_EXPORT_METHOD(@selector(resetLoadmore))
+
+- (void)resetLoadmore
+{
+    _previousLoadMoreContentHeight=0;
+}
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    [super _insertSubcomponent:subcomponent atIndex:index];
+    
+    if ([subcomponent isKindOfClass:[WXRefreshComponent class]]) {
+        _refreshComponent = (WXRefreshComponent*)subcomponent;
+    }
+    else if ([subcomponent isKindOfClass:[WXLoadingComponent class]]) {
+        _loadingComponent = (WXLoadingComponent*)subcomponent;
+    }
+}
+
+-(instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        
+        _stickyArray = [NSMutableArray array];
+        _listenerArray = [NSMutableArray array];
+        _scrollEvent = NO;
+        _scrollStartEvent = NO;
+        _scrollEndEvent = NO;
+        _lastScrollEventFiredOffset = CGPointMake(0, 0);
+        _scrollDirection = attributes[@"scrollDirection"] ? [WXConvert WXScrollDirection:attributes[@"scrollDirection"]] : WXScrollDirectionVertical;
+        _showScrollBar = attributes[@"showScrollbar"] ? [WXConvert BOOL:attributes[@"showScrollbar"]] : YES;
+        
+        if (attributes[@"alwaysScrollableVertical"]) {
+            _alwaysScrollableVertical = [WXConvert NSString:attributes[@"alwaysScrollableVertical"]];
+        }
+        if (attributes[@"alwaysScrollableHorizontal"]) {
+            _alwaysScrollableHorizontal = [WXConvert NSString:attributes[@"alwaysScrollableHorizontal"]];
+        }
+        _bounces = attributes[@"bounce"]?[WXConvert BOOL:attributes[@"bounce"]]:YES;
+        _refreshType = [WXConvert NSString:attributes[@"refreshType"]]?:@"refreshForWholeVisible";
+        _pagingEnabled = attributes[@"pagingEnabled"] ? [WXConvert BOOL:attributes[@"pagingEnabled"]] : NO;
+        _loadMoreOffset = attributes[@"loadmoreoffset"] ? [WXConvert WXPixelType:attributes[@"loadmoreoffset"] scaleFactor:self.weexInstance.pixelScaleFactor] : 0;
+        _loadmoreretry = attributes[@"loadmoreretry"] ? [WXConvert NSUInteger:attributes[@"loadmoreretry"]] : 0;
+        _listenLoadMore = [events containsObject:@"loadmore"];
+        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
+        _offsetAccuracy = attributes[@"offsetAccuracy"] ? [WXConvert WXPixelType:attributes[@"offsetAccuracy"] scaleFactor:self.weexInstance.pixelScaleFactor] : 0;
+        
+//#ifndef USE_FLEX
+        if(![WXComponent isUseFlex])
+        {
+            _scrollerCSSNode = new_css_node();
+            
+            // let scroller fill the rest space if it is a child component and has no fixed height & width
+            if (((_scrollDirection == WXScrollDirectionVertical &&
+                  isUndefined(self.cssNode->style.dimensions[CSS_HEIGHT])) ||
+                 (_scrollDirection == WXScrollDirectionHorizontal &&
+                  isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]))) &&
+                self.cssNode->style.flex <= 0.0) {
+                self.cssNode->style.flex = 1.0;
+            }
+        }
+//#else
+        else
+        {
+            _flexScrollerCSSNode = new WeexCore::WXCoreLayoutNode();
+            // let scroller fill the rest space if it is a child component and has no fixed height & width
+            if (((_scrollDirection == WXScrollDirectionVertical &&
+                  flexIsUndefined(self.flexCssNode->getStyleHeight())) ||
+                 (_scrollDirection == WXScrollDirectionHorizontal &&
+                  flexIsUndefined(self.flexCssNode->getStyleWidth()))) &&
+                self.flexCssNode->getFlex() <= 0.0) {
+                self.flexCssNode->setFlex(1.0);
+            }
+        }
+//#endif
+        id configCenter = [WXSDKEngine handlerForProtocol:@protocol(WXConfigCenterProtocol)];
+        if ([configCenter respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) {
+            BOOL shouldNotifiAppearDescendantView = [[configCenter configForKey:@"iOS_weex_ext_config.shouldNotifiAppearDescendantView" defaultValue:@(YES) isDefault:NULL] boolValue];
+            _shouldNotifiAppearDescendantView = shouldNotifiAppearDescendantView;
+            BOOL shouldRemoveScrollerListener = [[configCenter configForKey:@"iOS_weex_ext_config.shouldRemoveScrollerListener" defaultValue:@(YES) isDefault:NULL] boolValue];
+            _shouldRemoveScrollerListener = shouldRemoveScrollerListener;
+            
+        }
+    }
+    
+    return self;
+}
+
+- (UIView *)loadView
+{
+    return [[WXScrollerComponentView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    [self setContentSize:_contentSize];
+    WXScrollerComponentView* scrollView = (WXScrollerComponentView *)self.view;
+    scrollView.delegate = self;
+    scrollView.exclusiveTouch = YES;
+    scrollView.autoresizesSubviews = NO;
+    scrollView.clipsToBounds = YES;
+    scrollView.showsVerticalScrollIndicator = _showScrollBar;
+    scrollView.showsHorizontalScrollIndicator = _showScrollBar;
+    scrollView.scrollEnabled = _scrollable;
+    scrollView.pagingEnabled = _pagingEnabled;
+    
+    if (scrollView.bounces != _bounces) {
+        scrollView.bounces = _bounces;
+    }
+    
+    if (_alwaysScrollableHorizontal) {
+        scrollView.alwaysBounceHorizontal = [WXConvert BOOL:_alwaysScrollableHorizontal];
+    }
+    if (_alwaysScrollableVertical) {
+        scrollView.alwaysBounceVertical = [WXConvert BOOL:_alwaysScrollableVertical];
+    }
+    
+    if (@available(iOS 11.0, *)) {
+        if ([scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
+            scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+        }
+    } else {
+        // Fallback on earlier versions
+    }
+    
+    if (self.ancestorScroller) {
+        scrollView.scrollsToTop = NO;
+    } else {
+        scrollView.scrollsToTop = YES;
+    }
+}
+
+- (void)layoutDidFinish
+{
+
+    
+    if ([self isViewLoaded]) {
+        [self setContentSize:_contentSize];
+        [self adjustSticky];
+        [self handleAppear];
+    }
+    
+    [_loadingComponent resizeFrame];
+}
+
+- (void)viewWillUnload
+{
+    ((UIScrollView *)_view).delegate = nil;
+}
+
+- (void)dealloc
+{
+    ((UIScrollView *)_view).delegate = nil;
+    [self.stickyArray removeAllObjects];
+    [self.listenerArray removeAllObjects];
+//#ifndef USE_FLEX
+    if (![WXComponent isUseFlex]) {
+         free(_scrollerCSSNode);
+    }
+//#else
+    else
+    {
+        if(_flexScrollerCSSNode){
+            delete _flexScrollerCSSNode;
+            
+            //WeexCore::WXCoreLayoutNode::freeNodeTree(_flexScrollerCSSNode);
+            
+            _flexScrollerCSSNode=nullptr;
+        }
+    }
+//#endif
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"showScrollbar"]) {
+        _showScrollBar = [WXConvert BOOL:attributes[@"showScrollbar"]];
+        ((UIScrollView *)self.view).showsHorizontalScrollIndicator = _showScrollBar;
+        ((UIScrollView *)self.view).showsVerticalScrollIndicator = _showScrollBar;
+    }
+    
+    if (attributes[@"pagingEnabled"]) {
+        _pagingEnabled = [WXConvert BOOL:attributes[@"pagingEnabled"]];
+        ((UIScrollView *)self.view).pagingEnabled = _pagingEnabled;
+    }
+    
+    if (attributes[@"loadmoreoffset"]) {
+        _loadMoreOffset = [WXConvert WXPixelType:attributes[@"loadmoreoffset"] scaleFactor:self.weexInstance.pixelScaleFactor];
+    }
+    if (attributes[@"bounce"]) {
+        _bounces = [WXConvert BOOL:attributes[@"bounce"]];
+        ((UIScrollView *)self.view).bounces = _bounces;
+    }
+    
+    if (attributes[@"loadmoreretry"]) {
+        NSUInteger loadmoreretry = [WXConvert NSUInteger:attributes[@"loadmoreretry"]];
+        if (loadmoreretry != _loadmoreretry) {
+            _previousLoadMoreContentHeight = 0;
+        }
+        self.loadmoreretry = loadmoreretry;
+    }
+    if (attributes[@"scrollable"]) {
+        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
+        ((UIScrollView *)self.view).scrollEnabled = _scrollable;
+    }
+    if (attributes[@"alwaysScrollableHorizontal"]) {
+        _alwaysScrollableHorizontal = [WXConvert NSString:attributes[@"alwaysScrollableHorizontal"]];
+        ((UIScrollView*)self.view).alwaysBounceHorizontal = [WXConvert BOOL:_alwaysScrollableHorizontal];
+    }
+    
+    if (attributes[@"alwaysScrollableVertical"]) {
+        _alwaysScrollableVertical = [WXConvert NSString:attributes[@"alwaysScrollableVertical"]];
+        ((UIScrollView*)self.view).alwaysBounceVertical = [WXConvert BOOL:_alwaysScrollableVertical];
+    }
+    
+    if (attributes[@"refreshType"]) {
+        _refreshType = [WXConvert NSString:attributes[@"refreshType"]];
+    }
+    
+    if (attributes[@"offsetAccuracy"]) {
+        _offsetAccuracy = [WXConvert WXPixelType:attributes[@"offsetAccuracy"] scaleFactor:self.weexInstance.pixelScaleFactor];
+    }
+    
+    if (attributes[@"scrollDirection"]) {
+        _scrollDirection = attributes[@"scrollDirection"] ? [WXConvert WXScrollDirection:attributes[@"scrollDirection"]] : WXScrollDirectionVertical;
+    }
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"loadmore"]) {
+        _listenLoadMore = YES;
+    }
+    if ([eventName isEqualToString:@"scroll"]) {
+        _scrollEvent = YES;
+    }
+    if ([eventName isEqualToString:@"scrollstart"]) {
+        _scrollStartEvent = YES;
+    }
+    if ([eventName isEqualToString:@"scrollend"]) {
+        _scrollEndEvent = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"loadmore"]) {
+        _listenLoadMore = NO;
+    }
+    if ([eventName isEqualToString:@"scroll"]) {
+        _scrollEvent = NO;
+    }
+    if ([eventName isEqualToString:@"scrollstart"]) {
+        _scrollStartEvent = NO;
+    }
+    if ([eventName isEqualToString:@"scrollend"]) {
+        _scrollEndEvent = NO;
+    }
+}
+
+#pragma mark WXScrollerProtocol
+
+- (void)addStickyComponent:(WXComponent *)sticky
+{
+    if(![self.stickyArray containsObject:sticky]) {
+        [self.stickyArray addObject:sticky];
+        [self adjustSticky];
+    }
+}
+
+- (void)removeStickyComponent:(WXComponent *)sticky
+{
+    if([self.stickyArray containsObject:sticky]) {
+        [self.stickyArray removeObject:sticky];
+        [self adjustSticky];
+    }
+}
+
+- (void)adjustSticky
+{
+    if (![self isViewLoaded]) {
+        return;
+    }
+    CGFloat scrollOffsetY = ((UIScrollView *)self.view).contentOffset.y;
+    for(WXComponent *component in self.stickyArray) {
+        if (isnan(component->_absolutePosition.x) && isnan(component->_absolutePosition.y)) {
+            component->_absolutePosition = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view];
+        }
+        CGPoint relativePosition = component->_absolutePosition;
+        if (isnan(relativePosition.y)) {
+            continue;
+        }
+        
+        WXComponent *supercomponent = component.supercomponent;
+        if(supercomponent != self && component.view.superview != self.view) {
+            [component.view removeFromSuperview];
+            [self.view addSubview:component.view];
+        } else {
+            [self.view bringSubviewToFront:component.view];
+        }
+        
+        CGFloat relativeY = relativePosition.y;
+        BOOL needSticky = NO;
+        
+        if (scrollOffsetY >= relativeY) {
+            needSticky = YES;
+        } else {
+            // important: reset views' frame
+            component.view.frame = CGRectMake(relativePosition.x, relativePosition.y, component.calculatedFrame.size.width, component.calculatedFrame.size.height);
+        }
+        
+        if (!needSticky) {
+            continue;
+        }
+        
+        // The minimum Y sticky view can reach is its original position
+        CGFloat minY = relativeY;
+        CGPoint superRelativePosition = supercomponent == self ? CGPointZero : [supercomponent.supercomponent.view convertPoint:supercomponent.view.frame.origin toView:self.view];
+        CGFloat maxY = superRelativePosition.y + supercomponent.calculatedFrame.size.height - component.calculatedFrame.size.height;
+        
+        CGFloat stickyY = scrollOffsetY;
+        if (stickyY < minY) {
+            stickyY = minY;
+        } else if (stickyY > maxY && ![supercomponent conformsToProtocol:@protocol(WXScrollerProtocol)]) {
+            // Sticky component can not go beyond its parent's bounds when its parent is not scroller;
+            stickyY = maxY;
+        }
+        
+        UIView *stickyView = component.view;
+        CGPoint origin = stickyView.frame.origin;
+        origin.y = stickyY;
+        stickyView.frame = (CGRect){origin,stickyView.frame.size};
+    }
+}
+
+- (void)addScrollToListener:(WXComponent *)target
+{
+    BOOL has = NO;
+    NSMutableArray *listenerArray = [self.listenerArray copy];
+    for (WXScrollToTarget *targetData in listenerArray) {
+        if (targetData.target == target) {
+            has = YES;
+            break;
+        }
+    }
+    if (!has) {
+        WXScrollToTarget *scrollTarget = [[WXScrollToTarget alloc] init];
+        scrollTarget.target = target;
+        scrollTarget.hasAppear = NO;
+        [self.listenerArray addObject:scrollTarget];
+    }
+}
+
+- (void)removeScrollToListener:(WXComponent *)target
+{
+    if (_shouldRemoveScrollerListener) {
+        WXScrollToTarget *targetData = nil;
+        NSMutableArray *listenerArray = [self.listenerArray copy];
+        for (WXScrollToTarget *targetDataTemp in listenerArray) {
+            if (targetDataTemp.target == target) {
+                targetData = targetDataTemp;
+                break;
+            }
+        }
+        if(targetData) {
+            [self.listenerArray removeObject:targetData];
+        }
+    }
+}
+
+- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset animated:(BOOL)animated
+{
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+
+    CGPoint contentOffset = scrollView.contentOffset;
+    CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
+    
+    if (_scrollDirection == WXScrollDirectionHorizontal) {
+        CGFloat contentOffetX = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view].x;
+        contentOffetX += offset * scaleFactor;
+        
+        if (scrollView.contentSize.width >= scrollView.frame.size.width && contentOffetX > scrollView.contentSize.width - scrollView.frame.size.width) {
+            contentOffset.x = scrollView.contentSize.width - scrollView.frame.size.width;
+        } else {
+            contentOffset.x = contentOffetX;
+        }
+    } else {
+        CGFloat contentOffetY = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view].y;
+        contentOffetY += offset * scaleFactor;
+        
+        if (scrollView.contentSize.height >= scrollView.frame.size.height && contentOffetY > scrollView.contentSize.height - scrollView.frame.size.height) {
+            contentOffset.y = scrollView.contentSize.height - scrollView.frame.size.height;
+        } else {
+            contentOffset.y = contentOffetY;
+        }
+    }
+    
+    [scrollView setContentOffset:contentOffset animated:animated];
+}
+
+- (BOOL)isNeedLoadMore
+{
+    if (WXScrollDirectionVertical == _scrollDirection) {
+        if (_loadMoreOffset >= 0.0 && ((UIScrollView *)self.view).contentOffset.y >= 0) {
+            return _previousLoadMoreContentHeight != ((UIScrollView *)self.view).contentSize.height && ((UIScrollView *)self.view).contentSize.height - ((UIScrollView *)self.view).contentOffset.y -  self.view.frame.size.height <= _loadMoreOffset;
+        }
+    } else if (WXScrollDirectionHorizontal == _scrollDirection) {
+        if (_loadMoreOffset >= 0.0 && ((UIScrollView *)self.view).contentOffset.x >= 0) {
+            return _previousLoadMoreContentHeight != ((UIScrollView *)self.view).contentSize.width && ((UIScrollView *)self.view).contentSize.width - ((UIScrollView *)self.view).contentOffset.x -  self.view.frame.size.width <= _loadMoreOffset;
+        }
+    }
+    
+    return NO;
+}
+
+- (void)loadMore
+{
+    [self fireEvent:@"loadmore" params:nil];
+    
+    if (WXScrollDirectionVertical == _scrollDirection) {
+        _previousLoadMoreContentHeight = ((UIScrollView *)self.view).contentSize.height;
+    } else if (WXScrollDirectionHorizontal == _scrollDirection) {
+        _previousLoadMoreContentHeight = ((UIScrollView *)self.view).contentSize.width;
+    }
+}
+
+- (CGPoint)contentOffset
+{
+    CGPoint rtv = CGPointZero;
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    if (scrollView) {
+        rtv = scrollView.contentOffset;
+    }
+    return rtv;
+}
+
+- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
+{
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    [scrollView setContentOffset:contentOffset animated:animated];
+}
+
+- (CGSize)contentSize
+{
+    return ((UIScrollView *)self.view).contentSize;
+}
+
+- (void)setContentSize:(CGSize)size
+{
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    scrollView.contentSize = size;
+}
+
+- (UIEdgeInsets)contentInset
+{
+    UIEdgeInsets rtv = UIEdgeInsetsZero;
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    if (scrollView) {
+        rtv = scrollView.contentInset;
+    }
+    return rtv;
+}
+
+- (void)setContentInset:(UIEdgeInsets)contentInset
+{
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    [scrollView setContentInset:contentInset];
+}
+
+- (void)addScrollDelegate:(id<UIScrollViewDelegate>)delegate
+{
+    if (delegate) {
+        if (!_delegates) {
+            _delegates = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
+        }
+        [_delegates addObject:delegate];
+    }
+}
+
+- (void)removeScrollDelegate:(id<UIScrollViewDelegate>)delegate
+{
+    if (delegate) {
+        [_delegates removeObject:delegate];
+    }
+}
+
+- (WXScrollDirection)scrollDirection
+{
+    return _scrollDirection;
+}
+
+- (NSString*)refreshType
+{
+    return _refreshType;
+}
+- (BOOL)requestGestureShouldStopPropagation:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
+{
+    return [self gestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
+}
+
+#pragma mark UIScrollViewDelegate
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
+{
+    if ([_refreshType isEqualToString:@"refreshForAppear"] && _refreshComponent) {
+        [_refreshComponent setIndicatorHidden:NO];
+    }
+    
+    if (_scrollStartEvent) {
+        CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
+        NSDictionary *contentSizeData = @{@"width":[NSNumber numberWithFloat:scrollView.contentSize.width / scaleFactor],@"height":[NSNumber numberWithFloat:scrollView.contentSize.height / scaleFactor]};
+        NSDictionary *contentOffsetData = @{@"x":[NSNumber numberWithFloat:-scrollView.contentOffset.x / scaleFactor],@"y":[NSNumber numberWithFloat:-scrollView.contentOffset.y / scaleFactor]};
+        [self fireEvent:@"scrollstart" params:@{@"contentSize":contentSizeData,@"contentOffset":contentOffsetData} domChanges:nil];
+    }
+}
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView
+{
+    //apply block which are registered
+    WXSDKInstance *instance = self.weexInstance;
+    if ([self.ref isEqualToString:WX_SDK_ROOT_REF] &&
+        [self isKindOfClass:[WXScrollerComponent class]]) {
+        if (instance.onScroll) {
+            instance.onScroll(scrollView.contentOffset);
+        }
+    }
+    
+    if (_lastContentOffset.x > scrollView.contentOffset.x) {
+        _direction = @"right";
+    } else if (_lastContentOffset.x < scrollView.contentOffset.x) {
+        _direction = @"left";
+        if (WXScrollDirectionHorizontal == _scrollDirection) {
+            [self handleLoadMore];
+        }
+    } else if(_lastContentOffset.y > scrollView.contentOffset.y) {
+        _direction = @"down";
+    } else if(_lastContentOffset.y < scrollView.contentOffset.y) {
+        _direction = @"up";
+        if (WXScrollDirectionVertical == _scrollDirection) {
+            [self handleLoadMore];
+        }
+    }
+    
+    CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
+    [_refreshComponent pullingdown:@{
+             REFRESH_DISTANCE_Y: @(fabs((scrollView.contentOffset.y - _lastContentOffset.y)/scaleFactor)),
+             REFRESH_VIEWHEIGHT: @(_refreshComponent.view.frame.size.height/scaleFactor),
+             REFRESH_PULLINGDISTANCE: @(scrollView.contentOffset.y/scaleFactor),
+             @"type":@"pullingdown"
+    }];
+    _lastContentOffset = scrollView.contentOffset;
+    // check sticky
+    [self adjustSticky];
+    [self handleAppear];
+    
+    if (self.onScroll) {
+        self.onScroll(scrollView);
+    }
+    if (_scrollEvent) {
+        NSDictionary *contentSizeData = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:scrollView.contentSize.width / scaleFactor],@"width",[NSNumber numberWithFloat:scrollView.contentSize.height / scaleFactor],@"height", nil];
+        //contentOffset values are replaced by (-contentOffset.x,-contentOffset.y) ,in order to be consistent with Android client.
+        NSDictionary *contentOffsetData = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:-scrollView.contentOffset.x / scaleFactor],@"x",[NSNumber numberWithFloat:-scrollView.contentOffset.y / scaleFactor],@"y", nil];
+        CGFloat distance = 0;
+        if (_scrollDirection == WXScrollDirectionHorizontal) {
+            distance = scrollView.contentOffset.x - _lastScrollEventFiredOffset.x;
+        } else {
+            distance = scrollView.contentOffset.y - _lastScrollEventFiredOffset.y;
+        }
+        if (fabs(distance) >= _offsetAccuracy) {
+            [self fireEvent:@"scroll" params:@{@"contentSize":contentSizeData,@"contentOffset":contentOffsetData} domChanges:nil];
+            _lastScrollEventFiredOffset = scrollView.contentOffset;
+        }
+    }
+    NSHashTable *delegates = [_delegates copy];
+    for (id<UIScrollViewDelegate> delegate in delegates) {
+        if ([delegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
+            [delegate scrollViewDidScroll:scrollView];
+        }
+    }
+}
+
+- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
+{
+    UIEdgeInsets inset = [scrollView contentInset];
+    
+//  currently only set contentInset when loading
+//    if ([_refreshComponent displayState]) {
+//        inset.top = _refreshComponent.view.frame.size.height;
+//    }
+//    else {
+//        inset.top = 0;
+//    }
+    
+    if ([_loadingComponent displayState]) {
+        inset.bottom = _loadingComponent.view.frame.size.height;
+    } else {
+        inset.bottom = 0;
+    }
+    [scrollView setContentInset:inset];
+}
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
+{
+    if (_scrollEndEvent) {
+        if (!_isScrolling) {
+            CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
+            NSDictionary *contentSizeData = @{@"width":[NSNumber numberWithFloat:scrollView.contentSize.width / scaleFactor],@"height":[NSNumber numberWithFloat:scrollView.contentSize.height / scaleFactor]};
+            NSDictionary *contentOffsetData = @{@"x":[NSNumber numberWithFloat:-scrollView.contentOffset.x / scaleFactor],@"y":[NSNumber numberWithFloat:-scrollView.contentOffset.y / scaleFactor]};
+            [self fireEvent:@"scrollend" params:@{@"contentSize":contentSizeData,@"contentOffset":contentOffsetData} domChanges:nil];
+        }
+    }
+}
+
+- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
+{
+    if ([_refreshType isEqualToString:@"refreshForAppear"]) {
+        if(targetContentOffset == nil)
+            return;
+        CGPoint offset = *targetContentOffset;
+        if(velocity.y <= 0) {
+            // drop down
+            if( offset.y <= _refreshComponent.calculatedFrame.size.height ) {
+                [self loadMoreIfNeed];
+            }
+        } else if (velocity.y > 0) {
+            // drop up
+        }
+    }
+}
+
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
+{
+    [_loadingComponent.view setHidden:NO];
+    [_refreshComponent.view setHidden:NO];
+    
+    //refresh
+    if ([_refreshType isEqualToString:@"refreshForWholeVisible"]) {
+        if (_refreshComponent && scrollView.contentOffset.y < 0 && scrollView.contentOffset.y + _refreshComponent.calculatedFrame.size.height < _refreshComponent.calculatedFrame.origin.y) {
+            [_refreshComponent refresh];
+        }
+    }
+    
+    //loading
+    if (_loadingComponent && scrollView.contentOffset.y > 0 &&
+        scrollView.contentOffset.y + scrollView.frame.size.height > _loadingComponent.view.frame.origin.y + _loadingComponent.calculatedFrame.size.height) {
+        [_loadingComponent loading];
+    }
+    if (!decelerate) {
+        _isScrolling = NO;
+        [self performSelector:@selector(scrollViewDidEndDecelerating:) withObject:nil afterDelay:0.1];
+    }
+}
+
+- (void)loadMoreIfNeed
+{
+    WXScrollerComponentView* scrollView = (WXScrollerComponentView *)self.view;
+    if (scrollView.isDragging || scrollView.isTracking || scrollView.isDecelerating) {
+        [self performSelector:@selector(loadMoreIfNeed) withObject:nil afterDelay:0.1];
+        return;
+    }
+    [_refreshComponent refresh];
+}
+
+- (void)handleAppear
+{
+    if (![self isViewLoaded]) {
+        return;
+    }
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    CGFloat vx = scrollView.contentInset.left + scrollView.contentOffset.x;
+    CGFloat vy = scrollView.contentInset.top + scrollView.contentOffset.y;
+    CGFloat vw = scrollView.frame.size.width - scrollView.contentInset.left - scrollView.contentInset.right;
+    CGFloat vh = scrollView.frame.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom;
+    CGRect scrollRect = CGRectMake(vx, vy, vw, vh);;
+    
+    // notify action for appear
+    NSArray *listenerArrayCopy = [self.listenerArray copy];
+    for(WXScrollToTarget *target in listenerArrayCopy){
+        if (_shouldNotifiAppearDescendantView) {
+            // if target component is descendant of scrollerview, it should notify the appear event handler, or here will skip this appear calculation.
+            if ([target.target isViewLoaded] && [target.target.view isDescendantOfView:self.view]) {
+                [self scrollToTarget:target scrollRect:scrollRect];
+            }
+        } else {
+            [self scrollToTarget:target scrollRect:scrollRect];
+        }
+    }
+}
+
+- (CGPoint)absolutePositionForComponent:(WXComponent *)component
+{
+    return [component->_view.superview convertPoint:component->_view.frame.origin toView:_view];
+}
+
+#pragma mark  Private Methods
+
+- (void)scrollToTarget:(WXScrollToTarget *)target scrollRect:(CGRect)rect
+{
+    WXComponent *component = target.target;
+    if (![component isViewLoaded]) { 
+        return;
+    }
+    
+    CGFloat ctop;
+    if (component && component->_view && component->_view.superview) {
+        ctop = [self absolutePositionForComponent:component].y;
+    } else {
+        ctop = 0.0;
+    }
+    CGFloat cbottom = ctop + CGRectGetHeight(component.calculatedFrame);
+    CGFloat cleft;
+    if (component && component->_view && component->_view.superview) {
+        cleft = [self absolutePositionForComponent:component].x;
+    } else {
+        cleft = 0.0;
+    }
+    CGFloat cright = cleft + CGRectGetWidth(component.calculatedFrame);
+    
+    CGFloat vtop = CGRectGetMinY(rect), vbottom = CGRectGetMaxY(rect), vleft = CGRectGetMinX(rect), vright = CGRectGetMaxX(rect);
+    if(cbottom > vtop && ctop <= vbottom && cleft <= vright && cright > vleft){
+        if(!target.hasAppear && component){
+            target.hasAppear = YES;
+            if (component->_appearEvent) {
+//                NSLog(@"appear:%@, %.2f", component, ctop);
+                [component fireEvent:@"appear" params:_direction ? @{@"direction":_direction} : nil];
+            }
+        }
+    } else {
+        if(target.hasAppear && component){
+            target.hasAppear = NO;
+            if(component->_disappearEvent){
+//                NSLog(@"disappear:%@", component);
+                [component fireEvent:@"disappear" params:_direction ? @{@"direction":_direction} : nil];
+            }
+        }
+    }
+}
+
+- (void)handleLoadMore
+{
+    if (_listenLoadMore && [self isNeedLoadMore]) {
+        [self loadMore];
+    }
+}
+
+#pragma mark Layout
+
+- (NSUInteger)_childrenCountForLayout;
+{
+    return 0;
+}
+
+- (NSUInteger)childrenCountForScrollerLayout
+{
+    return [super _childrenCountForLayout];
+}
+
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition
+                          gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
+{
+    /**
+     *  Pretty hacky way
+     *  layout from root to scroller to get scroller's frame,
+     *  layout from children to scroller to get scroller's contentSize
+     */
+    if ([self needsLayout]) {
+//#ifndef USE_FLEX
+        if (![WXComponent isUseFlex]) {
+            memcpy(_scrollerCSSNode, self.cssNode, sizeof(css_node_t));
+            _scrollerCSSNode->children_count = (int)[self childrenCountForScrollerLayout];
+            
+            _scrollerCSSNode->style.position[CSS_LEFT] = 0;
+            _scrollerCSSNode->style.position[CSS_TOP] = 0;
+            
+            if (_scrollDirection == WXScrollDirectionVertical) {
+                _scrollerCSSNode->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
+                _scrollerCSSNode->style.dimensions[CSS_WIDTH] = _cssNode->layout.dimensions[CSS_WIDTH];
+                _scrollerCSSNode->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
+            } else {
+                _scrollerCSSNode->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+                _scrollerCSSNode->style.dimensions[CSS_HEIGHT] = _cssNode->layout.dimensions[CSS_HEIGHT];
+                _scrollerCSSNode->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
+            }
+            
+            _scrollerCSSNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
+            _scrollerCSSNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
+            
+            layoutNode(_scrollerCSSNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
+            if ([WXLog logLevel] >= WXLogLevelDebug) {
+                print_css_node(_scrollerCSSNode, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN));
+            }
+            CGSize size = {
+                WXRoundPixelValue(_scrollerCSSNode->layout.dimensions[CSS_WIDTH]),
+                WXRoundPixelValue(_scrollerCSSNode->layout.dimensions[CSS_HEIGHT])
+            };
+            
+            if (!CGSizeEqualToSize(size, _contentSize)) {
+                _contentSize = size;
+                [dirtyComponents addObject:self];
+            }
+            
+            _scrollerCSSNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
+            _scrollerCSSNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
+        }
+      
+//#else
+        else
+        {
+            _flexScrollerCSSNode->copyStyle(_flexCssNode);
+            _flexScrollerCSSNode->copyMeasureFunc(_flexCssNode);
+            
+            if (_scrollDirection == WXScrollDirectionVertical) {
+                _flexScrollerCSSNode->setFlexDirection(WeexCore::kFlexDirectionColumn,NO);
+                _flexScrollerCSSNode->setStyleWidth(self.flexCssNode->getLayoutWidth(),NO);
+                _flexScrollerCSSNode->setStyleHeight(FlexUndefined);
+            } else {
+                _flexScrollerCSSNode->setFlexDirection(WeexCore::kFlexDirectionRow,NO);
+                _flexScrollerCSSNode->setStyleHeight(self.flexCssNode->getLayoutHeight());
+                _flexScrollerCSSNode->setStyleWidth(FlexUndefined,NO);
+            }
+            _flexScrollerCSSNode->markDirty();
+            std::pair<float, float> renderPageSize;
+            renderPageSize.first = self.weexInstance.frame.size.width;
+            renderPageSize.second = self.weexInstance.frame.size.height;
+            _flexScrollerCSSNode->calculateLayout(renderPageSize);
+            CGSize size = {
+                WXRoundPixelValue(_flexScrollerCSSNode->getLayoutWidth()),
+                WXRoundPixelValue(_flexScrollerCSSNode->getLayoutHeight())
+            };
+            
+            if (!CGSizeEqualToSize(size, _contentSize)) {
+                // content size
+                _contentSize = size;
+                [dirtyComponents addObject:self];
+            }
+        }
+//#endif
+    }
+    
+    [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+}
+
+@end


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

Posted by ac...@apache.org.
[WEEX-311] [iOS] use new layoutEngin to replace yoga

* [iOS] support new flex-layout engine

* [iOS] update layout engin

* [iOS] fix recycleList copy node error

* [iOS] rm useless code

* [iOS] rtl old layout engin

* [iOS] rm uselse code

* [iOS] format log

* [iOS] rm useless code

close #1135


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/b77b4259
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/b77b4259
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/b77b4259

Branch: refs/heads/master
Commit: b77b42599e763b2e25a63d6a9c576eeb388494dd
Parents: bf14bcd
Author: MrRaindrop <te...@gmail.com>
Authored: Tue Oct 31 22:15:05 2017 +0800
Committer: acton393 <zh...@gmail.com>
Committed: Thu Apr 26 20:38:59 2018 +0800

----------------------------------------------------------------------
 WeexSDK.podspec                                 |    2 +-
 ios/playground/WeexDemo/WXExtModule.m           |    7 +
 ios/sdk/WeexSDK.xcodeproj/project.pbxproj       |  327 ++--
 .../WeexSDK/Sources/Bridge/WXBridgeContext.m    |   38 +
 .../Component/RecycleList/WXCellSlotComponent.m |   94 -
 .../RecycleList/WXCellSlotComponent.mm          |  117 ++
 .../RecycleList/WXRecycleListComponent.m        |  618 ------
 .../RecycleList/WXRecycleListComponent.mm       |  619 ++++++
 .../Component/Recycler/WXRecyclerComponent.m    |  738 -------
 .../Component/Recycler/WXRecyclerComponent.mm   |  768 ++++++++
 .../WeexSDK/Sources/Component/WXCellComponent.m |  145 --
 .../Sources/Component/WXCellComponent.mm        |  174 ++
 .../Sources/Component/WXComponent_internal.h    |   11 +-
 .../Sources/Component/WXCycleSliderComponent.m  |  681 -------
 .../Sources/Component/WXCycleSliderComponent.mm |  692 +++++++
 .../WeexSDK/Sources/Component/WXEditComponent.m |  918 ---------
 .../Sources/Component/WXEditComponent.mm        |  971 ++++++++++
 .../Sources/Component/WXHeaderComponent.m       |   87 -
 .../Sources/Component/WXHeaderComponent.mm      |  110 ++
 .../WeexSDK/Sources/Component/WXListComponent.m |  975 ----------
 .../Sources/Component/WXListComponent.mm        |  997 ++++++++++
 .../Sources/Component/WXLoadingComponent.m      |  152 --
 .../Sources/Component/WXLoadingComponent.mm     |  164 ++
 .../Sources/Component/WXRefreshComponent.m      |  207 --
 .../Sources/Component/WXRefreshComponent.mm     |  224 +++
 .../Sources/Component/WXScrollerComponent.h     |    2 -
 .../Sources/Component/WXScrollerComponent.m     |  884 ---------
 .../Sources/Component/WXScrollerComponent.mm    |  951 +++++++++
 .../Component/WXSliderNeighborComponent.m       | 1803 -----------------
 .../Component/WXSliderNeighborComponent.mm      | 1812 ++++++++++++++++++
 .../Sources/Component/WXSwitchComponent.m       |  151 --
 .../Sources/Component/WXSwitchComponent.mm      |  162 ++
 .../Sources/Component/WXTextAreaComponent.m     |  233 ---
 .../Sources/Component/WXTextAreaComponent.mm    |  261 +++
 .../WeexSDK/Sources/Component/WXTextComponent.m | 1076 -----------
 .../Sources/Component/WXTextComponent.mm        | 1170 +++++++++++
 ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m    |    2 +
 .../WeexSDK/Sources/Layout/WXComponent+Layout.h |   60 +-
 .../Sources/Layout/WXComponent+Layout.mm        |  963 ++++++++++
 ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h |  107 ++
 ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp | 1038 ++++++++++
 ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h   | 1073 +++++++++++
 ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp  |  247 +++
 ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h    |  285 +++
 ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h |    6 +
 .../Sources/Layout/WXScrollerComponent+Layout.h |   42 +
 .../Layout/WXScrollerComponent+Layout.mm        |   53 +
 .../Sources/Manager/WXComponentManager.m        |  958 ---------
 .../Sources/Manager/WXComponentManager.mm       | 1158 +++++++++++
 ios/sdk/WeexSDK/Sources/Model/WXComponent.h     |   13 +-
 ios/sdk/WeexSDK/Sources/Model/WXComponent.m     |  842 --------
 ios/sdk/WeexSDK/Sources/Model/WXComponent.mm    |  953 +++++++++
 ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m   |   16 +-
 ios/sdk/WeexSDK/Sources/Module/WXTransition.m   |  519 -----
 ios/sdk/WeexSDK/Sources/Module/WXTransition.mm  |  519 +++++
 ios/sdk/WeexSDK/Sources/Utility/WXConvert.m     |   23 +
 ios/sdk/WeexSDK/Sources/Utility/WXUtility.h     |   17 +-
 .../Sources/View/WXComponent+ViewManagement.m   |  346 ----
 .../Sources/View/WXComponent+ViewManagement.mm  |  347 ++++
 ios/sdk/WeexSDK/Sources/View/WXRootView.m       |    2 +-
 ios/sdk/WeexSDK/Sources/WeexSDK.h               |    4 +
 61 files changed, 16358 insertions(+), 11576 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/WeexSDK.podspec
----------------------------------------------------------------------
diff --git a/WeexSDK.podspec b/WeexSDK.podspec
index 21f80ee..53f0a17 100644
--- a/WeexSDK.podspec
+++ b/WeexSDK.podspec
@@ -27,7 +27,7 @@ Pod::Spec.new do |s|
   s.platform     = :ios
   s.ios.deployment_target = '8.0'
   s.source =  { :path => '.' }
-  s.source_files = 'ios/sdk/WeexSDK/Sources/**/*.{h,m,mm,c}'
+  s.source_files = 'ios/sdk/WeexSDK/Sources/**/*.{h,m,mm,c,cpp}'
   s.resources = 'pre-build/*.js','ios/sdk/WeexSDK/Resources/wx_load_error@3x.png'
 
   s.user_target_xcconfig  = { 'FRAMEWORK_SEARCH_PATHS' => "'$(PODS_ROOT)/WeexSDK'" }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/playground/WeexDemo/WXExtModule.m
----------------------------------------------------------------------
diff --git a/ios/playground/WeexDemo/WXExtModule.m b/ios/playground/WeexDemo/WXExtModule.m
index fe034e7..16b2e0a 100644
--- a/ios/playground/WeexDemo/WXExtModule.m
+++ b/ios/playground/WeexDemo/WXExtModule.m
@@ -32,8 +32,15 @@ WX_EXPORT_METHOD(@selector(generateCover:))
     setenv("GCOV_PREFIX", [documentsDirectory cStringUsingEncoding:NSUTF8StringEncoding], 1);
     setenv("GCOV_PREFIX_STRIP", "6", 1);
 #endif
+    
+#if defined __cplusplus
+    extern "C" {
+#endif
     extern void __gcov_flush(void);
     __gcov_flush();
+#if defined __cplusplus
+    };
+#endif
     
     if (callback) {
         NSDictionary * result = @{@"ok": @true};


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
index a4c0db2..e017293 100644
--- a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
+++ b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
@@ -11,6 +11,11 @@
 		170B4664208733AF00562666 /* WXAnalyzerCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C74F092072145000AB4CAB /* WXAnalyzerCenter.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		170B4665208733BF00562666 /* WXAnalyzerCenter+Transfer.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C74F082072145000AB4CAB /* WXAnalyzerCenter+Transfer.h */; };
 		170B4668208733E500562666 /* WXAnalyzerCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 17C74F0A2072145100AB4CAB /* WXAnalyzerCenter.m */; };
+		176BE43C209172330086B6AF /* WXComponent+Layout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 176BE43B209172330086B6AF /* WXComponent+Layout.mm */; };
+		176BE43D209172A30086B6AF /* WXScrollerComponent+Layout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17C7B4FF20452E1800A2296A /* WXScrollerComponent+Layout.mm */; };
+		176BE43E209172E20086B6AF /* WXScrollerComponent+Layout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17C7B4FF20452E1800A2296A /* WXScrollerComponent+Layout.mm */; };
+		178EDF0D204FEC1300917F6B /* WXScrollerComponent+Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C7B50020452E1800A2296A /* WXScrollerComponent+Layout.h */; };
+		178EDF0F204FF11700917F6B /* WXCoreLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C7B50420452E1800A2296A /* WXCoreLayout.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		17B122212090AA9300387E33 /* WXSDKInstance_performance.m in Sources */ = {isa = PBXBuildFile; fileRef = 17B1221F2090AA9300387E33 /* WXSDKInstance_performance.m */; };
 		17B122222090AA9300387E33 /* WXSDKInstance_performance.h in Headers */ = {isa = PBXBuildFile; fileRef = 17B122202090AA9300387E33 /* WXSDKInstance_performance.h */; };
 		17B122252090AAB000387E33 /* WXSDKError.h in Headers */ = {isa = PBXBuildFile; fileRef = 17B122232090AAB000387E33 /* WXSDKError.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -20,6 +25,17 @@
 		17C74F0C2072145100AB4CAB /* WXAnalyzerCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C74F092072145000AB4CAB /* WXAnalyzerCenter.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		17C74F0D2072145100AB4CAB /* WXAnalyzerCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 17C74F0A2072145100AB4CAB /* WXAnalyzerCenter.m */; };
 		17C74F0F2072147B00AB4CAB /* WXAnalyzerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C74F0E2072147A00AB4CAB /* WXAnalyzerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		17C7B50620452E1800A2296A /* WXCoreLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17C7B4FE20452E1700A2296A /* WXCoreLayout.cpp */; };
+		17C7B50820452E1800A2296A /* WXScrollerComponent+Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C7B50020452E1800A2296A /* WXScrollerComponent+Layout.h */; };
+		17C7B50920452E1800A2296A /* WXCoreStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17C7B50120452E1800A2296A /* WXCoreStyle.cpp */; };
+		17C7B50A20452E1800A2296A /* WXCoreFlexEnum.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C7B50220452E1800A2296A /* WXCoreFlexEnum.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		17C7B50B20452E1800A2296A /* WXCoreStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C7B50320452E1800A2296A /* WXCoreStyle.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		17E5ACD82091F02D00EE81F1 /* WXCoreLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C7B50420452E1800A2296A /* WXCoreLayout.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		17E5ACD92091F03700EE81F1 /* WXCoreStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C7B50320452E1800A2296A /* WXCoreStyle.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		17E5ACDA2091F05000EE81F1 /* WXCoreFlexEnum.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C7B50220452E1800A2296A /* WXCoreFlexEnum.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		17E5ACDB2091F05700EE81F1 /* WXComponent+Layout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 176BE43B209172330086B6AF /* WXComponent+Layout.mm */; };
+		17E5ACDC2091F05E00EE81F1 /* WXCoreLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17C7B4FE20452E1700A2296A /* WXCoreLayout.cpp */; };
+		17E5ACDD2091F06300EE81F1 /* WXCoreStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17C7B50120452E1800A2296A /* WXCoreStyle.cpp */; };
 		17F2D6E72087227300084378 /* WXAnalyzerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C74F0E2072147A00AB4CAB /* WXAnalyzerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		1C1A2BED1D91172800539AA1 /* WXConvertTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C1A2BEC1D91172800539AA1 /* WXConvertTests.m */; };
 		1D3000F11D40B9AC004F3B4F /* WXClipboardModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D3000EF1D40B9AB004F3B4F /* WXClipboardModule.h */; };
@@ -30,13 +46,13 @@
 		2A42AF8A1C23B33E00818EA6 /* WeexSDK_MTL.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A42AF891C23B33E00818EA6 /* WeexSDK_MTL.m */; };
 		2A4445BF1CA8FD56009E7C6D /* WXTextComponentProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A4445BE1CA8FD56009E7C6D /* WXTextComponentProtocol.h */; };
 		2A60CE9C1C91733E00857B9F /* WXSwitchComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A60CE9A1C91733E00857B9F /* WXSwitchComponent.h */; };
-		2A60CE9D1C91733E00857B9F /* WXSwitchComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A60CE9B1C91733E00857B9F /* WXSwitchComponent.m */; };
+		2A60CE9D1C91733E00857B9F /* WXSwitchComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A60CE9B1C91733E00857B9F /* WXSwitchComponent.mm */; };
 		2A837AB21CD9DE9200AEDF03 /* WXLoadingComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A837AAC1CD9DE9200AEDF03 /* WXLoadingComponent.h */; };
-		2A837AB31CD9DE9200AEDF03 /* WXLoadingComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.m */; };
+		2A837AB31CD9DE9200AEDF03 /* WXLoadingComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.mm */; };
 		2A837AB41CD9DE9200AEDF03 /* WXLoadingIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A837AAE1CD9DE9200AEDF03 /* WXLoadingIndicator.h */; };
 		2A837AB51CD9DE9200AEDF03 /* WXLoadingIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AAF1CD9DE9200AEDF03 /* WXLoadingIndicator.m */; };
 		2A837AB61CD9DE9200AEDF03 /* WXRefreshComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A837AB01CD9DE9200AEDF03 /* WXRefreshComponent.h */; };
-		2A837AB71CD9DE9200AEDF03 /* WXRefreshComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AB11CD9DE9200AEDF03 /* WXRefreshComponent.m */; };
+		2A837AB71CD9DE9200AEDF03 /* WXRefreshComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AB11CD9DE9200AEDF03 /* WXRefreshComponent.mm */; };
 		2A8E658A1C7C7AA20025C7B7 /* WXVideoComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A8E65881C7C7AA20025C7B7 /* WXVideoComponent.h */; };
 		2A8E658B1C7C7AA20025C7B7 /* WXVideoComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A8E65891C7C7AA20025C7B7 /* WXVideoComponent.m */; };
 		2A919DA61E321F1F006EB6B5 /* WXBridgeMethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A919DA41E321F1F006EB6B5 /* WXBridgeMethod.h */; };
@@ -49,11 +65,9 @@
 		2AFEB17B1C747139000507FA /* WXInstanceWrap.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AFEB1791C747139000507FA /* WXInstanceWrap.h */; };
 		2AFEB17C1C747139000507FA /* WXInstanceWrap.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AFEB17A1C747139000507FA /* WXInstanceWrap.m */; };
 		333D9A271F41507A007CED39 /* WXTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 333D9A251F41507A007CED39 /* WXTransition.h */; };
-		333D9A281F41507A007CED39 /* WXTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 333D9A251F41507A007CED39 /* WXTransition.h */; };
-		333D9A291F41507A007CED39 /* WXTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 333D9A261F41507A007CED39 /* WXTransition.m */; };
-		333D9A2A1F41507A007CED39 /* WXTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 333D9A261F41507A007CED39 /* WXTransition.m */; };
+		333D9A2A1F41507A007CED39 /* WXTransition.mm in Sources */ = {isa = PBXBuildFile; fileRef = 333D9A261F41507A007CED39 /* WXTransition.mm */; };
 		37B51EE41E97804D0040A743 /* WXCycleSliderComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 37B51EE21E97804D0040A743 /* WXCycleSliderComponent.h */; };
-		37B51EE51E97804D0040A743 /* WXCycleSliderComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 37B51EE31E97804D0040A743 /* WXCycleSliderComponent.m */; };
+		37B51EE51E97804D0040A743 /* WXCycleSliderComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37B51EE31E97804D0040A743 /* WXCycleSliderComponent.mm */; };
 		591324A31D49B7F1004E89ED /* WXTimerModuleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 591324A21D49B7F1004E89ED /* WXTimerModuleTests.m */; };
 		591DD3311D23AD5800BE8709 /* WXErrorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 591DD32F1D23AD5800BE8709 /* WXErrorView.m */; };
 		591DD3321D23AD5800BE8709 /* WXErrorView.h in Headers */ = {isa = PBXBuildFile; fileRef = 591DD3301D23AD5800BE8709 /* WXErrorView.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -101,7 +115,7 @@
 		740938F91D3D0E0300DBB801 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 740938F81D3D0E0300DBB801 /* MediaPlayer.framework */; };
 		740938FB1D3D0E1700DBB801 /* AVKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 740938FA1D3D0E1700DBB801 /* AVKit.framework */; };
 		7410811F1CED585A001BC6E5 /* WXComponentManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 7410811D1CED585A001BC6E5 /* WXComponentManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		741081201CED585A001BC6E5 /* WXComponentManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7410811E1CED585A001BC6E5 /* WXComponentManager.m */; };
+		741081201CED585A001BC6E5 /* WXComponentManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7410811E1CED585A001BC6E5 /* WXComponentManager.mm */; };
 		741081231CED6756001BC6E5 /* WXComponentFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 741081211CED6756001BC6E5 /* WXComponentFactory.h */; };
 		741081241CED6756001BC6E5 /* WXComponentFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 741081221CED6756001BC6E5 /* WXComponentFactory.m */; };
 		741081261CEDB4EC001BC6E5 /* WXComponent_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 741081251CEDB4EC001BC6E5 /* WXComponent_internal.h */; };
@@ -127,18 +141,17 @@
 		743933B51C7ED9AA00773BB7 /* WXSimulatorShortcutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 743933B31C7ED9AA00773BB7 /* WXSimulatorShortcutManager.m */; };
 		744BEA551D05178F00452B5D /* WXComponent+Display.h in Headers */ = {isa = PBXBuildFile; fileRef = 744BEA531D05178F00452B5D /* WXComponent+Display.h */; };
 		744BEA561D05178F00452B5D /* WXComponent+Display.m in Sources */ = {isa = PBXBuildFile; fileRef = 744BEA541D05178F00452B5D /* WXComponent+Display.m */; };
-		744BEA591D0520F300452B5D /* WXComponent+Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 744BEA571D0520F300452B5D /* WXComponent+Layout.h */; };
-		744BEA5A1D0520F300452B5D /* WXComponent+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 744BEA581D0520F300452B5D /* WXComponent+Layout.m */; };
+		744BEA591D0520F300452B5D /* WXComponent+Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 744BEA571D0520F300452B5D /* WXComponent+Layout.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		744D610C1E49978200B624B3 /* WXHeaderComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 744D610A1E49978200B624B3 /* WXHeaderComponent.h */; };
-		744D610D1E49978200B624B3 /* WXHeaderComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 744D610B1E49978200B624B3 /* WXHeaderComponent.m */; };
+		744D610D1E49978200B624B3 /* WXHeaderComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 744D610B1E49978200B624B3 /* WXHeaderComponent.mm */; };
 		744D61101E49979000B624B3 /* WXFooterComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 744D610E1E49979000B624B3 /* WXFooterComponent.h */; };
 		744D61111E49979000B624B3 /* WXFooterComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 744D610F1E49979000B624B3 /* WXFooterComponent.m */; };
 		744D61141E4AF23E00B624B3 /* WXDiffUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 744D61121E4AF23E00B624B3 /* WXDiffUtil.h */; };
 		744D61151E4AF23E00B624B3 /* WXDiffUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 744D61131E4AF23E00B624B3 /* WXDiffUtil.m */; };
 		745B2D681E5A8E1E0092D38A /* WXMultiColumnLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D5E1E5A8E1E0092D38A /* WXMultiColumnLayout.h */; };
 		745B2D691E5A8E1E0092D38A /* WXMultiColumnLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D5F1E5A8E1E0092D38A /* WXMultiColumnLayout.m */; };
-		745B2D6A1E5A8E1E0092D38A /* WXRecyclerComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D601E5A8E1E0092D38A /* WXRecyclerComponent.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		745B2D6B1E5A8E1E0092D38A /* WXRecyclerComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.m */; };
+		745B2D6A1E5A8E1E0092D38A /* WXRecyclerComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D601E5A8E1E0092D38A /* WXRecyclerComponent.h */; };
+		745B2D6B1E5A8E1E0092D38A /* WXRecyclerComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.mm */; };
 		745B2D6C1E5A8E1E0092D38A /* WXRecyclerDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D621E5A8E1E0092D38A /* WXRecyclerDataController.h */; };
 		745B2D6D1E5A8E1E0092D38A /* WXRecyclerDataController.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D631E5A8E1E0092D38A /* WXRecyclerDataController.m */; };
 		745B2D6E1E5A8E1E0092D38A /* WXRecyclerUpdateController.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D641E5A8E1E0092D38A /* WXRecyclerUpdateController.h */; };
@@ -160,9 +173,9 @@
 		7469869F1C4E2C000054A57E /* NSArray+Weex.h in Headers */ = {isa = PBXBuildFile; fileRef = 7469869D1C4E2C000054A57E /* NSArray+Weex.h */; };
 		746986A01C4E2C010054A57E /* NSArray+Weex.m in Sources */ = {isa = PBXBuildFile; fileRef = 7469869E1C4E2C000054A57E /* NSArray+Weex.m */; };
 		746B923B1F46BE36009AE86B /* WXCellSlotComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 746B92391F46BE36009AE86B /* WXCellSlotComponent.h */; };
-		746B923C1F46BE36009AE86B /* WXCellSlotComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 746B923A1F46BE36009AE86B /* WXCellSlotComponent.m */; };
+		746B923C1F46BE36009AE86B /* WXCellSlotComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 746B923A1F46BE36009AE86B /* WXCellSlotComponent.mm */; };
 		747A787C1D1BAAC900DED9D0 /* WXComponent+ViewManagement.h in Headers */ = {isa = PBXBuildFile; fileRef = 747A787A1D1BAAC900DED9D0 /* WXComponent+ViewManagement.h */; };
-		747A787D1D1BAAC900DED9D0 /* WXComponent+ViewManagement.m in Sources */ = {isa = PBXBuildFile; fileRef = 747A787B1D1BAAC900DED9D0 /* WXComponent+ViewManagement.m */; };
+		747A787D1D1BAAC900DED9D0 /* WXComponent+ViewManagement.mm in Sources */ = {isa = PBXBuildFile; fileRef = 747A787B1D1BAAC900DED9D0 /* WXComponent+ViewManagement.mm */; };
 		747DF6821E31AEE4005C53A8 /* WXLength.h in Headers */ = {isa = PBXBuildFile; fileRef = 747DF6801E31AEE4005C53A8 /* WXLength.h */; };
 		747DF6831E31AEE4005C53A8 /* WXLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 747DF6811E31AEE4005C53A8 /* WXLength.m */; };
 		74862F791E02B88D00B7A041 /* JSValue+Weex.h in Headers */ = {isa = PBXBuildFile; fileRef = 74862F771E02B88D00B7A041 /* JSValue+Weex.h */; };
@@ -193,7 +206,7 @@
 		74AD99851D5B0E59008F0336 /* WXPolyfillSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 74AD99831D5B0E59008F0336 /* WXPolyfillSet.m */; };
 		74B232D21D2A2BA4006322EA /* WXLayoutDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 74B232D11D2A2BA4006322EA /* WXLayoutDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		74B81AE31F73C3E300D3A61D /* WXRecycleListComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CFDD371F45939C007A1A66 /* WXRecycleListComponent.h */; };
-		74B81AE41F73C3E500D3A61D /* WXRecycleListComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CFDD381F45939C007A1A66 /* WXRecycleListComponent.m */; };
+		74B81AE41F73C3E500D3A61D /* WXRecycleListComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 74CFDD381F45939C007A1A66 /* WXRecycleListComponent.mm */; };
 		74B81AE51F73C3E900D3A61D /* WXRecycleListDataManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CFDD3B1F459400007A1A66 /* WXRecycleListDataManager.h */; };
 		74B81AE61F73C3E900D3A61D /* WXRecycleListDataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CFDD3C1F459400007A1A66 /* WXRecycleListDataManager.m */; };
 		74B81AE71F73C3E900D3A61D /* WXRecycleListTemplateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CFDD3F1F45941E007A1A66 /* WXRecycleListTemplateManager.h */; };
@@ -203,7 +216,7 @@
 		74B81AEB1F73C3E900D3A61D /* WXRecycleListLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 74BA4AB11F70F4B600AC29BF /* WXRecycleListLayout.h */; };
 		74B81AEC1F73C3E900D3A61D /* WXRecycleListLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 74BA4AB21F70F4B600AC29BF /* WXRecycleListLayout.m */; };
 		74B81AED1F73C3E900D3A61D /* WXCellSlotComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 746B92391F46BE36009AE86B /* WXCellSlotComponent.h */; };
-		74B81AEE1F73C3E900D3A61D /* WXCellSlotComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 746B923A1F46BE36009AE86B /* WXCellSlotComponent.m */; };
+		74B81AEE1F73C3E900D3A61D /* WXCellSlotComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 746B923A1F46BE36009AE86B /* WXCellSlotComponent.mm */; };
 		74B81AEF1F73C3E900D3A61D /* WXComponent+DataBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = 7423EB4F1F4ADE30001662D1 /* WXComponent+DataBinding.h */; };
 		74B81AF01F73C3E900D3A61D /* WXComponent+DataBinding.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7423EB501F4ADE30001662D1 /* WXComponent+DataBinding.mm */; };
 		74B81AF11F73C3E900D3A61D /* WXJSASTParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 74BF19F61F5139BB00AEE3D7 /* WXJSASTParser.h */; };
@@ -220,11 +233,11 @@
 		74C896401D2AC2210043B82A /* WeexSDKTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 74C8963F1D2AC2210043B82A /* WeexSDKTests.m */; };
 		74C896421D2AC2210043B82A /* WeexSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77D160FD1C02DBE70010B15B /* WeexSDK.framework */; };
 		74CC7A1C1C2BC5F800829368 /* WXCellComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CC7A1A1C2BC5F800829368 /* WXCellComponent.h */; };
-		74CC7A1D1C2BC5F800829368 /* WXCellComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CC7A1B1C2BC5F800829368 /* WXCellComponent.m */; };
+		74CC7A1D1C2BC5F800829368 /* WXCellComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 74CC7A1B1C2BC5F800829368 /* WXCellComponent.mm */; };
 		74CC7A201C2BF9DC00829368 /* WXListComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CC7A1E1C2BF9DC00829368 /* WXListComponent.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		74CC7A211C2BF9DC00829368 /* WXListComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CC7A1F1C2BF9DC00829368 /* WXListComponent.m */; };
+		74CC7A211C2BF9DC00829368 /* WXListComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 74CC7A1F1C2BF9DC00829368 /* WXListComponent.mm */; };
 		74CFDD391F45939C007A1A66 /* WXRecycleListComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CFDD371F45939C007A1A66 /* WXRecycleListComponent.h */; };
-		74CFDD3A1F45939C007A1A66 /* WXRecycleListComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CFDD381F45939C007A1A66 /* WXRecycleListComponent.m */; };
+		74CFDD3A1F45939C007A1A66 /* WXRecycleListComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 74CFDD381F45939C007A1A66 /* WXRecycleListComponent.mm */; };
 		74CFDD3D1F459400007A1A66 /* WXRecycleListDataManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CFDD3B1F459400007A1A66 /* WXRecycleListDataManager.h */; };
 		74CFDD3E1F459400007A1A66 /* WXRecycleListDataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CFDD3C1F459400007A1A66 /* WXRecycleListDataManager.m */; };
 		74CFDD411F45941E007A1A66 /* WXRecycleListTemplateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CFDD3F1F45941E007A1A66 /* WXRecycleListTemplateManager.h */; };
@@ -250,7 +263,7 @@
 		77D161281C02DE1A0010B15B /* WXSDKManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 77D161261C02DE1A0010B15B /* WXSDKManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		77D161291C02DE1A0010B15B /* WXSDKManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 77D161271C02DE1A0010B15B /* WXSDKManager.m */; };
 		77D161301C02DE4E0010B15B /* WXComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 77D1612E1C02DE4E0010B15B /* WXComponent.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		77D161311C02DE4E0010B15B /* WXComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77D1612F1C02DE4E0010B15B /* WXComponent.m */; };
+		77D161311C02DE4E0010B15B /* WXComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77D1612F1C02DE4E0010B15B /* WXComponent.mm */; };
 		77D161381C02DE940010B15B /* WXBridgeManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 77D161361C02DE940010B15B /* WXBridgeManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		77D161391C02DE940010B15B /* WXBridgeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 77D161371C02DE940010B15B /* WXBridgeManager.m */; };
 		77D1613C1C02DEA60010B15B /* WXJSCoreBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 77D1613A1C02DEA60010B15B /* WXJSCoreBridge.h */; };
@@ -271,13 +284,14 @@
 		77E65A111C155EA8008B8775 /* WXImageComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 77E65A0F1C155EA8008B8775 /* WXImageComponent.h */; };
 		77E65A121C155EA8008B8775 /* WXImageComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A101C155EA8008B8775 /* WXImageComponent.m */; };
 		77E65A151C155EB5008B8775 /* WXTextComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 77E65A131C155EB5008B8775 /* WXTextComponent.h */; };
-		77E65A161C155EB5008B8775 /* WXTextComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A141C155EB5008B8775 /* WXTextComponent.m */; };
+		77E65A161C155EB5008B8775 /* WXTextComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A141C155EB5008B8775 /* WXTextComponent.mm */; };
 		77E65A191C155F25008B8775 /* WXScrollerComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 77E65A171C155F25008B8775 /* WXScrollerComponent.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		77E65A1A1C155F25008B8775 /* WXScrollerComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A181C155F25008B8775 /* WXScrollerComponent.m */; };
+		77E65A1A1C155F25008B8775 /* WXScrollerComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A181C155F25008B8775 /* WXScrollerComponent.mm */; };
 		841CD1031F9739890081196D /* WXExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 841CD1021F9739890081196D /* WXExceptionUtils.m */; };
 		841CD1051F974DFA0081196D /* WXExceptionUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 841CD1041F97399C0081196D /* WXExceptionUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		841CD1061F974DFA0081196D /* WXExceptionUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 841CD1041F97399C0081196D /* WXExceptionUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		841CD1071F974E000081196D /* WXExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 841CD1021F9739890081196D /* WXExceptionUtils.m */; };
+		847E1DE41F9A1BCF00A48124 /* WXCoreStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 847E1DE01F9A1BCF00A48124 /* WXCoreStyle.h */; };
 		9B9E74791FA2DB5800DAAEA9 /* WXTestBridgeMethodDummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9E74781FA2DB5800DAAEA9 /* WXTestBridgeMethodDummy.m */; };
 		BA5F00F11FC5AFFE00F76B5C /* WXLocaleModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BA5F00EF1FC5AFFE00F76B5C /* WXLocaleModule.h */; };
 		BA5F00F21FC5AFFE00F76B5C /* WXLocaleModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BA5F00F01FC5AFFE00F76B5C /* WXLocaleModule.m */; };
@@ -298,7 +312,7 @@
 		C47B78CF1F2998EE001D3B0C /* WXExtendCallNativeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C47B78CD1F2998EE001D3B0C /* WXExtendCallNativeManager.m */; };
 		C49642EC1F73E6DF0092CC5A /* WXWebSocketHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = C4F012761E1502A6003378D0 /* WXWebSocketHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		C4B3D6D41E6954300013F38D /* WXEditComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = C4B3D6D21E6954300013F38D /* WXEditComponent.h */; };
-		C4B3D6D51E6954300013F38D /* WXEditComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = C4B3D6D31E6954300013F38D /* WXEditComponent.m */; };
+		C4B3D6D51E6954300013F38D /* WXEditComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = C4B3D6D31E6954300013F38D /* WXEditComponent.mm */; };
 		C4B834271DE69B09007AD27E /* WXPickerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C4B834251DE69B09007AD27E /* WXPickerModule.m */; };
 		C4B834281DE69B09007AD27E /* WXPickerModule.h in Headers */ = {isa = PBXBuildFile; fileRef = C4B834261DE69B09007AD27E /* WXPickerModule.h */; };
 		C4C30DE81E1B833D00786B6C /* WXComponent+PseudoClassManagement.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C30DE61E1B833D00786B6C /* WXComponent+PseudoClassManagement.m */; };
@@ -328,7 +342,7 @@
 		D362F9501C83EDA20003F546 /* WXWebViewModule.m in Sources */ = {isa = PBXBuildFile; fileRef = D362F94E1C83EDA20003F546 /* WXWebViewModule.m */; };
 		D3FC0DF71C508B2A002B9E31 /* WXTimerModule.h in Headers */ = {isa = PBXBuildFile; fileRef = D3FC0DF51C508B2A002B9E31 /* WXTimerModule.h */; };
 		D3FC0DF81C508B2A002B9E31 /* WXTimerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = D3FC0DF61C508B2A002B9E31 /* WXTimerModule.m */; };
-		DC03ADB91D508719003F76E7 /* WXTextAreaComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = DC03ADB71D508719003F76E7 /* WXTextAreaComponent.m */; };
+		DC03ADB91D508719003F76E7 /* WXTextAreaComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = DC03ADB71D508719003F76E7 /* WXTextAreaComponent.mm */; };
 		DC03ADBA1D508719003F76E7 /* WXTextAreaComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = DC03ADB81D508719003F76E7 /* WXTextAreaComponent.h */; };
 		DC15A3DB2010BC93009C8977 /* weex-main-jsfm.js in Resources */ = {isa = PBXBuildFile; fileRef = DC15A3D92010BC93009C8977 /* weex-main-jsfm.js */; };
 		DC15A3DC2010BC93009C8977 /* weex-rax-api.js in Resources */ = {isa = PBXBuildFile; fileRef = DC15A3DA2010BC93009C8977 /* weex-rax-api.js */; };
@@ -342,7 +356,6 @@
 		DC9F46871D61BA8C00A88239 /* wx_load_error@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 59AC02501D2A7E6E00355112 /* wx_load_error@3x.png */; };
 		DCA0EF641D6EED6F00CB18B9 /* WXGlobalEventModule.h in Headers */ = {isa = PBXBuildFile; fileRef = DCA0EF621D6EED6F00CB18B9 /* WXGlobalEventModule.h */; };
 		DCA0EF651D6EED6F00CB18B9 /* WXGlobalEventModule.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA0EF631D6EED6F00CB18B9 /* WXGlobalEventModule.m */; };
-		DCA4452D1EFA55B300D0CFA8 /* WXComponent+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 744BEA581D0520F300452B5D /* WXComponent+Layout.m */; };
 		DCA4452F1EFA55B300D0CFA8 /* WXResourceLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 742AD7391DF98C8B007DC46C /* WXResourceLoader.m */; };
 		DCA445301EFA55B300D0CFA8 /* WXComponent+Events.m in Sources */ = {isa = PBXBuildFile; fileRef = 7408C48D1CFB345D000BCCD0 /* WXComponent+Events.m */; };
 		DCA445311EFA55B300D0CFA8 /* WXComponent+BoxShadow.m in Sources */ = {isa = PBXBuildFile; fileRef = C4E375351E5FCBD3009B2D9C /* WXComponent+BoxShadow.m */; };
@@ -356,39 +369,39 @@
 		DCA445391EFA55B300D0CFA8 /* WXComponent+PseudoClassManagement.m in Sources */ = {isa = PBXBuildFile; fileRef = C4C30DE61E1B833D00786B6C /* WXComponent+PseudoClassManagement.m */; };
 		DCA4453A1EFA55B300D0CFA8 /* WXView.m in Sources */ = {isa = PBXBuildFile; fileRef = 745ED2D71C5F2C7E002DB5A8 /* WXView.m */; };
 		DCA4453B1EFA55B300D0CFA8 /* WXErrorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 591DD32F1D23AD5800BE8709 /* WXErrorView.m */; };
-		DCA4453C1EFA55B300D0CFA8 /* WXComponent+ViewManagement.m in Sources */ = {isa = PBXBuildFile; fileRef = 747A787B1D1BAAC900DED9D0 /* WXComponent+ViewManagement.m */; };
+		DCA4453C1EFA55B300D0CFA8 /* WXComponent+ViewManagement.mm in Sources */ = {isa = PBXBuildFile; fileRef = 747A787B1D1BAAC900DED9D0 /* WXComponent+ViewManagement.mm */; };
 		DCA4453D1EFA55B300D0CFA8 /* WXRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 74B8BEFD1DC47B72004A6027 /* WXRootView.m */; };
 		DCA4453E1EFA55B300D0CFA8 /* WXBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A5962C1CB632050012CD52 /* WXBaseViewController.m */; };
 		DCA4453F1EFA55B300D0CFA8 /* WXRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A5962E1CB632050012CD52 /* WXRootViewController.m */; };
-		DCA445401EFA55B300D0CFA8 /* WXEditComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = C4B3D6D31E6954300013F38D /* WXEditComponent.m */; };
+		DCA445401EFA55B300D0CFA8 /* WXEditComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = C4B3D6D31E6954300013F38D /* WXEditComponent.mm */; };
 		DCA445411EFA55B300D0CFA8 /* WXMultiColumnLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D5F1E5A8E1E0092D38A /* WXMultiColumnLayout.m */; };
-		DCA445421EFA55B300D0CFA8 /* WXRecyclerComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.m */; };
+		DCA445421EFA55B300D0CFA8 /* WXRecyclerComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.mm */; };
 		DCA445431EFA55B300D0CFA8 /* WXRecyclerDataController.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D631E5A8E1E0092D38A /* WXRecyclerDataController.m */; };
 		DCA445441EFA55B300D0CFA8 /* WXRecyclerUpdateController.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D651E5A8E1E0092D38A /* WXRecyclerUpdateController.m */; };
 		DCA445451EFA55B300D0CFA8 /* WXSectionDataController.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D671E5A8E1E0092D38A /* WXSectionDataController.m */; };
-		DCA445461EFA55B300D0CFA8 /* WXLoadingComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.m */; };
-		DCA445471EFA55B300D0CFA8 /* WXSliderNeighborComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC77C111D770AE300CE7288 /* WXSliderNeighborComponent.m */; };
+		DCA445461EFA55B300D0CFA8 /* WXLoadingComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.mm */; };
+		DCA445471EFA55B300D0CFA8 /* WXSliderNeighborComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = DCC77C111D770AE300CE7288 /* WXSliderNeighborComponent.mm */; };
 		DCA445481EFA55B300D0CFA8 /* WXLoadingIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AAF1CD9DE9200AEDF03 /* WXLoadingIndicator.m */; };
-		DCA445491EFA55B300D0CFA8 /* WXRefreshComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AB11CD9DE9200AEDF03 /* WXRefreshComponent.m */; };
+		DCA445491EFA55B300D0CFA8 /* WXRefreshComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A837AB11CD9DE9200AEDF03 /* WXRefreshComponent.mm */; };
 		DCA4454A1EFA55B300D0CFA8 /* WXEmbedComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 59CE27E71CC387DB000BE37A /* WXEmbedComponent.m */; };
 		DCA4454B1EFA55B300D0CFA8 /* WXVideoComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A8E65891C7C7AA20025C7B7 /* WXVideoComponent.m */; };
-		DCA4454C1EFA55B300D0CFA8 /* WXComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77D1612F1C02DE4E0010B15B /* WXComponent.m */; };
+		DCA4454C1EFA55B300D0CFA8 /* WXComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77D1612F1C02DE4E0010B15B /* WXComponent.mm */; };
 		DCA4454D1EFA55B300D0CFA8 /* WXDivComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A0C1C155E99008B8775 /* WXDivComponent.m */; };
 		DCA4454E1EFA55B300D0CFA8 /* WXImageComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A101C155EA8008B8775 /* WXImageComponent.m */; };
-		DCA4454F1EFA55B300D0CFA8 /* WXTextComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A141C155EB5008B8775 /* WXTextComponent.m */; };
-		DCA445501EFA55B300D0CFA8 /* WXScrollerComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A181C155F25008B8775 /* WXScrollerComponent.m */; };
-		DCA445511EFA55B300D0CFA8 /* WXCycleSliderComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 37B51EE31E97804D0040A743 /* WXCycleSliderComponent.m */; };
-		DCA445531EFA55B300D0CFA8 /* WXCellComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CC7A1B1C2BC5F800829368 /* WXCellComponent.m */; };
-		DCA445541EFA55B300D0CFA8 /* WXListComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CC7A1F1C2BF9DC00829368 /* WXListComponent.m */; };
+		DCA4454F1EFA55B300D0CFA8 /* WXTextComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A141C155EB5008B8775 /* WXTextComponent.mm */; };
+		DCA445501EFA55B300D0CFA8 /* WXScrollerComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A181C155F25008B8775 /* WXScrollerComponent.mm */; };
+		DCA445511EFA55B300D0CFA8 /* WXCycleSliderComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37B51EE31E97804D0040A743 /* WXCycleSliderComponent.mm */; };
+		DCA445531EFA55B300D0CFA8 /* WXCellComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 74CC7A1B1C2BC5F800829368 /* WXCellComponent.mm */; };
+		DCA445541EFA55B300D0CFA8 /* WXListComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 74CC7A1F1C2BF9DC00829368 /* WXListComponent.mm */; };
 		DCA445551EFA55B300D0CFA8 /* WXIndicatorComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AC750231C7565690041D390 /* WXIndicatorComponent.m */; };
 		DCA445561EFA55B300D0CFA8 /* WXTextInputComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A1F57B61C75C6A600B58017 /* WXTextInputComponent.m */; };
-		DCA445571EFA55B300D0CFA8 /* WXTextAreaComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = DC03ADB71D508719003F76E7 /* WXTextAreaComponent.m */; };
+		DCA445571EFA55B300D0CFA8 /* WXTextAreaComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = DC03ADB71D508719003F76E7 /* WXTextAreaComponent.mm */; };
 		DCA445581EFA55B300D0CFA8 /* WXTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = D317338B1C57257000BB7539 /* WXTransform.m */; };
 		DCA445591EFA55B300D0CFA8 /* WXWebComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = D312CE3A1C730DEB00046D68 /* WXWebComponent.m */; };
-		DCA4455A1EFA55B300D0CFA8 /* WXSwitchComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A60CE9B1C91733E00857B9F /* WXSwitchComponent.m */; };
+		DCA4455A1EFA55B300D0CFA8 /* WXSwitchComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A60CE9B1C91733E00857B9F /* WXSwitchComponent.mm */; };
 		DCA4455B1EFA55B300D0CFA8 /* WXAComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AE5B7511CAB7DBD0082FDDB /* WXAComponent.m */; };
 		DCA4455C1EFA55B300D0CFA8 /* WXCanvasComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = D33451071D3E19480083598A /* WXCanvasComponent.m */; };
-		DCA4455D1EFA55B300D0CFA8 /* WXHeaderComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 744D610B1E49978200B624B3 /* WXHeaderComponent.m */; };
+		DCA4455D1EFA55B300D0CFA8 /* WXHeaderComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 744D610B1E49978200B624B3 /* WXHeaderComponent.mm */; };
 		DCA4455E1EFA55B300D0CFA8 /* WXFooterComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 744D610F1E49979000B624B3 /* WXFooterComponent.m */; };
 		DCA4455F1EFA55B300D0CFA8 /* WXNavigationDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 59A583051CF5B2FD0081FD3E /* WXNavigationDefaultImpl.m */; };
 		DCA445601EFA55B300D0CFA8 /* WXURLRewriteDefaultImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 74EF31AC1DE58BE200667A07 /* WXURLRewriteDefaultImpl.m */; };
@@ -439,7 +452,7 @@
 		DCA445901EFA55B300D0CFA8 /* WXBridgeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 77D161371C02DE940010B15B /* WXBridgeManager.m */; };
 		DCA445911EFA55B300D0CFA8 /* WXModuleFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E659F01C0C3612008B8775 /* WXModuleFactory.m */; };
 		DCA445921EFA55B300D0CFA8 /* WXHandlerFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 74A4BA9D1CB3C0A100195969 /* WXHandlerFactory.m */; };
-		DCA445931EFA55B300D0CFA8 /* WXComponentManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7410811E1CED585A001BC6E5 /* WXComponentManager.m */; };
+		DCA445931EFA55B300D0CFA8 /* WXComponentManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7410811E1CED585A001BC6E5 /* WXComponentManager.mm */; };
 		DCA445941EFA55B300D0CFA8 /* WXComponentFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 741081221CED6756001BC6E5 /* WXComponentFactory.m */; };
 		DCA445951EFA55B300D0CFA8 /* WXRuleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAB35FD1D658EB700C0EA70 /* WXRuleManager.m */; };
 		DCA445961EFA55B300D0CFA8 /* WXMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 749DC27A1D40827B009E1C91 /* WXMonitor.m */; };
@@ -583,7 +596,7 @@
 		DCA446291EFA688B00D0CFA8 /* WeexSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = DCA446261EFA5DAF00D0CFA8 /* WeexSDK.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		DCAB35FE1D658EB700C0EA70 /* WXRuleManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DCAB35FC1D658EB700C0EA70 /* WXRuleManager.h */; };
 		DCAB35FF1D658EB700C0EA70 /* WXRuleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAB35FD1D658EB700C0EA70 /* WXRuleManager.m */; };
-		DCC77C131D770AE300CE7288 /* WXSliderNeighborComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC77C111D770AE300CE7288 /* WXSliderNeighborComponent.m */; };
+		DCC77C131D770AE300CE7288 /* WXSliderNeighborComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = DCC77C111D770AE300CE7288 /* WXSliderNeighborComponent.mm */; };
 		DCC77C141D770AE300CE7288 /* WXSliderNeighborComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC77C121D770AE300CE7288 /* WXSliderNeighborComponent.h */; };
 		DCD8D0F32073392A0002C420 /* weex-polyfill.js in Resources */ = {isa = PBXBuildFile; fileRef = DCD8D0F22073392A0002C420 /* weex-polyfill.js */; };
 		DCD8D0F42073392A0002C420 /* weex-polyfill.js in Resources */ = {isa = PBXBuildFile; fileRef = DCD8D0F22073392A0002C420 /* weex-polyfill.js */; };
@@ -633,6 +646,7 @@
 
 /* Begin PBXFileReference section */
 		042013AC1E66CD6A001FC79C /* WXValidateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXValidateProtocol.h; sourceTree = "<group>"; };
+		176BE43B209172330086B6AF /* WXComponent+Layout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "WXComponent+Layout.mm"; path = "Layout/WXComponent+Layout.mm"; sourceTree = "<group>"; };
 		17B1221F2090AA9300387E33 /* WXSDKInstance_performance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXSDKInstance_performance.m; sourceTree = "<group>"; };
 		17B122202090AA9300387E33 /* WXSDKInstance_performance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXSDKInstance_performance.h; sourceTree = "<group>"; };
 		17B122232090AAB000387E33 /* WXSDKError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXSDKError.h; sourceTree = "<group>"; };
@@ -641,6 +655,13 @@
 		17C74F092072145000AB4CAB /* WXAnalyzerCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXAnalyzerCenter.h; sourceTree = "<group>"; };
 		17C74F0A2072145100AB4CAB /* WXAnalyzerCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXAnalyzerCenter.m; sourceTree = "<group>"; };
 		17C74F0E2072147A00AB4CAB /* WXAnalyzerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXAnalyzerProtocol.h; sourceTree = "<group>"; };
+		17C7B4FE20452E1700A2296A /* WXCoreLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WXCoreLayout.cpp; path = Layout/WXCoreLayout.cpp; sourceTree = "<group>"; };
+		17C7B4FF20452E1800A2296A /* WXScrollerComponent+Layout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "WXScrollerComponent+Layout.mm"; path = "Layout/WXScrollerComponent+Layout.mm"; sourceTree = "<group>"; };
+		17C7B50020452E1800A2296A /* WXScrollerComponent+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "WXScrollerComponent+Layout.h"; path = "Layout/WXScrollerComponent+Layout.h"; sourceTree = "<group>"; };
+		17C7B50120452E1800A2296A /* WXCoreStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WXCoreStyle.cpp; path = Layout/WXCoreStyle.cpp; sourceTree = "<group>"; };
+		17C7B50220452E1800A2296A /* WXCoreFlexEnum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXCoreFlexEnum.h; path = Layout/WXCoreFlexEnum.h; sourceTree = "<group>"; };
+		17C7B50320452E1800A2296A /* WXCoreStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXCoreStyle.h; path = Layout/WXCoreStyle.h; sourceTree = "<group>"; };
+		17C7B50420452E1800A2296A /* WXCoreLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXCoreLayout.h; path = Layout/WXCoreLayout.h; sourceTree = "<group>"; };
 		1C1A2BEC1D91172800539AA1 /* WXConvertTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXConvertTests.m; sourceTree = "<group>"; };
 		1D3000EF1D40B9AB004F3B4F /* WXClipboardModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXClipboardModule.h; sourceTree = "<group>"; };
 		1D3000F01D40B9AB004F3B4F /* WXClipboardModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXClipboardModule.m; sourceTree = "<group>"; };
@@ -651,13 +672,13 @@
 		2A42AF891C23B33E00818EA6 /* WeexSDK_MTL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WeexSDK_MTL.m; sourceTree = "<group>"; };
 		2A4445BE1CA8FD56009E7C6D /* WXTextComponentProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXTextComponentProtocol.h; sourceTree = "<group>"; };
 		2A60CE9A1C91733E00857B9F /* WXSwitchComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXSwitchComponent.h; sourceTree = "<group>"; };
-		2A60CE9B1C91733E00857B9F /* WXSwitchComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXSwitchComponent.m; sourceTree = "<group>"; };
+		2A60CE9B1C91733E00857B9F /* WXSwitchComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXSwitchComponent.mm; sourceTree = "<group>"; };
 		2A837AAC1CD9DE9200AEDF03 /* WXLoadingComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXLoadingComponent.h; sourceTree = "<group>"; };
-		2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXLoadingComponent.m; sourceTree = "<group>"; };
+		2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXLoadingComponent.mm; sourceTree = "<group>"; };
 		2A837AAE1CD9DE9200AEDF03 /* WXLoadingIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXLoadingIndicator.h; sourceTree = "<group>"; };
 		2A837AAF1CD9DE9200AEDF03 /* WXLoadingIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXLoadingIndicator.m; sourceTree = "<group>"; };
 		2A837AB01CD9DE9200AEDF03 /* WXRefreshComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXRefreshComponent.h; sourceTree = "<group>"; };
-		2A837AB11CD9DE9200AEDF03 /* WXRefreshComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXRefreshComponent.m; sourceTree = "<group>"; };
+		2A837AB11CD9DE9200AEDF03 /* WXRefreshComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXRefreshComponent.mm; sourceTree = "<group>"; };
 		2A8E65881C7C7AA20025C7B7 /* WXVideoComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXVideoComponent.h; sourceTree = "<group>"; };
 		2A8E65891C7C7AA20025C7B7 /* WXVideoComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXVideoComponent.m; sourceTree = "<group>"; };
 		2A919DA41E321F1F006EB6B5 /* WXBridgeMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXBridgeMethod.h; sourceTree = "<group>"; };
@@ -670,9 +691,9 @@
 		2AFEB1791C747139000507FA /* WXInstanceWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXInstanceWrap.h; sourceTree = "<group>"; };
 		2AFEB17A1C747139000507FA /* WXInstanceWrap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXInstanceWrap.m; sourceTree = "<group>"; };
 		333D9A251F41507A007CED39 /* WXTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXTransition.h; sourceTree = "<group>"; };
-		333D9A261F41507A007CED39 /* WXTransition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXTransition.m; sourceTree = "<group>"; };
+		333D9A261F41507A007CED39 /* WXTransition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXTransition.mm; sourceTree = "<group>"; };
 		37B51EE21E97804D0040A743 /* WXCycleSliderComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXCycleSliderComponent.h; sourceTree = "<group>"; };
-		37B51EE31E97804D0040A743 /* WXCycleSliderComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXCycleSliderComponent.m; sourceTree = "<group>"; };
+		37B51EE31E97804D0040A743 /* WXCycleSliderComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXCycleSliderComponent.mm; sourceTree = "<group>"; };
 		591324A21D49B7F1004E89ED /* WXTimerModuleTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXTimerModuleTests.m; sourceTree = "<group>"; };
 		591DD32F1D23AD5800BE8709 /* WXErrorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXErrorView.m; sourceTree = "<group>"; };
 		591DD3301D23AD5800BE8709 /* WXErrorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXErrorView.h; sourceTree = "<group>"; };
@@ -707,6 +728,7 @@
 		59CE27E71CC387DB000BE37A /* WXEmbedComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXEmbedComponent.m; sourceTree = "<group>"; };
 		59D3CA3E1CF9ED57008835DC /* Layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Layout.c; path = Layout/Layout.c; sourceTree = "<group>"; };
 		59D3CA3F1CF9ED57008835DC /* Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Layout.h; path = Layout/Layout.h; sourceTree = "<group>"; };
+		59D3CA461CFC3CC0008835DC /* WXSliderComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXSliderComponent.mm; sourceTree = "<group>"; };
 		59D3CA481CFC3CE1008835DC /* NSTimer+Weex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+Weex.h"; sourceTree = "<group>"; };
 		59D3CA491CFC3CE1008835DC /* NSTimer+Weex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+Weex.m"; sourceTree = "<group>"; };
 		740451E81E14BB26004157CB /* WXServiceFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXServiceFactory.h; sourceTree = "<group>"; };
@@ -720,7 +742,7 @@
 		740938F81D3D0E0300DBB801 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
 		740938FA1D3D0E1700DBB801 /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; };
 		7410811D1CED585A001BC6E5 /* WXComponentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXComponentManager.h; sourceTree = "<group>"; };
-		7410811E1CED585A001BC6E5 /* WXComponentManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXComponentManager.m; sourceTree = "<group>"; };
+		7410811E1CED585A001BC6E5 /* WXComponentManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXComponentManager.mm; sourceTree = "<group>"; };
 		741081211CED6756001BC6E5 /* WXComponentFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXComponentFactory.h; sourceTree = "<group>"; };
 		741081221CED6756001BC6E5 /* WXComponentFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXComponentFactory.m; sourceTree = "<group>"; };
 		741081251CEDB4EC001BC6E5 /* WXComponent_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXComponent_internal.h; sourceTree = "<group>"; };
@@ -747,9 +769,8 @@
 		744BEA531D05178F00452B5D /* WXComponent+Display.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WXComponent+Display.h"; sourceTree = "<group>"; };
 		744BEA541D05178F00452B5D /* WXComponent+Display.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WXComponent+Display.m"; sourceTree = "<group>"; };
 		744BEA571D0520F300452B5D /* WXComponent+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "WXComponent+Layout.h"; path = "Layout/WXComponent+Layout.h"; sourceTree = "<group>"; };
-		744BEA581D0520F300452B5D /* WXComponent+Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "WXComponent+Layout.m"; path = "Layout/WXComponent+Layout.m"; sourceTree = "<group>"; };
 		744D610A1E49978200B624B3 /* WXHeaderComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXHeaderComponent.h; sourceTree = "<group>"; };
-		744D610B1E49978200B624B3 /* WXHeaderComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXHeaderComponent.m; sourceTree = "<group>"; };
+		744D610B1E49978200B624B3 /* WXHeaderComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXHeaderComponent.mm; sourceTree = "<group>"; };
 		744D610E1E49979000B624B3 /* WXFooterComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXFooterComponent.h; sourceTree = "<group>"; };
 		744D610F1E49979000B624B3 /* WXFooterComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXFooterComponent.m; sourceTree = "<group>"; };
 		744D61121E4AF23E00B624B3 /* WXDiffUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXDiffUtil.h; sourceTree = "<group>"; };
@@ -757,7 +778,7 @@
 		745B2D5E1E5A8E1E0092D38A /* WXMultiColumnLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXMultiColumnLayout.h; path = WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.h; sourceTree = SOURCE_ROOT; };
 		745B2D5F1E5A8E1E0092D38A /* WXMultiColumnLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXMultiColumnLayout.m; path = WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.m; sourceTree = SOURCE_ROOT; };
 		745B2D601E5A8E1E0092D38A /* WXRecyclerComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXRecyclerComponent.h; path = WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.h; sourceTree = SOURCE_ROOT; };
-		745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXRecyclerComponent.m; path = WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m; sourceTree = SOURCE_ROOT; };
+		745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WXRecyclerComponent.mm; path = WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.mm; sourceTree = SOURCE_ROOT; };
 		745B2D621E5A8E1E0092D38A /* WXRecyclerDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXRecyclerDataController.h; path = WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.h; sourceTree = SOURCE_ROOT; };
 		745B2D631E5A8E1E0092D38A /* WXRecyclerDataController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXRecyclerDataController.m; path = WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.m; sourceTree = SOURCE_ROOT; };
 		745B2D641E5A8E1E0092D38A /* WXRecyclerUpdateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXRecyclerUpdateController.h; path = WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.h; sourceTree = SOURCE_ROOT; };
@@ -780,9 +801,9 @@
 		7469869D1C4E2C000054A57E /* NSArray+Weex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Weex.h"; sourceTree = "<group>"; };
 		7469869E1C4E2C000054A57E /* NSArray+Weex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Weex.m"; sourceTree = "<group>"; };
 		746B92391F46BE36009AE86B /* WXCellSlotComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXCellSlotComponent.h; sourceTree = "<group>"; };
-		746B923A1F46BE36009AE86B /* WXCellSlotComponent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WXCellSlotComponent.m; sourceTree = "<group>"; };
+		746B923A1F46BE36009AE86B /* WXCellSlotComponent.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WXCellSlotComponent.mm; sourceTree = "<group>"; };
 		747A787A1D1BAAC900DED9D0 /* WXComponent+ViewManagement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WXComponent+ViewManagement.h"; sourceTree = "<group>"; };
-		747A787B1D1BAAC900DED9D0 /* WXComponent+ViewManagement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WXComponent+ViewManagement.m"; sourceTree = "<group>"; };
+		747A787B1D1BAAC900DED9D0 /* WXComponent+ViewManagement.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "WXComponent+ViewManagement.mm"; sourceTree = "<group>"; };
 		747DF6801E31AEE4005C53A8 /* WXLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXLength.h; sourceTree = "<group>"; };
 		747DF6811E31AEE4005C53A8 /* WXLength.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXLength.m; sourceTree = "<group>"; };
 		74862F771E02B88D00B7A041 /* JSValue+Weex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JSValue+Weex.h"; sourceTree = "<group>"; };
@@ -826,11 +847,11 @@
 		74C8963F1D2AC2210043B82A /* WeexSDKTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WeexSDKTests.m; sourceTree = "<group>"; };
 		74C896411D2AC2210043B82A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		74CC7A1A1C2BC5F800829368 /* WXCellComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXCellComponent.h; sourceTree = "<group>"; };
-		74CC7A1B1C2BC5F800829368 /* WXCellComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXCellComponent.m; sourceTree = "<group>"; };
+		74CC7A1B1C2BC5F800829368 /* WXCellComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXCellComponent.mm; sourceTree = "<group>"; };
 		74CC7A1E1C2BF9DC00829368 /* WXListComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXListComponent.h; sourceTree = "<group>"; };
-		74CC7A1F1C2BF9DC00829368 /* WXListComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXListComponent.m; sourceTree = "<group>"; };
+		74CC7A1F1C2BF9DC00829368 /* WXListComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXListComponent.mm; sourceTree = "<group>"; };
 		74CFDD371F45939C007A1A66 /* WXRecycleListComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXRecycleListComponent.h; sourceTree = "<group>"; };
-		74CFDD381F45939C007A1A66 /* WXRecycleListComponent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WXRecycleListComponent.m; sourceTree = "<group>"; };
+		74CFDD381F45939C007A1A66 /* WXRecycleListComponent.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WXRecycleListComponent.mm; sourceTree = "<group>"; };
 		74CFDD3B1F459400007A1A66 /* WXRecycleListDataManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXRecycleListDataManager.h; sourceTree = "<group>"; };
 		74CFDD3C1F459400007A1A66 /* WXRecycleListDataManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WXRecycleListDataManager.m; sourceTree = "<group>"; };
 		74CFDD3F1F45941E007A1A66 /* WXRecycleListTemplateManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXRecycleListTemplateManager.h; sourceTree = "<group>"; };
@@ -858,7 +879,7 @@
 		77D161261C02DE1A0010B15B /* WXSDKManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXSDKManager.h; sourceTree = "<group>"; };
 		77D161271C02DE1A0010B15B /* WXSDKManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXSDKManager.m; sourceTree = "<group>"; };
 		77D1612E1C02DE4E0010B15B /* WXComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXComponent.h; path = ../Model/WXComponent.h; sourceTree = "<group>"; };
-		77D1612F1C02DE4E0010B15B /* WXComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXComponent.m; path = ../Model/WXComponent.m; sourceTree = "<group>"; };
+		77D1612F1C02DE4E0010B15B /* WXComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WXComponent.mm; path = ../Model/WXComponent.mm; sourceTree = "<group>"; };
 		77D161361C02DE940010B15B /* WXBridgeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXBridgeManager.h; sourceTree = "<group>"; };
 		77D161371C02DE940010B15B /* WXBridgeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXBridgeManager.m; sourceTree = "<group>"; };
 		77D1613A1C02DEA60010B15B /* WXJSCoreBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXJSCoreBridge.h; sourceTree = "<group>"; };
@@ -879,11 +900,13 @@
 		77E65A0F1C155EA8008B8775 /* WXImageComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXImageComponent.h; sourceTree = "<group>"; };
 		77E65A101C155EA8008B8775 /* WXImageComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXImageComponent.m; sourceTree = "<group>"; };
 		77E65A131C155EB5008B8775 /* WXTextComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXTextComponent.h; sourceTree = "<group>"; };
-		77E65A141C155EB5008B8775 /* WXTextComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXTextComponent.m; sourceTree = "<group>"; };
+		77E65A141C155EB5008B8775 /* WXTextComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXTextComponent.mm; sourceTree = "<group>"; };
 		77E65A171C155F25008B8775 /* WXScrollerComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXScrollerComponent.h; sourceTree = "<group>"; };
-		77E65A181C155F25008B8775 /* WXScrollerComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXScrollerComponent.m; sourceTree = "<group>"; };
+		77E65A181C155F25008B8775 /* WXScrollerComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXScrollerComponent.mm; sourceTree = "<group>"; };
 		841CD1021F9739890081196D /* WXExceptionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXExceptionUtils.m; sourceTree = "<group>"; };
 		841CD1041F97399C0081196D /* WXExceptionUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXExceptionUtils.h; sourceTree = "<group>"; };
+		8431F8DD1F9EFCC100C76E1E /* WXScrollerComponent+Layout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "WXScrollerComponent+Layout.mm"; path = "Layout/WXScrollerComponent+Layout.mm"; sourceTree = "<group>"; };
+		847E1DE01F9A1BCF00A48124 /* WXCoreStyle.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; name = WXCoreStyle.h; path = Layout/WXCoreStyle.h; sourceTree = "<group>"; };
 		9B9E74771FA2DB5800DAAEA9 /* WXTestBridgeMethodDummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXTestBridgeMethodDummy.h; sourceTree = "<group>"; };
 		9B9E74781FA2DB5800DAAEA9 /* WXTestBridgeMethodDummy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXTestBridgeMethodDummy.m; sourceTree = "<group>"; };
 		BA5F00EF1FC5AFFE00F76B5C /* WXLocaleModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXLocaleModule.h; sourceTree = "<group>"; };
@@ -898,7 +921,7 @@
 		C47B78CC1F2998EE001D3B0C /* WXExtendCallNativeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXExtendCallNativeManager.h; sourceTree = "<group>"; };
 		C47B78CD1F2998EE001D3B0C /* WXExtendCallNativeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXExtendCallNativeManager.m; sourceTree = "<group>"; };
 		C4B3D6D21E6954300013F38D /* WXEditComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXEditComponent.h; sourceTree = "<group>"; };
-		C4B3D6D31E6954300013F38D /* WXEditComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXEditComponent.m; sourceTree = "<group>"; };
+		C4B3D6D31E6954300013F38D /* WXEditComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXEditComponent.mm; sourceTree = "<group>"; };
 		C4B834251DE69B09007AD27E /* WXPickerModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXPickerModule.m; sourceTree = "<group>"; };
 		C4B834261DE69B09007AD27E /* WXPickerModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXPickerModule.h; sourceTree = "<group>"; };
 		C4C30DE61E1B833D00786B6C /* WXComponent+PseudoClassManagement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WXComponent+PseudoClassManagement.m"; sourceTree = "<group>"; };
@@ -929,7 +952,7 @@
 		D3FC0DF51C508B2A002B9E31 /* WXTimerModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXTimerModule.h; sourceTree = "<group>"; };
 		D3FC0DF61C508B2A002B9E31 /* WXTimerModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXTimerModule.m; sourceTree = "<group>"; };
 		DAB176F008F516E4F9391C61 /* libPods-WeexSDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WeexSDK.a"; sourceTree = BUILT_PRODUCTS_DIR; };
-		DC03ADB71D508719003F76E7 /* WXTextAreaComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXTextAreaComponent.m; sourceTree = "<group>"; };
+		DC03ADB71D508719003F76E7 /* WXTextAreaComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXTextAreaComponent.mm; sourceTree = "<group>"; };
 		DC03ADB81D508719003F76E7 /* WXTextAreaComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXTextAreaComponent.h; sourceTree = "<group>"; };
 		DC15A3D92010BC93009C8977 /* weex-main-jsfm.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "weex-main-jsfm.js"; path = "../../../../pre-build/weex-main-jsfm.js"; sourceTree = "<group>"; };
 		DC15A3DA2010BC93009C8977 /* weex-rax-api.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "weex-rax-api.js"; path = "../../../../pre-build/weex-rax-api.js"; sourceTree = "<group>"; };
@@ -946,7 +969,7 @@
 		DCA446261EFA5DAF00D0CFA8 /* WeexSDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeexSDK.h; sourceTree = "<group>"; };
 		DCAB35FC1D658EB700C0EA70 /* WXRuleManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXRuleManager.h; sourceTree = "<group>"; };
 		DCAB35FD1D658EB700C0EA70 /* WXRuleManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXRuleManager.m; sourceTree = "<group>"; };
-		DCC77C111D770AE300CE7288 /* WXSliderNeighborComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXSliderNeighborComponent.m; sourceTree = "<group>"; };
+		DCC77C111D770AE300CE7288 /* WXSliderNeighborComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXSliderNeighborComponent.mm; sourceTree = "<group>"; };
 		DCC77C121D770AE300CE7288 /* WXSliderNeighborComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXSliderNeighborComponent.h; sourceTree = "<group>"; };
 		DCD8D0F22073392A0002C420 /* weex-polyfill.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "weex-polyfill.js"; path = "../../../../pre-build/weex-polyfill.js"; sourceTree = "<group>"; };
 		DCDFED001E68238F00C228D7 /* WXJSExceptionProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXJSExceptionProtocol.h; sourceTree = "<group>"; };
@@ -1003,6 +1026,16 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		17B12228209170CF00387E33 /* Recovered References */ = {
+			isa = PBXGroup;
+			children = (
+				8431F8DD1F9EFCC100C76E1E /* WXScrollerComponent+Layout.mm */,
+				59D3CA461CFC3CC0008835DC /* WXSliderComponent.mm */,
+				847E1DE01F9A1BCF00A48124 /* WXCoreStyle.h */,
+			);
+			name = "Recovered References";
+			sourceTree = "<group>";
+		};
 		2A42AF861C23B33E00818EA6 /* WeexSDK_MTL */ = {
 			isa = PBXGroup;
 			children = (
@@ -1015,10 +1048,17 @@
 		2AF626C61C191E2200E71A38 /* Layout */ = {
 			isa = PBXGroup;
 			children = (
+				176BE43B209172330086B6AF /* WXComponent+Layout.mm */,
+				17C7B50220452E1800A2296A /* WXCoreFlexEnum.h */,
+				17C7B4FE20452E1700A2296A /* WXCoreLayout.cpp */,
+				17C7B50420452E1800A2296A /* WXCoreLayout.h */,
+				17C7B50120452E1800A2296A /* WXCoreStyle.cpp */,
+				17C7B50320452E1800A2296A /* WXCoreStyle.h */,
+				17C7B50020452E1800A2296A /* WXScrollerComponent+Layout.h */,
+				17C7B4FF20452E1800A2296A /* WXScrollerComponent+Layout.mm */,
 				59D3CA3E1CF9ED57008835DC /* Layout.c */,
 				59D3CA3F1CF9ED57008835DC /* Layout.h */,
 				744BEA571D0520F300452B5D /* WXComponent+Layout.h */,
-				744BEA581D0520F300452B5D /* WXComponent+Layout.m */,
 				74B232D11D2A2BA4006322EA /* WXLayoutDefine.h */,
 			);
 			name = Layout;
@@ -1076,7 +1116,7 @@
 				591DD3301D23AD5800BE8709 /* WXErrorView.h */,
 				591DD32F1D23AD5800BE8709 /* WXErrorView.m */,
 				747A787A1D1BAAC900DED9D0 /* WXComponent+ViewManagement.h */,
-				747A787B1D1BAAC900DED9D0 /* WXComponent+ViewManagement.m */,
+				747A787B1D1BAAC900DED9D0 /* WXComponent+ViewManagement.mm */,
 				74B8BEFC1DC47B72004A6027 /* WXRootView.h */,
 				74B8BEFD1DC47B72004A6027 /* WXRootView.m */,
 			);
@@ -1177,7 +1217,7 @@
 			isa = PBXGroup;
 			children = (
 				74CFDD371F45939C007A1A66 /* WXRecycleListComponent.h */,
-				74CFDD381F45939C007A1A66 /* WXRecycleListComponent.m */,
+				74CFDD381F45939C007A1A66 /* WXRecycleListComponent.mm */,
 				74CFDD3B1F459400007A1A66 /* WXRecycleListDataManager.h */,
 				74CFDD3C1F459400007A1A66 /* WXRecycleListDataManager.m */,
 				74CFDD3F1F45941E007A1A66 /* WXRecycleListTemplateManager.h */,
@@ -1187,7 +1227,7 @@
 				74BA4AB11F70F4B600AC29BF /* WXRecycleListLayout.h */,
 				74BA4AB21F70F4B600AC29BF /* WXRecycleListLayout.m */,
 				746B92391F46BE36009AE86B /* WXCellSlotComponent.h */,
-				746B923A1F46BE36009AE86B /* WXCellSlotComponent.m */,
+				746B923A1F46BE36009AE86B /* WXCellSlotComponent.mm */,
 				7423EB4F1F4ADE30001662D1 /* WXComponent+DataBinding.h */,
 				7423EB501F4ADE30001662D1 /* WXComponent+DataBinding.mm */,
 				74BF19F61F5139BB00AEE3D7 /* WXJSASTParser.h */,
@@ -1204,7 +1244,7 @@
 				745B2D5E1E5A8E1E0092D38A /* WXMultiColumnLayout.h */,
 				745B2D5F1E5A8E1E0092D38A /* WXMultiColumnLayout.m */,
 				745B2D601E5A8E1E0092D38A /* WXRecyclerComponent.h */,
-				745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.m */,
+				745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.mm */,
 				745B2D621E5A8E1E0092D38A /* WXRecyclerDataController.h */,
 				745B2D631E5A8E1E0092D38A /* WXRecyclerDataController.m */,
 				745B2D641E5A8E1E0092D38A /* WXRecyclerUpdateController.h */,
@@ -1243,6 +1283,7 @@
 				DCA445261EFA555400D0CFA8 /* WeexSDK-Dynamic */,
 				77D160FE1C02DBE70010B15B /* Products */,
 				A5818E244F9E235722E3B938 /* Frameworks */,
+				17B12228209170CF00387E33 /* Recovered References */,
 			);
 			sourceTree = "<group>";
 		};
@@ -1351,7 +1392,7 @@
 				74A4BA9C1CB3C0A100195969 /* WXHandlerFactory.h */,
 				74A4BA9D1CB3C0A100195969 /* WXHandlerFactory.m */,
 				7410811D1CED585A001BC6E5 /* WXComponentManager.h */,
-				7410811E1CED585A001BC6E5 /* WXComponentManager.m */,
+				7410811E1CED585A001BC6E5 /* WXComponentManager.mm */,
 				741081211CED6756001BC6E5 /* WXComponentFactory.h */,
 				741081221CED6756001BC6E5 /* WXComponentFactory.m */,
 				DCAB35FC1D658EB700C0EA70 /* WXRuleManager.h */,
@@ -1461,7 +1502,7 @@
 				DCE2CF981F46D4220021BDC4 /* WXVoiceOverModule.m */,
 				DCE2CF991F46D4220021BDC4 /* WXVoiceOverModule.h */,
 				333D9A251F41507A007CED39 /* WXTransition.h */,
-				333D9A261F41507A007CED39 /* WXTransition.m */,
+				333D9A261F41507A007CED39 /* WXTransition.mm */,
 				C43C03E41EC8ACA40044C7FF /* WXPrerenderManager.h */,
 				C43C03E51EC8ACA40044C7FF /* WXPrerenderManager.m */,
 				C4F012801E1502E9003378D0 /* WXWebSocketModule.h */,
@@ -1502,56 +1543,56 @@
 			isa = PBXGroup;
 			children = (
 				C4B3D6D21E6954300013F38D /* WXEditComponent.h */,
-				C4B3D6D31E6954300013F38D /* WXEditComponent.m */,
+				C4B3D6D31E6954300013F38D /* WXEditComponent.mm */,
 				74CFDD361F45937D007A1A66 /* RecycleList */,
 				74D8DB401E4825920078B667 /* Recycler */,
 				2A837AAC1CD9DE9200AEDF03 /* WXLoadingComponent.h */,
-				2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.m */,
+				2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.mm */,
 				2A837AAE1CD9DE9200AEDF03 /* WXLoadingIndicator.h */,
-				DCC77C111D770AE300CE7288 /* WXSliderNeighborComponent.m */,
+				DCC77C111D770AE300CE7288 /* WXSliderNeighborComponent.mm */,
 				DCC77C121D770AE300CE7288 /* WXSliderNeighborComponent.h */,
 				2A837AAF1CD9DE9200AEDF03 /* WXLoadingIndicator.m */,
 				2A837AB01CD9DE9200AEDF03 /* WXRefreshComponent.h */,
-				2A837AB11CD9DE9200AEDF03 /* WXRefreshComponent.m */,
+				2A837AB11CD9DE9200AEDF03 /* WXRefreshComponent.mm */,
 				59CE27E61CC387DB000BE37A /* WXEmbedComponent.h */,
 				59CE27E71CC387DB000BE37A /* WXEmbedComponent.m */,
 				2A8E65881C7C7AA20025C7B7 /* WXVideoComponent.h */,
 				2A8E65891C7C7AA20025C7B7 /* WXVideoComponent.m */,
 				77D1612E1C02DE4E0010B15B /* WXComponent.h */,
-				77D1612F1C02DE4E0010B15B /* WXComponent.m */,
+				77D1612F1C02DE4E0010B15B /* WXComponent.mm */,
 				77E65A0B1C155E99008B8775 /* WXDivComponent.h */,
 				77E65A0C1C155E99008B8775 /* WXDivComponent.m */,
 				77E65A0F1C155EA8008B8775 /* WXImageComponent.h */,
 				77E65A101C155EA8008B8775 /* WXImageComponent.m */,
 				77E65A131C155EB5008B8775 /* WXTextComponent.h */,
-				77E65A141C155EB5008B8775 /* WXTextComponent.m */,
+				77E65A141C155EB5008B8775 /* WXTextComponent.mm */,
 				77E65A171C155F25008B8775 /* WXScrollerComponent.h */,
-				77E65A181C155F25008B8775 /* WXScrollerComponent.m */,
+				77E65A181C155F25008B8775 /* WXScrollerComponent.mm */,
 				37B51EE21E97804D0040A743 /* WXCycleSliderComponent.h */,
-				37B51EE31E97804D0040A743 /* WXCycleSliderComponent.m */,
-				74CC7A1B1C2BC5F800829368 /* WXCellComponent.m */,
+				37B51EE31E97804D0040A743 /* WXCycleSliderComponent.mm */,
+				74CC7A1B1C2BC5F800829368 /* WXCellComponent.mm */,
 				74CC7A1E1C2BF9DC00829368 /* WXListComponent.h */,
-				74CC7A1F1C2BF9DC00829368 /* WXListComponent.m */,
+				74CC7A1F1C2BF9DC00829368 /* WXListComponent.mm */,
 				2AC750221C7565690041D390 /* WXIndicatorComponent.h */,
 				2AC750231C7565690041D390 /* WXIndicatorComponent.m */,
 				74CC7A1A1C2BC5F800829368 /* WXCellComponent.h */,
 				2A1F57B51C75C6A600B58017 /* WXTextInputComponent.h */,
 				2A1F57B61C75C6A600B58017 /* WXTextInputComponent.m */,
 				DC03ADB81D508719003F76E7 /* WXTextAreaComponent.h */,
-				DC03ADB71D508719003F76E7 /* WXTextAreaComponent.m */,
+				DC03ADB71D508719003F76E7 /* WXTextAreaComponent.mm */,
 				D317338A1C57257000BB7539 /* WXTransform.h */,
 				D317338B1C57257000BB7539 /* WXTransform.m */,
 				D312CE391C730DEB00046D68 /* WXWebComponent.h */,
 				D312CE3A1C730DEB00046D68 /* WXWebComponent.m */,
 				2A60CE9A1C91733E00857B9F /* WXSwitchComponent.h */,
-				2A60CE9B1C91733E00857B9F /* WXSwitchComponent.m */,
+				2A60CE9B1C91733E00857B9F /* WXSwitchComponent.mm */,
 				2AE5B7501CAB7DBD0082FDDB /* WXAComponent.h */,
 				2AE5B7511CAB7DBD0082FDDB /* WXAComponent.m */,
 				741081251CEDB4EC001BC6E5 /* WXComponent_internal.h */,
 				D33451061D3E19480083598A /* WXCanvasComponent.h */,
 				D33451071D3E19480083598A /* WXCanvasComponent.m */,
 				744D610A1E49978200B624B3 /* WXHeaderComponent.h */,
-				744D610B1E49978200B624B3 /* WXHeaderComponent.m */,
+				744D610B1E49978200B624B3 /* WXHeaderComponent.mm */,
 				744D610E1E49979000B624B3 /* WXFooterComponent.h */,
 				744D610F1E49979000B624B3 /* WXFooterComponent.m */,
 			);
@@ -1662,6 +1703,7 @@
 				74BB5FB91DFEE81A004FC3DF /* WXMetaModule.h in Headers */,
 				DCA0EF641D6EED6F00CB18B9 /* WXGlobalEventModule.h in Headers */,
 				2A837AB21CD9DE9200AEDF03 /* WXLoadingComponent.h in Headers */,
+				17E5ACD82091F02D00EE81F1 /* WXCoreLayout.h in Headers */,
 				DCA446271EFA5DAF00D0CFA8 /* WeexSDK.h in Headers */,
 				841CD1051F974DFA0081196D /* WXExceptionUtils.h in Headers */,
 				745B2D6A1E5A8E1E0092D38A /* WXRecyclerComponent.h in Headers */,
@@ -1686,6 +1728,7 @@
 				741DFE021DDD7D18009B020F /* WXRoundedRect.h in Headers */,
 				17C74F0F2072147B00AB4CAB /* WXAnalyzerProtocol.h in Headers */,
 				7423899B1C3174EB00D748CA /* WXWeakObjectWrapper.h in Headers */,
+				17C7B50A20452E1800A2296A /* WXCoreFlexEnum.h in Headers */,
 				74BF19F81F5139BB00AEE3D7 /* WXJSASTParser.h in Headers */,
 				59A596191CB630E50012CD52 /* WXNavigationProtocol.h in Headers */,
 				59A5962F1CB632050012CD52 /* WXBaseViewController.h in Headers */,
@@ -1718,9 +1761,11 @@
 				77E659F11C0C3612008B8775 /* WXModuleFactory.h in Headers */,
 				77D161431C02DEE40010B15B /* WXBridgeProtocol.h in Headers */,
 				59A582D41CF481110081FD3E /* WXAppMonitorProtocol.h in Headers */,
+				847E1DE41F9A1BCF00A48124 /* WXCoreStyle.h in Headers */,
 				2A837AB61CD9DE9200AEDF03 /* WXRefreshComponent.h in Headers */,
 				C43C03E81EC8ACA40044C7FF /* WXPrerenderManager.h in Headers */,
 				17C74F0C2072145100AB4CAB /* WXAnalyzerCenter.h in Headers */,
+				17C7B50B20452E1800A2296A /* WXCoreStyle.h in Headers */,
 				74B232D21D2A2BA4006322EA /* WXLayoutDefine.h in Headers */,
 				C4B834281DE69B09007AD27E /* WXPickerModule.h in Headers */,
 				59A596311CB632050012CD52 /* WXRootViewController.h in Headers */,
@@ -1731,6 +1776,7 @@
 				74CC7A1C1C2BC5F800829368 /* WXCellComponent.h in Headers */,
 				74896F301D1AC79400D1D593 /* NSObject+WXSwizzle.h in Headers */,
 				DCF343671E49CAEE00A2FB34 /* WXJSExceptionInfo.h in Headers */,
+				17C7B50820452E1800A2296A /* WXScrollerComponent+Layout.h in Headers */,
 				C4F012821E1502E9003378D0 /* WXWebSocketModule.h in Headers */,
 				74EF31AA1DE58AE600667A07 /* WXURLRewriteProtocol.h in Headers */,
 				59A596241CB6311F0012CD52 /* WXStorageModule.h in Headers */,
@@ -1781,10 +1827,10 @@
 				170B4665208733BF00562666 /* WXAnalyzerCenter+Transfer.h in Headers */,
 				DCA445A01EFA56F400D0CFA8 /* WXType.h in Headers */,
 				DCA445B21EFA576D00D0CFA8 /* WXListComponent.h in Headers */,
-				333D9A281F41507A007CED39 /* WXTransition.h in Headers */,
 				DCA445AD1EFA575100D0CFA8 /* WXNavigationProtocol.h in Headers */,
 				DCA445B01EFA576200D0CFA8 /* WXModalUIModule.h in Headers */,
 				DCA445A61EFA571E00D0CFA8 /* WXSDKEngine.h in Headers */,
+				17E5ACDA2091F05000EE81F1 /* WXCoreFlexEnum.h in Headers */,
 				DCA445AA1EFA573900D0CFA8 /* WXResourceRequest.h in Headers */,
 				DCA445C61EFA57EE00D0CFA8 /* NSObject+WXSwizzle.h in Headers */,
 				74B81AEB1F73C3E900D3A61D /* WXRecycleListLayout.h in Headers */,
@@ -1827,6 +1873,7 @@
 				DCA445DB1EFA59AA00D0CFA8 /* WXRecyclerComponent.h in Headers */,
 				DCA445CD1EFA592E00D0CFA8 /* WXComponent+Events.h in Headers */,
 				DCA445EC1EFA5A0E00D0CFA8 /* WXTextAreaComponent.h in Headers */,
+				17E5ACD92091F03700EE81F1 /* WXCoreStyle.h in Headers */,
 				DCA445D81EFA599400D0CFA8 /* WXRootView.h in Headers */,
 				DCA446131EFA5A8C00D0CFA8 /* WXCallJSMethod.h in Headers */,
 				BA5F00F31FC6834900F76B5C /* WXLocaleModule.h in Headers */,
@@ -1880,6 +1927,8 @@
 				DCA445E61EFA59E500D0CFA8 /* WXImageComponent.h in Headers */,
 				DCA4461B1EFA5AA200D0CFA8 /* WXDatePickerManager.h in Headers */,
 				DCA445D71EFA598D00D0CFA8 /* WXComponent+ViewManagement.h in Headers */,
+				178EDF0D204FEC1300917F6B /* WXScrollerComponent+Layout.h in Headers */,
+				DCA445DB1EFA59AA00D0CFA8 /* WXRecyclerComponent.h in Headers */,
 				DCA445D31EFA594A00D0CFA8 /* WXRoundedRect.h in Headers */,
 				DCA445EA1EFA5A0300D0CFA8 /* WXCellComponent.h in Headers */,
 				DCA446201EFA5AB800D0CFA8 /* WXComponent+Navigation.h in Headers */,
@@ -1911,6 +1960,7 @@
 				DCA4460C1EFA5A7600D0CFA8 /* WXThreadSafeMutableDictionary.h in Headers */,
 				DCA445CE1EFA593500D0CFA8 /* WXComponent+BoxShadow.h in Headers */,
 				74B81AF11F73C3E900D3A61D /* WXJSASTParser.h in Headers */,
+				178EDF0F204FF11700917F6B /* WXCoreLayout.h in Headers */,
 				DCA4461C1EFA5AA600D0CFA8 /* WXModuleFactory.h in Headers */,
 				DCA445D91EFA59A100D0CFA8 /* WXEditComponent.h in Headers */,
 				DCA445FB1EFA5A3C00D0CFA8 /* WXStorageModule.h in Headers */,
@@ -2165,6 +2215,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				176BE43E209172E20086B6AF /* WXScrollerComponent+Layout.mm in Sources */,
 				77D161291C02DE1A0010B15B /* WXSDKManager.m in Sources */,
 				7461F8911CFB373100F62D44 /* WXDisplayQueue.m in Sources */,
 				74896F311D1AC79400D1D593 /* NSObject+WXSwizzle.m in Sources */,
@@ -2175,14 +2226,14 @@
 				747DF6831E31AEE4005C53A8 /* WXLength.m in Sources */,
 				77E65A0E1C155E99008B8775 /* WXDivComponent.m in Sources */,
 				ED053502207F4DEB007B4568 /* JSContext+Weex.m in Sources */,
-				2A60CE9D1C91733E00857B9F /* WXSwitchComponent.m in Sources */,
+				2A60CE9D1C91733E00857B9F /* WXSwitchComponent.mm in Sources */,
 				744D61111E49979000B624B3 /* WXFooterComponent.m in Sources */,
 				745B2D6F1E5A8E1E0092D38A /* WXRecyclerUpdateController.m in Sources */,
-				745B2D6B1E5A8E1E0092D38A /* WXRecyclerComponent.m in Sources */,
-				2A837AB71CD9DE9200AEDF03 /* WXRefreshComponent.m in Sources */,
+				745B2D6B1E5A8E1E0092D38A /* WXRecyclerComponent.mm in Sources */,
+				2A837AB71CD9DE9200AEDF03 /* WXRefreshComponent.mm in Sources */,
 				74A4BA9B1CB3BAA100195969 /* WXThreadSafeMutableDictionary.m in Sources */,
-				77E65A1A1C155F25008B8775 /* WXScrollerComponent.m in Sources */,
-				747A787D1D1BAAC900DED9D0 /* WXComponent+ViewManagement.m in Sources */,
+				77E65A1A1C155F25008B8775 /* WXScrollerComponent.mm in Sources */,
+				747A787D1D1BAAC900DED9D0 /* WXComponent+ViewManagement.mm in Sources */,
 				C4E375371E5FCBD3009B2D9C /* WXComponent+BoxShadow.m in Sources */,
 				C43C03E91EC8ACA40044C7FF /* WXPrerenderManager.m in Sources */,
 				2A837AB51CD9DE9200AEDF03 /* WXLoadingIndicator.m in Sources */,
@@ -2190,7 +2241,7 @@
 				59D3CA401CF9ED57008835DC /* Layout.c in Sources */,
 				DCF087621DCAE161005CD6EB /* WXInvocationConfig.m in Sources */,
 				C47B78CF1F2998EE001D3B0C /* WXExtendCallNativeManager.m in Sources */,
-				77D161311C02DE4E0010B15B /* WXComponent.m in Sources */,
+				77D161311C02DE4E0010B15B /* WXComponent.mm in Sources */,
 				74CFDD461F459443007A1A66 /* WXRecycleListUpdateManager.m in Sources */,
 				74862F7A1E02B88D00B7A041 /* JSValue+Weex.m in Sources */,
 				740451EB1E14BB26004157CB /* WXServiceFactory.m in Sources */,
@@ -2200,12 +2251,12 @@
 				59A5961D1CB630F10012CD52 /* WXComponent+Navigation.m in Sources */,
 				77D161631C02ED790010B15B /* WXLog.m in Sources */,
 				17C74F0D2072145100AB4CAB /* WXAnalyzerCenter.m in Sources */,
-				744BEA5A1D0520F300452B5D /* WXComponent+Layout.m in Sources */,
 				59A582FD1CF5B17B0081FD3E /* WXBridgeContext.m in Sources */,
+				17C7B50620452E1800A2296A /* WXCoreLayout.cpp in Sources */,
 				743933B51C7ED9AA00773BB7 /* WXSimulatorShortcutManager.m in Sources */,
 				BA5F00F21FC5AFFE00F76B5C /* WXLocaleModule.m in Sources */,
 				74BB5FBA1DFEE81A004FC3DF /* WXMetaModule.m in Sources */,
-				741081201CED585A001BC6E5 /* WXComponentManager.m in Sources */,
+				741081201CED585A001BC6E5 /* WXComponentManager.mm in Sources */,
 				1D3000F21D40B9AC004F3B4F /* WXClipboardModule.m in Sources */,
 				741DFE071DDD9B30009B020F /* UIBezierPath+Weex.m in Sources */,
 				D312CE3C1C730DEB00046D68 /* WXWebComponent.m in Sources */,
@@ -2217,15 +2268,15 @@
 				591DD3311D23AD5800BE8709 /* WXErrorView.m in Sources */,
 				59D3CA4B1CFC3CE1008835DC /* NSTimer+Weex.m in Sources */,
 				59A596321CB632050012CD52 /* WXRootViewController.m in Sources */,
-				DCC77C131D770AE300CE7288 /* WXSliderNeighborComponent.m in Sources */,
+				DCC77C131D770AE300CE7288 /* WXSliderNeighborComponent.mm in Sources */,
 				2A8E658B1C7C7AA20025C7B7 /* WXVideoComponent.m in Sources */,
 				74862F7E1E03A0F300B7A041 /* WXModuleMethod.m in Sources */,
 				742AD7341DF98C45007DC46C /* WXResourceResponse.m in Sources */,
-				77E65A161C155EB5008B8775 /* WXTextComponent.m in Sources */,
+				77E65A161C155EB5008B8775 /* WXTextComponent.mm in Sources */,
 				C4D872261E5DDF7500E39BC1 /* WXBoxShadow.m in Sources */,
 				746319031C60AFC100EFEBD4 /* WXThreadSafeCounter.m in Sources */,
 				74A4BAA71CB4F98300195969 /* WXStreamModule.m in Sources */,
-				744D610D1E49978200B624B3 /* WXHeaderComponent.m in Sources */,
+				744D610D1E49978200B624B3 /* WXHeaderComponent.mm in Sources */,
 				77E659F21C0C3612008B8775 /* WXModuleFactory.m in Sources */,
 				DCF343681E49CAEE00A2FB34 /* WXJSExceptionInfo.m in Sources */,
 				59CE27E91CC387DB000BE37A /* WXEmbedComponent.m in Sources */,
@@ -2238,8 +2289,9 @@
 				744D61151E4AF23E00B624B3 /* WXDiffUtil.m in Sources */,
 				74EF31AE1DE58BE200667A07 /* WXURLRewriteDefaultImpl.m in Sources */,
 				17B122262090AAB000387E33 /* WXSDKError.m in Sources */,
-				C4B3D6D51E6954300013F38D /* WXEditComponent.m in Sources */,
+				C4B3D6D51E6954300013F38D /* WXEditComponent.mm in Sources */,
 				C4C30DE81E1B833D00786B6C /* WXComponent+PseudoClassManagement.m in Sources */,
+				17C7B50920452E1800A2296A /* WXCoreStyle.cpp in Sources */,
 				74915F481C8EB02B00BEBCC0 /* WXAssert.m in Sources */,
 				59A596251CB6311F0012CD52 /* WXStorageModule.m in Sources */,
 				2AFEB17C1C747139000507FA /* WXInstanceWrap.m in Sources */,
@@ -2251,17 +2303,17 @@
 				745B2D711E5A8E1E0092D38A /* WXSectionDataController.m in Sources */,
 				DCE2CF9A1F46D4220021BDC4 /* WXVoiceOverModule.m in Sources */,
 				2A1F57B81C75C6A600B58017 /* WXTextInputComponent.m in Sources */,
-				74CC7A1D1C2BC5F800829368 /* WXCellComponent.m in Sources */,
+				74CC7A1D1C2BC5F800829368 /* WXCellComponent.mm in Sources */,
 				74862F821E03A24500B7A041 /* WXComponentMethod.m in Sources */,
 				77E65A121C155EA8008B8775 /* WXImageComponent.m in Sources */,
 				74CFDD3E1F459400007A1A66 /* WXRecycleListDataManager.m in Sources */,
-				2A837AB31CD9DE9200AEDF03 /* WXLoadingComponent.m in Sources */,
+				2A837AB31CD9DE9200AEDF03 /* WXLoadingComponent.mm in Sources */,
 				2AE5B7531CAB7DBD0082FDDB /* WXAComponent.m in Sources */,
-				333D9A291F41507A007CED39 /* WXTransition.m in Sources */,
-				74CFDD3A1F45939C007A1A66 /* WXRecycleListComponent.m in Sources */,
+				176BE43C209172330086B6AF /* WXComponent+Layout.mm in Sources */,
+				74CFDD3A1F45939C007A1A66 /* WXRecycleListComponent.mm in Sources */,
 				741DFE031DDD7D18009B020F /* WXRoundedRect.mm in Sources */,
 				59A596301CB632050012CD52 /* WXBaseViewController.m in Sources */,
-				74CC7A211C2BF9DC00829368 /* WXListComponent.m in Sources */,
+				74CC7A211C2BF9DC00829368 /* WXListComponent.mm in Sources */,
 				7423899C1C3174EB00D748CA /* WXWeakObjectWrapper.m in Sources */,
 				744BEA561D05178F00452B5D /* WXComponent+Display.m in Sources */,
 				7408C48F1CFB

<TRUNCATED>


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXSliderNeighborComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXSliderNeighborComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXSliderNeighborComponent.mm
new file mode 100644
index 0000000..86124ff
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXSliderNeighborComponent.mm
@@ -0,0 +1,1812 @@
+/*
+ * 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 "WXSliderNeighborComponent.h"
+#import "WXConvert.h"
+#import "WXUtility.h"
+#import "WXComponent_internal.h"
+#import "WXIndicatorComponent.h"
+#import "WXSDKInstance.h"
+#import "NSTimer+Weex.h"
+#import "WXComponent+Layout.h"
+
+#define MAX_VISIBLE_ITEMS 30
+#define MIN_TOGGLE_DURATION 0.2
+#define MAX_TOGGLE_DURATION 0.4
+#define SCROLL_DURATION 0.4
+#define INSERT_DURATION 0.4
+#define DECELERATE_THRESHOLD 0.1
+#define SCROLL_SPEED_THRESHOLD 2.0
+#define SCROLL_DISTANCE_THRESHOLD 0.1
+#define DECELERATION_MULTIPLIER 30.0
+#define FLOAT_ERROR_MARGIN 0.000001
+
+@protocol WXSliderNeighborDelegate, WXSliderNeighborDataSource;
+
+@interface WXSliderNeighborView: UIView
+@property (nonatomic, strong) WXIndicatorView *indicator;
+@property (nonatomic, weak) id<WXSliderNeighborDelegate> delegate;
+@property (nonatomic, weak) id<WXSliderNeighborDataSource> dataSource;
+@property (nonatomic, assign) CGFloat perspective;
+@property (nonatomic, readonly, getter = isDragging) BOOL dragging;
+@property (nonatomic, readonly, getter = isScrolling) BOOL scrolling;
+@property (nonatomic, assign) CGFloat autoscroll;
+@property (nonatomic, assign) CGFloat scrollOffset;
+@property (nonatomic, assign) CGFloat previousTranslation;
+@property (nonatomic, assign, getter = isVertical) BOOL vertical;
+@property (nonatomic, assign) CGFloat decelerationRate;
+@property (nonatomic, assign, getter = isScrollEnabled) BOOL scrollEnabled;
+@property (nonatomic, assign, getter = isPagingEnabled) BOOL pagingEnabled;
+@property (nonatomic, assign) BOOL bounces;
+@property (nonatomic, assign) BOOL didDrag;
+@property (nonatomic, readonly, getter = isDecelerating) BOOL decelerating;
+@property (nonatomic, strong, readonly) UIView *contentView;
+@property (nonatomic, strong) NSMutableDictionary *itemViews;
+@property (nonatomic, readonly) NSInteger numberOfVisibleItems;
+@property (nonatomic, readonly) NSInteger numberOfItems;
+@property (nonatomic, readonly) NSInteger numberOfPlaceholders;
+@property (nonatomic, strong) NSMutableSet *itemViewPool;
+@property (nonatomic, strong) NSMutableSet *placeholderViewPool;
+@property (nonatomic, assign) NSTimeInterval startTime;
+@property (nonatomic, assign) NSTimeInterval lastTime;
+@property (nonatomic, assign) CGFloat startVelocity;
+@property (nonatomic, assign) CGFloat offsetMultiplier;
+@property (nonatomic, assign) CGFloat startOffset;
+@property (nonatomic, assign) CGFloat endOffset;
+@property (nonatomic, assign) CGSize contentOffset;
+@property (nonatomic, assign) CGSize viewpointOffset;
+@property (nonatomic, assign) CGFloat scrollSpeed;
+@property (nonatomic, assign) CGFloat bounceDistance;
+@property (nonatomic, assign) BOOL stopAtItemBoundary;
+@property (nonatomic, assign) BOOL scrollToItemBoundary;
+@property (nonatomic, assign) BOOL centerItemWhenSelected;
+@property (nonatomic, assign) NSTimeInterval scrollDuration;
+@property (nonatomic, readonly, getter = isWrapEnabled) BOOL wrapEnabled;
+@property (nonatomic, strong) NSTimer *timer;
+@property (nonatomic, assign) NSInteger numberOfPlaceholdersToShow;
+@property (nonatomic, assign) CGFloat previousScrollOffset;
+@property (nonatomic, assign) NSTimeInterval toggleTime;
+@property (nonatomic, readonly) CGFloat toggle;
+@property (nonatomic, assign) NSInteger previousItemIndex;
+@property (nonatomic, readonly) CGFloat itemWidth;
+@property (nonatomic, assign) BOOL inited;
+@end
+
+@implementation WXSliderNeighborView
+
+- (instancetype)init {
+    
+    self = [super init];
+    if (!self) {
+    }
+    _decelerationRate = 0.01;
+    _scrollEnabled = YES;
+    _bounces = YES;
+    _offsetMultiplier = 1.0;
+    _perspective = -1.0/500.0;
+    _contentOffset = CGSizeZero;
+    _viewpointOffset = CGSizeZero;
+    _scrollSpeed = 1.0;
+    _bounceDistance = 1.0;
+    _stopAtItemBoundary = YES;
+    _scrollToItemBoundary = YES;
+    _centerItemWhenSelected = YES;
+    _inited = NO;
+    
+    _contentView = [[UIView alloc] initWithFrame:self.bounds];
+    
+    //pan gesture recognizer
+    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didPan:)];
+    panGesture.delegate = (id <UIGestureRecognizerDelegate>)self;
+    [_contentView addGestureRecognizer:panGesture];
+    
+    //tap gesture recognizer
+    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)];
+    tapGesture.delegate = (id <UIGestureRecognizerDelegate>)self;
+    [_contentView addGestureRecognizer:tapGesture];
+    
+    self.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;
+    self.isAccessibilityElement = YES;
+    
+    [self addSubview:_contentView];
+    
+    if (_dataSource) {
+        [self reloadData];
+    }
+    
+    return self;
+}
+
+- (void)dealloc
+{
+    [self stopAnimation];
+}
+
+- (void)accessibilityIncrement
+{
+    [self setCurrentItemIndex: [self lastItemIndex]];
+}
+
+- (void)accessibilityDecrement
+{
+    [self setCurrentItemIndex:[self nextItemIndex]];
+}
+
+- (void)setDataSource:(id<WXSliderNeighborDataSource>)dataSource
+{
+    if (_dataSource != dataSource) {
+        _dataSource = dataSource;
+        if (_dataSource) {
+            [self reloadData];
+        }
+    }
+}
+
+- (void)setDelegate:(id<WXSliderNeighborDelegate>)delegate
+{
+    if (_delegate != delegate) {
+        _delegate = delegate;
+        if (_delegate && _dataSource) {
+            [self setNeedsLayout];
+        }
+    }
+}
+
+- (void)setVertical:(BOOL)vertical
+{
+    if (_vertical != vertical)
+    {
+        _vertical = vertical;
+        [self layOutItemViews];
+    }
+}
+
+#pragma clang diagnostic push
+#pragma GCC diagnostic ignored "-Wundeclared-selector"
+- (void)setCurrentItemIndex:(NSInteger)currentItemIndex
+{
+    if ([self currentItemIndex] == currentItemIndex) return;
+    
+    [self setScrollOffset:currentItemIndex];
+    [self.indicator setCurrentPoint:currentItemIndex];
+    
+    if (self.delegate && [self.delegate respondsToSelector:@selector(sliderView:didScrollToItemAtIndex:)]) {
+        [self.delegate sliderNeighbor:self didScrollToItemAtIndex:currentItemIndex];
+    }
+    [self scroll2ItemViewAtIndex:currentItemIndex animated:YES];
+    
+}
+#pragma clang diagnostic pop
+
+- (void)updateItemWidth
+{
+    _itemWidth = [_delegate sliderNeighborItemWidth:self] ?: _itemWidth;
+    if (_numberOfItems > 0) {
+        if ([_itemViews count] == 0) {
+            [self loadViewAtIndex:0];
+        }
+    } else if (_numberOfPlaceholders > 0) {
+        if ([_itemViews count] == 0) {
+            [self loadViewAtIndex:-1];
+        }
+    }
+}
+
+- (NSInteger)circularCarouselItemCount
+{
+    NSInteger count = 0;
+    CGFloat spacing = [self valueForOption:WXSliderNeighborOptionSpacing withDefault:1.0];
+    CGFloat width = _vertical ? self.bounds.size.height: self.bounds.size.width;
+    count = MIN(MAX_VISIBLE_ITEMS, MAX(12, ceil(width / (spacing * _itemWidth)) * M_PI));
+    count = MIN(_numberOfItems + _numberOfPlaceholdersToShow, count);
+    return [self valueForOption:WXSliderNeighborOptionCount withDefault:count];
+}
+
+- (void)updateNumberOfVisibleItems
+{
+    //get number of visible items
+    //based on count value
+    CGFloat spacing = [self valueForOption:WXSliderNeighborOptionSpacing withDefault:1.0];
+    CGFloat width = _vertical ? self.bounds.size.height: self.bounds.size.width;
+    CGFloat itemWidth = _itemWidth * spacing;
+    _numberOfVisibleItems = ceil(width / itemWidth) + 2;
+    _numberOfVisibleItems = MIN(MAX_VISIBLE_ITEMS, _numberOfVisibleItems);
+    _numberOfVisibleItems = [self valueForOption:WXSliderNeighborOptionVisibleItems withDefault:_numberOfVisibleItems];
+    _numberOfVisibleItems = MAX(0, MIN(_numberOfVisibleItems, _numberOfItems + _numberOfPlaceholdersToShow));
+    
+}
+
+- (CGFloat)offsetForItemAtIndex:(NSInteger)index
+{
+    //calculate relative position
+    CGFloat offset = index - _scrollOffset;
+    if (_wrapEnabled) {
+        if (offset > _numberOfItems/2.0) {
+            offset -= _numberOfItems;
+        } else if (offset < -_numberOfItems/2.0) {
+            offset += _numberOfItems;
+        }
+    }
+    
+    return offset;
+}
+
+- (CGFloat)alphaForItemWithOffset:(CGFloat)offset
+{
+    CGFloat fadeMin = -INFINITY;
+    CGFloat fadeMax = INFINITY;
+    CGFloat fadeRange = 1.0;
+    CGFloat fadeMinAlpha = 0.0;
+    fadeMin = [self valueForOption:WXSliderNeighborOptionFadeMin withDefault:fadeMin];
+    fadeMax = [self valueForOption:WXSliderNeighborOptionFadeMax withDefault:fadeMax];
+    fadeRange = [self valueForOption:WXSliderNeighborOptionFadeRange withDefault:fadeRange];
+    fadeMinAlpha = [self valueForOption:WXSliderNeighborOptionFadeMinAlpha withDefault:fadeMinAlpha];
+    
+    CGFloat factor = 0.0;
+    if (offset > fadeMax) {
+        factor = offset - fadeMax;
+    } else if (offset < fadeMin) {
+        factor = fadeMin - offset;
+    }
+    return 1.0 - MIN(factor, fadeRange) / fadeRange * (1.0 - fadeMinAlpha);
+}
+
+
+- (UIView *)containView:(UIView *)view
+{
+    //set item width
+    if (!_itemWidth) {
+        _itemWidth = _vertical? view.frame.size.height: view.frame.size.width;
+    }
+    
+    //set container frame
+    CGRect frame = view.frame;
+    frame.size.width = _vertical? frame.size.width: _itemWidth;
+    frame.size.height = _vertical? _itemWidth: frame.size.height;
+    UIView *containerView = [[UIView alloc] initWithFrame:frame];
+    
+    //set view frame
+    frame = view.frame;
+    frame.origin.x = (containerView.bounds.size.width - frame.size.width) / 2.0;
+    frame.origin.y = (containerView.bounds.size.height - frame.size.height) / 2.0;
+    view.frame = frame;
+    [containerView addSubview:view];
+    containerView.layer.opacity = 0;
+    containerView.transform = CGAffineTransformMakeScale(0.8, 1.0);
+    return containerView;
+}
+
+- (void)transformItemViews
+{
+    for (NSNumber *number in _itemViews)
+    {
+        NSInteger index = [number integerValue];
+        UIView *view = _itemViews[number];
+        [self transformItemView:view atIndex:index];
+    }
+}
+
+- (CATransform3D)transformForItemViewWithOffset:(CGFloat)offset
+{
+    //set up base transform
+    CATransform3D transform = CATransform3DIdentity;
+    transform.m34 = _perspective;
+    transform = CATransform3DTranslate(transform, -_viewpointOffset.width, -_viewpointOffset.height, 0.0);
+    
+    //perform transforms
+    CGFloat spacing = [self valueForOption:WXSliderNeighborOptionSpacing withDefault:1.0];
+    if (_vertical) {
+        return CATransform3DTranslate(transform, 0.0, offset * _itemWidth * spacing, 0.0);
+    } else {
+        return CATransform3DTranslate(transform, offset * _itemWidth * spacing, 0.0, 0.0);
+    }
+}
+
+- (void)transformItemView:(UIView *)view atIndex:(NSInteger)index
+{
+    //calculate offset
+    CGFloat offset = [self offsetForItemAtIndex:index];
+    
+    //update alpha
+    view.superview.layer.opacity = [self alphaForItemWithOffset:offset];
+    
+    //center view
+    view.superview.center = CGPointMake(self.bounds.size.width/2.0 + _contentOffset.width,
+                                        self.bounds.size.height/2.0 + _contentOffset.height);
+    
+    //enable/disable interaction
+    view.superview.userInteractionEnabled = (!_centerItemWhenSelected || index == self.currentItemIndex);
+    view.superview.layer.rasterizationScale = [UIScreen mainScreen].scale;
+    
+    [view layoutIfNeeded];
+    
+    CGFloat clampedOffset = MAX(-1.0, MIN(1.0, offset));
+    if (_decelerating || (_scrolling && !_dragging && !_didDrag) || (_autoscroll && !_dragging) ||
+        (!_wrapEnabled && (_scrollOffset < 0 || _scrollOffset >= _numberOfItems - 1))) {
+        if (offset > 0) {
+            _toggle = (offset <= 0.5)? -clampedOffset: (1.0 - clampedOffset);
+        } else {
+            _toggle = (offset > -0.5)? -clampedOffset: (- 1.0 - clampedOffset);
+        }
+    }
+    
+    //calculate transform
+    CATransform3D transform = [self transformForItemViewWithOffset:offset];
+    
+    //transform view
+    view.superview.layer.transform = transform;
+    
+    //backface culling
+    BOOL showBackfaces = view.layer.doubleSided;
+    if (showBackfaces) {
+        showBackfaces = YES;
+    }
+    showBackfaces = !![self valueForOption:WXSliderNeighborOptionShowBackfaces withDefault:showBackfaces];
+    
+    view.superview.hidden = !(showBackfaces ?: (transform.m33 > 0.0));
+}
+
+NSComparisonResult sliderNeighorCompareViewDepth(UIView *view1, UIView *view2, WXSliderNeighborView *self)
+{
+    //compare depths
+    CATransform3D t1 = view1.superview.layer.transform;
+    CATransform3D t2 = view2.superview.layer.transform;
+    CGFloat z1 = t1.m13 + t1.m23 + t1.m33 + t1.m43;
+    CGFloat z2 = t2.m13 + t2.m23 + t2.m33 + t2.m43;
+    CGFloat difference = z1 - z2;
+    
+    //if depths are equal, compare distance from current view
+    if (difference == 0.0) {
+        CATransform3D t3 = [self currentItemView].superview.layer.transform;
+        if (self.vertical) {
+            CGFloat y1 = t1.m12 + t1.m22 + t1.m32 + t1.m42;
+            CGFloat y2 = t2.m12 + t2.m22 + t2.m32 + t2.m42;
+            CGFloat y3 = t3.m12 + t3.m22 + t3.m32 + t3.m42;
+            difference = fabs(y2 - y3) - fabs(y1 - y3);
+        } else {
+            CGFloat x1 = t1.m11 + t1.m21 + t1.m31 + t1.m41;
+            CGFloat x2 = t2.m11 + t2.m21 + t2.m31 + t2.m41;
+            CGFloat x3 = t3.m11 + t3.m21 + t3.m31 + t3.m41;
+            difference = fabs(x2 - x3) - fabs(x1 - x3);
+        }
+    }
+    return (difference < 0.0)? NSOrderedAscending: NSOrderedDescending;
+}
+
+- (void)depthSortViews
+{
+    for (UIView *view in [[_itemViews allValues] sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))sliderNeighorCompareViewDepth context:(__bridge void *)self])
+    {
+        [_contentView bringSubviewToFront:(UIView *__nonnull)view.superview];
+    }
+}
+
+- (void)layOutItemViews
+{
+    //bail out if not set up yet
+    if (!_dataSource || !_contentView) {
+        return;
+    }
+    
+    //update wrap
+    _wrapEnabled = YES;
+    _wrapEnabled = !![self valueForOption:WXSliderNeighborOptionWrap withDefault:_wrapEnabled];
+    
+    //no placeholders on wrapped carousels
+    _numberOfPlaceholdersToShow = _wrapEnabled? 0: _numberOfPlaceholders;
+    
+    //set item width
+    [self updateItemWidth];
+    
+    //update number of visible items
+    [self updateNumberOfVisibleItems];
+    
+    //prevent false index changed event
+    _previousScrollOffset = self.scrollOffset;
+    
+    //update offset multiplier
+    _offsetMultiplier = 1.0;
+    _offsetMultiplier = [self valueForOption:WXSliderNeighborOptionOffsetMultiplier withDefault:_offsetMultiplier];
+    
+    //align
+    if (!_scrolling && !_decelerating && !_autoscroll) {
+        if (_scrollToItemBoundary && self.currentItemIndex != -1) {
+            [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
+        } else {
+            _scrollOffset = [self clampedOffset:_scrollOffset];
+        }
+    }
+    //update views
+    if (_inited) {
+        [self didScroll];
+    }
+    
+    _inited = YES;
+}
+
+- (CGFloat)valueForOption:(WXSliderNeighborOption)option withDefault:(CGFloat)value
+{
+    if (_delegate && [_delegate respondsToSelector:@selector(sliderNeighbor:valueForOption:withDefault:)]) {
+        return [_delegate sliderNeighbor:self valueForOption:option withDefault:value];
+    }
+    return value;
+}
+
+#pragma mark -
+#pragma mark Gestures and taps
+
+- (NSInteger)viewOrSuperviewIndex:(UIView *)view
+{
+    if (view == nil || view == _contentView) {
+        return NSNotFound;
+    }
+    NSInteger index = [self indexOfItemView:view];
+    if (index == NSNotFound) {
+        return [self viewOrSuperviewIndex:view.superview];
+    }
+    return index;
+}
+
+- (BOOL)viewOrSuperview:(UIView *)view implementsSelector:(SEL)selector
+{
+    if (!view || view == self.contentView) {
+        return NO;
+    }
+    
+    Class viewClass = [view class];
+    while (viewClass && viewClass != [UIView class])
+    {
+        unsigned int numberOfMethods;
+        Method *methods = class_copyMethodList(viewClass, &numberOfMethods);
+        for (unsigned int i = 0; i < numberOfMethods; i++)
+        {
+            if (method_getName(methods[i]) == selector) {
+                free(methods);
+                return YES;
+            }
+        }
+        if (methods) free(methods);
+        viewClass = [viewClass superclass];
+    }
+    
+    return [self viewOrSuperview:view.superview implementsSelector:selector];
+}
+
+- (id)viewOrSuperview:(UIView *)view ofClass:(Class)swizzClass
+{
+    if (!view || view == self.contentView) {
+        return nil;
+    } else if ([view isKindOfClass:swizzClass]) {
+        return view;
+    }
+    return [self viewOrSuperview:view.superview ofClass:swizzClass];
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch
+{
+    if (_scrollEnabled) {
+        _dragging = NO;
+        _scrolling = NO;
+        _decelerating = NO;
+    }
+    
+    if ([gesture isKindOfClass:[UITapGestureRecognizer class]]) {
+        //handle tap
+        NSInteger index = [self viewOrSuperviewIndex:touch.view];
+        if (index == NSNotFound && _centerItemWhenSelected) {
+            //view is a container view
+            index = [self viewOrSuperviewIndex:[touch.view.subviews lastObject]];
+        }
+        if (index != NSNotFound) {
+            if ([self viewOrSuperview:touch.view implementsSelector:@selector(touchesBegan:withEvent:)]) {
+                return NO;
+            }
+        }
+    } else if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) {
+        if (!_scrollEnabled) {
+            return NO;
+        } else if ([self viewOrSuperview:touch.view implementsSelector:@selector(touchesMoved:withEvent:)]) {
+            UIScrollView *scrollView = [self viewOrSuperview:touch.view ofClass:[UIScrollView class]];
+            if (scrollView) {
+                return !scrollView.scrollEnabled ||
+                (self.vertical && scrollView.contentSize.height <= scrollView.frame.size.height) ||
+                (!self.vertical && scrollView.contentSize.width <= scrollView.frame.size.width);
+            }
+            if ([self viewOrSuperview:touch.view ofClass:[UIButton class]] ||
+                [self viewOrSuperview:touch.view ofClass:[UIBarButtonItem class]]) {
+                return YES;
+            }
+            return NO;
+        }
+    }
+    return YES;
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
+   //if the view which the otherGestureRecognizer works on is a scrollview and also it is scrollEnabled vertically ,at this time,we should not block the guesture from being recognized by the otherGestureRecognize
+    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
+        if ([otherGestureRecognizer.view isKindOfClass:[UIScrollView class]]) {
+            UIScrollView* scrollview = (UIScrollView *)otherGestureRecognizer.view;
+            if (scrollview.scrollEnabled) {
+                UIPanGestureRecognizer* panRcgn= (UIPanGestureRecognizer *)gestureRecognizer;
+                //check offset for confirming vertival movement
+                if (fabs([panRcgn translationInView:panRcgn.view].y) > fabs([panRcgn translationInView:panRcgn.view].x)*16) {
+                    return YES;
+                }
+            }
+        }
+    }
+    return NO;
+}
+
+
+- (void)didPan:(UIPanGestureRecognizer *)panGesture
+{
+    if (_scrollEnabled && _numberOfItems) {
+        switch (panGesture.state)
+        {
+            case UIGestureRecognizerStateBegan:
+            {
+                _dragging = YES;
+                _scrolling = NO;
+                _decelerating = NO;
+                _previousTranslation = _vertical? [panGesture translationInView:self].y: [panGesture translationInView:self].x;
+                
+                [_delegate sliderNeighborWillBeginDragging:self];
+                break;
+            }
+            case UIGestureRecognizerStateEnded:
+            case UIGestureRecognizerStateCancelled:
+            case UIGestureRecognizerStateFailed:
+            {
+                _dragging = NO;
+                _didDrag = YES;
+                if ([self shouldDecelerate]) {
+                    _didDrag = NO;
+                    [self startDecelerating];
+                }
+                
+                [self pushAnimationState:YES];
+                [_delegate sliderNeighborDidEndDragging:self willDecelerate:_decelerating];
+                [self popAnimationState];
+                
+                if (!_decelerating) {
+                    if ((_scrollToItemBoundary || fabs(_scrollOffset - [self clampedOffset:_scrollOffset]) > FLOAT_ERROR_MARGIN) && !_autoscroll) {
+                        if (fabs(_scrollOffset - self.currentItemIndex) < FLOAT_ERROR_MARGIN) {
+                            //call scroll to trigger events for legacy support reasons
+                            //even though technically we don't need to scroll at all
+                            [self scroll2ItemViewAtIndex:self.currentItemIndex duration:0.01];
+                        } else {
+                            [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
+                        }
+                    } else {
+                        [self depthSortViews];
+                    }
+                } else {
+                    [self pushAnimationState:YES];
+                    [_delegate sliderNeighborWillBeginDecelerating:self];
+                    [self popAnimationState];
+                }
+                break;
+            }
+            case UIGestureRecognizerStateChanged:
+            {
+                CGFloat translation = _vertical? [panGesture translationInView:self].y: [panGesture translationInView:self].x;
+                CGFloat velocity = _vertical? [panGesture velocityInView:self].y: [panGesture velocityInView:self].x;
+                
+                CGFloat factor = 1.0;
+                if (!_wrapEnabled && _bounces) {
+                    factor = 1.0 - MIN(fabs(_scrollOffset - [self clampedOffset:_scrollOffset]),
+                                       _bounceDistance) / _bounceDistance;
+                }
+                
+                _startVelocity = -velocity * factor * _scrollSpeed / _itemWidth;
+                _scrollOffset -= (translation - _previousTranslation) * factor * _offsetMultiplier / _itemWidth;
+                _previousTranslation = translation;
+                [self didScroll];
+                break;
+            }
+            case UIGestureRecognizerStatePossible:
+            {
+                //do nothing
+                break;
+            }
+        }
+    }
+}
+
+- (void)didTap:(UITapGestureRecognizer *)tapGesture
+{
+    //check for tapped view
+    NSInteger index = [self indexOfItemView:[self itemViewAtPoint:[tapGesture locationInView:_contentView]]];
+    if (index != NSNotFound) {
+        if (!_delegate || [_delegate sliderNeighbor:self shouldSelectItemAtIndex:index]) {
+            if ((index != self.currentItemIndex && _centerItemWhenSelected) ||
+                (index == self.currentItemIndex && _scrollToItemBoundary)) {
+                [self scroll2ItemViewAtIndex:index animated:YES];
+            }
+            [_delegate sliderNeighbor:self didSelectItemAtIndex:index];
+        } else if (_scrollEnabled && _scrollToItemBoundary && _autoscroll) {
+            [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
+        }
+    } else {
+        [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
+    }
+}
+
+- (void)pushAnimationState:(BOOL)enabled
+{
+    [CATransaction begin];
+    [CATransaction setDisableActions:!enabled];
+}
+
+- (void)popAnimationState
+{
+    [CATransaction commit];
+}
+
+- (void)reloadData
+{
+    //remove old views
+    for (UIView *view in [_itemViews allValues])
+    {
+        [view.superview removeFromSuperview];
+    }
+    
+    //bail out if not set up yet
+    if (!_dataSource || !_contentView)
+    {
+        return;
+    }
+    
+    //get number of items and placeholders
+    _numberOfVisibleItems = 0;
+    _numberOfItems = [_dataSource numberOfItemsInSliderNeighbor:self];
+    if ([_dataSource respondsToSelector:@selector(numberOfPlaceholdersInsliderNeighbor:)]) {
+        _numberOfPlaceholders = [_dataSource numberOfPlaceholdersInsliderNeighbor:self];
+    }
+    
+    //reset view pools
+    self.itemViews = [NSMutableDictionary dictionary];
+    self.itemViewPool = [NSMutableSet set];
+    self.placeholderViewPool = [NSMutableSet setWithCapacity:_numberOfPlaceholders];
+    
+    //layout views
+    [self setNeedsLayout];
+    
+    //fix scroll offset
+    if (_numberOfItems > 0 && _scrollOffset < 0.0)
+    {
+        [self scroll2ItemViewAtIndex:0 animated:(_numberOfPlaceholders > 0)];
+    }
+}
+
+#pragma mark scrolling
+
+- (NSInteger)currentItemIndex
+{
+    return [self clampedIndex:round(_scrollOffset)];
+}
+
+- (NSInteger)nextItemIndex
+{
+    return ([self currentItemIndex]+1)%_numberOfItems;
+}
+
+- (NSInteger)lastItemIndex
+{
+    if ([self currentItemIndex] == 0) {
+        return _numberOfItems - 1;
+    }
+    return ((NSInteger)round(abs((int)[self currentItemIndex] - 1))) % _numberOfItems;
+}
+
+- (NSInteger)minScrollDistanceFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex
+{
+    NSInteger directDistance = toIndex - fromIndex;
+    if (_wrapEnabled)
+    {
+        NSInteger wrappedDistance = MIN(toIndex, fromIndex) + _numberOfItems - MAX(toIndex, fromIndex);
+        if (fromIndex < toIndex)
+        {
+            wrappedDistance = -wrappedDistance;
+        }
+        return (ABS(directDistance) <= ABS(wrappedDistance))? directDistance: wrappedDistance;
+    }
+    return directDistance;
+}
+
+- (NSInteger)clampedIndex:(NSInteger)index
+{
+    if (_numberOfItems == 0)
+    {
+        return -1;
+    } else if (_wrapEnabled) {
+        return index - floor((CGFloat)index / (CGFloat)_numberOfItems) * _numberOfItems;
+    } else {
+        return MIN(MAX(0, index), MAX(0, _numberOfItems - 1));
+    }
+}
+
+- (CGFloat)clampedOffset:(CGFloat)offset
+{
+    if (_numberOfItems == 0) {
+        return -1.0;
+    } else if (_wrapEnabled) {
+        return offset - floor(offset / (CGFloat)_numberOfItems) * _numberOfItems;
+    } else {
+        return MIN(MAX(0.0, offset), MAX(0.0, (CGFloat)_numberOfItems - 1.0));
+    }
+}
+
+- (CGFloat)minScrollDistanceFromOffset:(CGFloat)fromOffset toOffset:(CGFloat)toOffset
+{
+    CGFloat directDistance = toOffset - fromOffset;
+    if (_wrapEnabled) {
+        CGFloat wrappedDistance = MIN(toOffset, fromOffset) + _numberOfItems - MAX(toOffset, fromOffset);
+        if (fromOffset < toOffset) {
+            wrappedDistance = -wrappedDistance;
+        }
+        return (fabs(directDistance) <= fabs(wrappedDistance))? directDistance: wrappedDistance;
+    }
+    return directDistance;
+}
+
+- (void)scrollByOffset:(CGFloat)offset duration:(NSTimeInterval)duration
+{
+    if (duration > 0.0) {
+        _decelerating = NO;
+        _scrolling = YES;
+        _startTime = CACurrentMediaTime();
+        _startOffset = _scrollOffset;
+        _scrollDuration = duration;
+        _endOffset = _startOffset + offset;
+        if (!_wrapEnabled) {
+            _endOffset = [self clampedOffset:_endOffset];
+        }
+        [_delegate sliderNeighborWillBeginScrollingAnimation:self];
+        [self startAnimation];
+    } else {
+        self.scrollOffset += offset;
+    }
+}
+
+- (void)scroll2Offset:(CGFloat)offset duration:(NSTimeInterval)duration
+{
+    [self scrollByOffset:[self minScrollDistanceFromOffset:_scrollOffset toOffset:offset] duration:duration];
+    if (_delegate && [_delegate respondsToSelector:@selector(sliderNeighbor:didScrollToItemAtIndex:)]) {
+        [_delegate sliderNeighbor:self didScrollToItemAtIndex:offset];
+    }
+}
+
+- (void)scroll2ItemViewAtIndex:(NSInteger)index duration:(NSTimeInterval)duration
+{
+    [self scroll2Offset:index duration:duration];
+}
+
+- (void)scroll2ItemViewAtIndex:(NSInteger)index animated:(BOOL)animated
+{
+    [self scroll2ItemViewAtIndex:index duration:animated? 0.6: 0];
+}
+
+- (void)scrollByNumberOfItems:(NSInteger)itemCount duration:(NSTimeInterval)duration
+{
+    if (duration > 0.0) {
+        CGFloat offset = 0.0;
+        if (itemCount > 0) {
+            offset = (floor(_scrollOffset) + itemCount) - _scrollOffset;
+        } else if (itemCount < 0) {
+            offset = (ceil(_scrollOffset) + itemCount) - _scrollOffset;
+        } else {
+            offset = round(_scrollOffset) - _scrollOffset;
+        }
+        [self scrollByOffset:offset duration:duration];
+    } else {
+        self.scrollOffset = [self clampedIndex:_previousItemIndex + itemCount];
+    }
+}
+
+- (void)removeItemAtIndex:(NSInteger)index animated:(BOOL)animated
+{
+    index = [self clampedIndex:index];
+    UIView *itemView = [self itemViewAtIndex:index];
+    
+    if (animated) {
+        [UIView beginAnimations:nil context:nil];
+        [UIView setAnimationDuration:0.1];
+        [UIView setAnimationDelegate:itemView.superview];
+        [UIView setAnimationDidStopSelector:@selector(removeFromSuperview)];
+        [self performSelector:@selector(queueItemView:) withObject:itemView afterDelay:0.1];
+        itemView.superview.layer.opacity = 0.0;
+        [UIView commitAnimations];
+        
+        [UIView beginAnimations:nil context:nil];
+        [UIView setAnimationDelay:0.1];
+        [UIView setAnimationDuration:INSERT_DURATION];
+        [UIView setAnimationDelegate:self];
+        [UIView setAnimationDidStopSelector:@selector(depthSortViews)];
+        [self removeViewAtIndex:index];
+        _numberOfItems --;
+        _wrapEnabled = !![self valueForOption:WXSliderNeighborOptionWrap withDefault:_wrapEnabled];
+        [self updateNumberOfVisibleItems];
+        _scrollOffset = self.currentItemIndex;
+        [self didScroll];
+        [UIView commitAnimations];
+    } else {
+        [self pushAnimationState:NO];
+        [self queueItemView:itemView];
+        [itemView.superview removeFromSuperview];
+        [self removeViewAtIndex:index];
+        _numberOfItems --;
+        _wrapEnabled = !![self valueForOption:WXSliderNeighborOptionWrap withDefault:_wrapEnabled];
+        _scrollOffset = self.currentItemIndex;
+        [self didScroll];
+        [self depthSortViews];
+        [self popAnimationState];
+    }
+}
+
+- (void)insertItemAtIndex:(NSInteger)index animated:(BOOL)animated
+{
+    _numberOfItems ++;
+    _wrapEnabled = !![self valueForOption:WXSliderNeighborOptionWrap withDefault:_wrapEnabled];
+    [self updateNumberOfVisibleItems];
+    
+    index = [self clampedIndex:index];
+    [self insertView:nil atIndex:index];
+    [self loadViewAtIndex:index];
+    
+    if (fabs(_itemWidth) < FLOAT_ERROR_MARGIN) {
+        [self updateItemWidth];
+    }
+    
+    if (animated) {
+        [UIView beginAnimations:nil context:nil];
+        [UIView setAnimationDuration:INSERT_DURATION];
+        [UIView setAnimationDelegate:self];
+        [UIView setAnimationDidStopSelector:@selector(didScroll)];
+        [self transformItemViews];
+        [UIView commitAnimations];
+    } else {
+        [self pushAnimationState:NO];
+        [self didScroll];
+        [self popAnimationState];
+    }
+    
+    if (_scrollOffset < 0.0) {
+        [self scroll2ItemViewAtIndex:0 animated:(animated && _numberOfPlaceholders)];
+    }
+}
+
+- (void)reloadItemAtIndex:(NSInteger)index animated:(BOOL)animated
+{
+    //get container view
+    UIView *containerView = [[self itemViewAtIndex:index] superview];
+    if (containerView) {
+        if (animated) {
+            //fade transition
+            CATransition *transition = [CATransition animation];
+            transition.duration = INSERT_DURATION;
+            transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+            transition.type = kCATransitionFade;
+            [containerView.layer addAnimation:transition forKey:nil];
+        }
+        
+        //reload view
+        [self loadViewAtIndex:index withContainerView:containerView];
+    }
+}
+
+#pragma mark Animation
+- (void)step
+{
+    [self pushAnimationState:NO];
+    NSTimeInterval currentTime = CACurrentMediaTime();
+    double delta = currentTime - _lastTime;
+    _lastTime = currentTime;
+    
+    if (_scrolling && !_dragging) {
+        NSTimeInterval time = MIN(1.0, (currentTime - _startTime) / _scrollDuration);
+        delta = [self easeInOut:time];
+        _scrollOffset = _startOffset + (_endOffset - _startOffset) * delta;
+        [self didScroll];
+        if (time >= 1.0) {
+            _scrolling = NO;
+            [self depthSortViews];
+            [self pushAnimationState:YES];
+            [_delegate sliderNeighborDidEndScrollingAnimation:self];
+            [self popAnimationState];
+        }
+    } else if (_decelerating) {
+        CGFloat time = MIN(_scrollDuration, currentTime - _startTime);
+        CGFloat acceleration = -_startVelocity/_scrollDuration;
+        CGFloat distance = _startVelocity * time + 0.5 * acceleration * pow(time, 2.0);
+        _scrollOffset = _startOffset + distance;
+        [self didScroll];
+        if (fabs(time - _scrollDuration) < FLOAT_ERROR_MARGIN) {
+            _decelerating = NO;
+            [self pushAnimationState:YES];
+            [_delegate sliderNeighborDidEndDecelerating:self];
+            [self popAnimationState];
+            if ((_scrollToItemBoundary || fabs(_scrollOffset - [self clampedOffset:_scrollOffset]) > FLOAT_ERROR_MARGIN) && !_autoscroll) {
+                if (fabs(_scrollOffset - self.currentItemIndex) < FLOAT_ERROR_MARGIN) {
+                    //call scroll to trigger events for legacy support reasons
+                    //even though technically we don't need to scroll at all
+                    [self scroll2ItemViewAtIndex:self.currentItemIndex duration:0.01];
+                } else {
+                    [self scroll2ItemViewAtIndex:self.currentItemIndex animated:YES];
+                }
+            } else {
+                CGFloat difference = round(_scrollOffset) - _scrollOffset;
+                if (difference > 0.5) {
+                    difference = difference - 1.0;
+                } else if (difference < -0.5) {
+                    difference = 1.0 + difference;
+                }
+                _toggleTime = currentTime - MAX_TOGGLE_DURATION * fabs(difference);
+                _toggle = MAX(-1.0, MIN(1.0, -difference));
+            }
+        }
+    } else if (_autoscroll && !_dragging) {
+        //autoscroll goes backwards from what you'd expect, for historical reasons
+        self.scrollOffset = [self clampedOffset:_scrollOffset - delta * _autoscroll];
+    } else if (fabs(_toggle) > FLOAT_ERROR_MARGIN) {
+        NSTimeInterval toggleDuration = _startVelocity? MIN(1.0, MAX(0.0, 1.0 / fabs(_startVelocity))): 1.0;
+        toggleDuration = MIN_TOGGLE_DURATION + (MAX_TOGGLE_DURATION - MIN_TOGGLE_DURATION) * toggleDuration;
+        NSTimeInterval time = MIN(1.0, (currentTime - _toggleTime) / toggleDuration);
+        delta = [self easeInOut:time];
+        _toggle = (_toggle < 0.0)? (delta - 1.0): (1.0 - delta);
+        [self didScroll];
+    } else if (!_autoscroll) {
+        [self stopAnimation];
+    }
+    
+    [self popAnimationState];
+}
+
+- (CGFloat)easeInOut:(CGFloat)time
+{
+    return (time < 0.5)? 0.5 * pow(time * 2.0, 3.0): 0.5 * pow(time * 2.0 - 2.0, 3.0) + 1.0;
+}
+
+- (CGFloat)decelerationDistance
+{
+    CGFloat acceleration = -_startVelocity * DECELERATION_MULTIPLIER * (1.0 - _decelerationRate);
+    return -pow(_startVelocity, 2.0) / (2.0 * acceleration);
+}
+
+- (void)startDecelerating
+{
+    CGFloat distance = [self decelerationDistance];
+    _startOffset = _scrollOffset;
+    _endOffset = _startOffset + distance;
+    if (_pagingEnabled) {
+        if (distance > 0.0) {
+            _endOffset = ceil(_startOffset);
+        } else {
+            _endOffset = floor(_startOffset);
+        }
+    } else if (_stopAtItemBoundary) {
+        if (distance > 0.0) {
+            _endOffset = ceil(_endOffset);
+        } else {
+            _endOffset = floor(_endOffset);
+        }
+    }
+    if (!_wrapEnabled) {
+        if (_bounces) {
+            _endOffset = MAX(-_bounceDistance, MIN(_numberOfItems - 1.0 + _bounceDistance, _endOffset));
+        } else {
+            _endOffset = [self clampedOffset:_endOffset];
+        }
+    }
+    distance = _endOffset - _startOffset;
+    
+    _startTime = CACurrentMediaTime();
+    _scrollDuration = fabs(distance) / fabs(0.5 * _startVelocity);
+    
+    if (distance != 0.0) {
+        _decelerating = YES;
+        [self startAnimation];
+    }
+}
+
+
+- (BOOL)shouldDecelerate
+{
+    return (fabs(_startVelocity) > SCROLL_SPEED_THRESHOLD) &&
+    (fabs([self decelerationDistance]) > DECELERATE_THRESHOLD);
+}
+
+- (BOOL)shouldScroll
+{
+    return (fabs(_startVelocity) > SCROLL_SPEED_THRESHOLD) &&
+    (fabs(_scrollOffset - self.currentItemIndex) > SCROLL_DISTANCE_THRESHOLD);
+}
+
+- (void)didScroll
+{
+    if (_wrapEnabled || !_bounces) {
+        _scrollOffset = [self clampedOffset:_scrollOffset];
+    } else {
+        CGFloat min = -_bounceDistance;
+        CGFloat max = MAX(_numberOfItems - 1, 0.0) + _bounceDistance;
+        if (_scrollOffset < min) {
+            _scrollOffset = min;
+            _startVelocity = 0.0;
+        } else if (_scrollOffset > max) {
+            _scrollOffset = max;
+            _startVelocity = 0.0;
+        }
+    }
+    
+    //check if index has changed
+    NSInteger difference = [self minScrollDistanceFromIndex:self.currentItemIndex toIndex:self.previousItemIndex];
+    if (difference) {
+        _toggleTime = CACurrentMediaTime();
+        _toggle = MAX(-1, MIN(1, difference));
+        
+        [self startAnimation];
+    }
+    
+    [self loadUnloadViews];
+    [self transformItemViews];
+    
+    //notify delegate of offset change
+    if (fabs(_scrollOffset - _previousScrollOffset) > 0.000001)
+    {
+        [self pushAnimationState:YES];
+        [_delegate sliderNeighborDidScroll:self];
+        [self popAnimationState];
+    }
+    
+    //notify delegate of index change
+    if (_previousItemIndex != self.currentItemIndex)
+    {
+        [self pushAnimationState:YES];
+        if([_delegate respondsToSelector:@selector(sliderNeighborCurrentItemIndexDidChange:from:to:)]) {
+            [_delegate sliderNeighborCurrentItemIndexDidChange:self from:_previousItemIndex to:self.currentItemIndex];
+        }
+        [self popAnimationState];
+    }
+    
+    //update previous index
+    _previousScrollOffset = _scrollOffset;
+    _previousItemIndex = self.currentItemIndex;
+    [self.indicator setCurrentPoint:self.currentItemIndex];
+}
+
+- (void)startAnimation
+{
+    if (!_timer) {
+        self.timer = [NSTimer timerWithTimeInterval:1.0/60.0
+                                             target:self
+                                           selector:@selector(step)
+                                           userInfo:nil
+                                            repeats:YES];
+        
+        [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
+        [[NSRunLoop mainRunLoop] addTimer:_timer forMode:UITrackingRunLoopMode];
+        
+    }
+}
+
+- (void)stopAnimation
+{
+    [_timer invalidate];
+    _timer = nil;
+}
+
+#pragma mark -
+#pragma mark view management
+
+- (NSArray *)indexesForVisibleItems
+{
+    return [[_itemViews allKeys] sortedArrayUsingSelector:@selector(compare:)];
+}
+
+- (NSArray *)visibleItemViews
+{
+    NSArray *indexes = [self indexesForVisibleItems];
+    return [_itemViews objectsForKeys:indexes notFoundMarker:[NSNull null]];
+}
+
+- (UIView *)itemViewAtIndex:(NSInteger)index
+{
+    return _itemViews[@(index)];
+}
+
+- (UIView *)currentItemView
+{
+    return [self itemViewAtIndex:self.currentItemIndex];
+}
+
+- (NSInteger)indexOfItemView:(UIView *)view
+{
+    NSInteger index = [[_itemViews allValues] indexOfObject:view];
+    if (index != NSNotFound) {
+        return [[_itemViews allKeys][index] integerValue];
+    }
+    return NSNotFound;
+}
+
+- (NSInteger)indexOfItemViewOrSubview:(UIView *)view
+{
+    NSInteger index = [self indexOfItemView:view];
+    if (index == NSNotFound && view != nil && view != _contentView) {
+        return [self indexOfItemViewOrSubview:view.superview];
+    }
+    return index;
+}
+
+- (UIView *)itemViewAtPoint:(CGPoint)point
+{
+    for (UIView *view in [[[_itemViews allValues] sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))sliderNeighorCompareViewDepth context:(__bridge void *)self] reverseObjectEnumerator])
+    {
+        if ([view.superview.layer hitTest:point]) {
+            return view;
+        }
+    }
+    return nil;
+}
+
+- (void)setItemView:(UIView *)view forIndex:(NSInteger)index
+{
+    _itemViews[@(index)] = view;
+}
+
+- (void)removeViewAtIndex:(NSInteger)index
+{
+    NSMutableDictionary *newItemViews = [NSMutableDictionary dictionaryWithCapacity:[_itemViews count] - 1];
+    for (NSNumber *number in [self indexesForVisibleItems])
+    {
+        NSInteger i = [number integerValue];
+        if (i < index) {
+            newItemViews[number] = _itemViews[number];
+        } else if (i > index) {
+            newItemViews[@(i - 1)] = _itemViews[number];
+        }
+    }
+    self.itemViews = newItemViews;
+    [self.indicator setPointCount:self.itemViews.count];
+}
+
+- (void)insertView:(UIView *)view atIndex:(NSInteger)index
+{
+    NSMutableDictionary *newItemViews = [NSMutableDictionary dictionaryWithCapacity:[_itemViews count] + 1];
+    for (NSNumber *number in [self indexesForVisibleItems])
+    {
+        NSInteger i = [number integerValue];
+        if (i < index) {
+            newItemViews[number] = _itemViews[number];
+        } else {
+            newItemViews[@(i + 1)] = _itemViews[number];
+        }
+    }
+    if (view) {
+        [self setItemView:view forIndex:index];
+    }
+    self.itemViews = newItemViews;
+    
+    [self.indicator setPointCount:self.itemViews.count];
+}
+
+#pragma mark -
+#pragma mark View loading
+
+- (UIView *)loadViewAtIndex:(NSInteger)index withContainerView:(UIView *)containerView
+{
+    [self pushAnimationState:NO];
+    
+    UIView *view = nil;
+    if (index < 0) {
+        view = [_dataSource sliderNeighbor:self placeholderViewAtIndex:(NSInteger)(ceil((CGFloat)_numberOfPlaceholdersToShow/2.0)) + index reusingView:[self dequeuePlaceholderView]];
+    } else if (index >= _numberOfItems) {
+        view = [_dataSource sliderNeighbor:self placeholderViewAtIndex:_numberOfPlaceholdersToShow/2.0 + index - _numberOfItems reusingView:[self dequeuePlaceholderView]];
+    } else {
+        view = [_dataSource sliderNeighbor:self viewForItemAtIndex:index reusingView:[self dequeueItemView]];
+    }
+    
+    if (view == nil) {
+        view = [[UIView alloc] init];
+    }
+    
+    [self setItemView:view forIndex:index];
+    if (containerView) {
+        //get old item view
+        UIView *oldItemView = [containerView.subviews lastObject];
+        if (index < 0 || index >= _numberOfItems) {
+            [self queuePlaceholderView:oldItemView];
+        } else {
+            [self queueItemView:oldItemView];
+        }
+        
+        //set container frame
+        CGRect frame = containerView.bounds;
+        if(_vertical) {
+            frame.size.width = view.frame.size.width;
+            frame.size.height = MIN(_itemWidth, view.frame.size.height);
+        } else {
+            frame.size.width = MIN(_itemWidth, view.frame.size.width);
+            frame.size.height = view.frame.size.height;
+        }
+        containerView.bounds = frame;
+        
+        //set view frame
+        frame = view.frame;
+        frame.origin.x = (containerView.bounds.size.width - frame.size.width) / 2.0;
+        frame.origin.y = (containerView.bounds.size.height - frame.size.height) / 2.0;
+        view.frame = frame;
+        
+        //switch views
+        [oldItemView removeFromSuperview];
+        [containerView addSubview:view];
+    } else {
+        [_contentView addSubview:[self containView:view]];
+    }
+    view.superview.layer.opacity = 0.0;
+    [self transformItemView:view atIndex:index];
+    
+    [self popAnimationState];
+    
+    return view;
+}
+
+- (UIView *)loadViewAtIndex:(NSInteger)index
+{
+    return [self loadViewAtIndex:index withContainerView:nil];
+}
+
+- (void)loadUnloadViews
+{
+    //set item width
+    [self updateItemWidth];
+    
+    //update number of visible items
+    [self updateNumberOfVisibleItems];
+    
+    //calculate visible view indices
+    NSMutableSet *visibleIndices = [NSMutableSet setWithCapacity:_numberOfVisibleItems];
+    NSInteger min = -(NSInteger)(ceil((CGFloat)_numberOfPlaceholdersToShow/2.0));
+    NSInteger max = _numberOfItems - 1 + _numberOfPlaceholdersToShow/2;
+    NSInteger offset = self.currentItemIndex - _numberOfVisibleItems/2;
+    if (!_wrapEnabled) {
+        offset = MAX(min, MIN(max - _numberOfVisibleItems + 1, offset));
+    }
+    for (NSInteger i = 0; i < _numberOfVisibleItems; i++)
+    {
+        NSInteger index = i + offset;
+        if (_wrapEnabled) {
+            index = [self clampedIndex:index];
+        }
+        CGFloat alpha = [self alphaForItemWithOffset:[self offsetForItemAtIndex:index]];
+        if (alpha) {
+            //only add views with alpha > 0
+            [visibleIndices addObject:@(index)];
+        }
+    }
+    
+    //remove offscreen views
+    for (NSNumber *number in [_itemViews allKeys])
+    {
+        if (![visibleIndices containsObject:number]) {
+            UIView *view = _itemViews[number];
+            if ([number integerValue] < 0 || [number integerValue] >= _numberOfItems) {
+                [self queuePlaceholderView:view];
+            } else {
+                [self queueItemView:view];
+            }
+            [view.superview removeFromSuperview];
+            [(NSMutableDictionary *)_itemViews removeObjectForKey:number];
+        }
+    }
+    
+    //add onscreen views
+    for (NSNumber *number in visibleIndices)
+    {
+        UIView *view = _itemViews[number];
+        if (view == nil) {
+            [self loadViewAtIndex:[number integerValue]];
+        }
+    }
+}
+
+#pragma mark View queing
+
+- (void)queueItemView:(UIView *)view
+{
+    if (view) {
+        [_itemViewPool addObject:view];
+    }
+}
+
+- (void)queuePlaceholderView:(UIView *)view
+{
+    if (view) {
+        [_placeholderViewPool addObject:view];
+    }
+}
+
+- (UIView *)dequeueItemView
+{
+    UIView *view = [_itemViewPool anyObject];
+    if (view) {
+        [_itemViewPool removeObject:view];
+    }
+    return view;
+}
+
+- (UIView *)dequeuePlaceholderView
+{
+    UIView *view = [_placeholderViewPool anyObject];
+    if (view) {
+        [_placeholderViewPool removeObject:view];
+    }
+    return view;
+}
+
+- (void)setIndicator:(WXIndicatorView *)indicator
+{
+    _indicator = indicator;
+    [_indicator setPointCount:self.numberOfItems];
+    [_indicator setCurrentPoint:[self currentItemIndex]];
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    _contentView.frame = self.bounds;
+    [self layOutItemViews];
+}
+
+@end
+
+@implementation NSObject (WXSliderNeighborView)
+
+- (NSUInteger)numberOfPlaceholdersInSliderNeighborView:(__unused WXSliderNeighborView *)sliderNeighbor { return 0; }
+- (void)sliderNeighborWillBeginScrollingAnimation:(__unused WXSliderNeighborView *)sliderNeighbor {}
+- (void)sliderNeighborDidEndScrollingAnimation:(__unused WXSliderNeighborView *)sliderNeighbor {}
+- (void)sliderNeighborDidScroll:(__unused WXSliderNeighborView *)sliderNeighbor {}
+
+- (void)sliderNeighborCurrentItemIndexDidChange:(__unused WXSliderNeighborView *)sliderNeighbor {}
+- (void)sliderNeighborWillBeginDragging:(__unused WXSliderNeighborView *)sliderNeighbor {}
+- (void)sliderNeighborDidEndDragging:(__unused WXSliderNeighborView *)sliderNeighbor willDecelerate:(__unused BOOL)decelerate {}
+- (void)sliderNeighborWillBeginDecelerating:(__unused WXSliderNeighborView *)sliderNeighbor {}
+- (void)sliderNeighborDidEndDecelerating:(__unused WXSliderNeighborView *)sliderNeighbor {}
+
+- (BOOL)sliderNeighbor:(__unused WXSliderNeighborView *)sliderNeighbor shouldSelectItemAtIndex:(__unused NSInteger)index { return YES; }
+- (void)sliderNeighbor:(__unused WXSliderNeighborView *)sliderNeighbor didSelectItemAtIndex:(__unused NSInteger)index {}
+
+- (CGFloat)sliderNeighborItemWidth:(__unused WXSliderNeighborView *)sliderNeighbor { return 0; }
+- (CATransform3D)sliderNeighbor:(__unused WXSliderNeighborView *)sliderNeighbor
+   itemTransformForOffset:(__unused CGFloat)offset
+            baseTransform:(CATransform3D)transform { return transform; }
+- (CGFloat)sliderNeighbor:(__unused WXSliderNeighborView *)sliderNeighbor
+     valueForOption:(__unused WXSliderNeighborOption)option
+        withDefault:(CGFloat)value { return value; }
+
+@end
+
+@interface WXSliderNeighborComponent () <WXIndicatorComponentDelegate>{
+    WXPixelType neighborSpace;
+    CGFloat neighborAlpha;
+    CGFloat neighborScale;
+    CGFloat currentItemScale;
+}
+
+@property (nonatomic, strong) WXSliderNeighborView *sliderView;
+@property (nonatomic, assign) BOOL  autoPlay;
+@property (nonatomic, assign) NSUInteger interval;
+@property (nonatomic, assign) NSInteger index;
+@property (nonatomic, strong) NSMutableArray *items;
+@property (nonatomic, strong) NSTimer *autoTimer;
+@property (nonatomic, assign) BOOL  sliderChangeEvent;
+@property (nonatomic, assign) NSInteger currentIndex;
+@property (nonatomic) CGRect itemRect;
+@property (nonatomic, assign) BOOL scrollable;
+
+@end
+
+#define DEFAULT_NEIGHBOR_ITEM_SCALE 0.8
+#define DEFAULT_CURRENT_ITEM_SCALE 0.9
+#define DEFAULT_NEIGHBOR_ALPHA 0.6
+#define DEFAULT_ANIMATION_DURATION 0.3
+#define DEFAULT_NEIGHBOR_SPACE 25
+
+
+@implementation WXSliderNeighborComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance {
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        _sliderChangeEvent = NO;
+        _interval = 3000;
+        _items = [NSMutableArray array];
+        _itemRect = CGRectNull;
+        self->neighborAlpha = DEFAULT_NEIGHBOR_ALPHA;
+        self->neighborScale = DEFAULT_NEIGHBOR_ITEM_SCALE;
+        self->currentItemScale = DEFAULT_CURRENT_ITEM_SCALE;
+        self->neighborSpace = [WXConvert WXPixelType:@(DEFAULT_NEIGHBOR_SPACE) scaleFactor:self.weexInstance.pixelScaleFactor];
+        _scrollable = YES;
+        [self setAttributes:attributes];
+    
+        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
+    }
+//#ifndef USE_FLEX
+    if (![WXComponent isUseFlex]) {
+        self.cssNode->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+    }
+//#else
+    else
+    {
+        self.flexCssNode->setFlexDirection(WeexCore::kFlexDirectionRow,NO);
+    }
+//#endif
+    return self;
+}
+
+
+#pragma mark life circle
+
+- (UIView *)loadView
+{
+    _sliderView = [[WXSliderNeighborView alloc] init];
+    return _sliderView;
+}
+
+- (void)dealloc
+{
+    _sliderView.delegate = nil;
+    _sliderView.dataSource = nil;
+    if (_autoPlay) {
+        [self _stopAutoPlayTimer];
+    }
+    _sliderView = nil;
+    [self.items removeAllObjects];
+}
+
+- (void)viewDidUnload
+{
+    [self.items removeAllObjects];
+}
+
+- (void)viewDidLoad
+{
+    _sliderView = (WXSliderNeighborView *)self.view;
+    _sliderView.delegate = self;
+    _sliderView.dataSource = self;
+    _sliderView.contentView.clipsToBounds = YES;
+    _sliderView.scrollEnabled = _scrollable;
+    UIAccessibilityTraits traits = UIAccessibilityTraitAdjustable;
+    
+    if (_autoPlay) {
+        traits |= UIAccessibilityTraitUpdatesFrequently;
+        [self _startAutoPlayTimer];
+    } else {
+        [self _stopAutoPlayTimer];
+    }
+    _sliderView.accessibilityTraits = traits;
+}
+
+- (void)layoutDidFinish {
+    
+    [_sliderView setCurrentItemIndex:_index];
+}
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    if (subcomponent->_positionType == WXPositionTypeFixed) {
+        [self.weexInstance.rootView addSubview:subcomponent.view];
+        return;
+    }
+    
+    // use _lazyCreateView to forbid component like cell's view creating
+    if(_lazyCreateView) {
+        subcomponent->_lazyCreateView = YES;
+    }
+    
+    if (!subcomponent->_lazyCreateView || (self->_lazyCreateView && [self isViewLoaded])) {
+        UIView *view = subcomponent.view;
+        
+        WXSliderNeighborView *sliderView = (WXSliderNeighborView *)self.view;
+        if ([view isKindOfClass:[WXIndicatorView class]]) {
+            ((WXIndicatorComponent *)subcomponent).delegate = self;
+            [sliderView addSubview:view];
+            return;
+        }
+        
+        if(index < 0) {
+            [self.items addObject:view];
+        } else {
+            [self.items insertObject:view atIndex:index];
+        }
+        
+        subcomponent.isViewFrameSyncWithCalculated = NO;
+        
+        if (index == -1) {
+            [sliderView insertView:view atIndex:index];
+        } else {
+            NSInteger offset = 0;
+            for (int i = 0; i < [self.items count]; ++i) {
+                if (index == i) break;
+                
+                if ([self.items[i] isKindOfClass:[WXIndicatorView class]]) {
+                    offset++;
+                }
+            }
+            [sliderView insertView:view atIndex:index - offset];
+        }
+        
+        [sliderView reloadData];
+    }
+}
+
+#pragma mark attributes update
+- (void)setAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"index"]) {
+        _index = [attributes[@"index"] integerValue];
+        _currentIndex = _index;
+    }
+    if (attributes[@"autoPlay"]) {
+        _autoPlay = [attributes[@"autoPlay"] boolValue];
+        if (_autoPlay) {
+            [self _startAutoPlayTimer];
+        } else {
+            [self _stopAutoPlayTimer];
+        }
+    }
+    if (attributes[@"interval"]) {
+        _interval = [attributes[@"interval"] integerValue];
+        
+        [self _stopAutoPlayTimer];
+        
+        if (_autoPlay) {
+            [self _startAutoPlayTimer];
+        }
+    }
+    if (attributes[@"neighborScale"]) {
+        [self setNeighborScale:attributes];
+    }
+    if (attributes[@"currentItemScale"]) {
+        [self setCurrentItemScale:attributes];
+    }
+    if (attributes[@"neighborAlpha"]) {
+        [self setNeighborAlpha:attributes];
+    }
+    if (attributes[@"neighborSpace"]) {
+        [self setNeighborSpace:attributes];
+    }
+    if (attributes[@"scrollable"]) {
+        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
+        ((WXSliderNeighborView *)self.view).scrollEnabled = _scrollable;
+    }
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    [self setAttributes:attributes];
+    [self.sliderView setCurrentItemIndex:_index];
+    [self updateSliderPage:YES];
+}
+
+#pragma mark styles update
+- (void)updateStyles:(NSDictionary *)styles {
+    
+}
+
+#pragma mark event
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"change"]) {
+        _sliderChangeEvent = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"change"]) {
+        _sliderChangeEvent = NO;
+    }
+}
+
+#pragma mark WXIndicatorComponentDelegate Methods
+
+- (void)setIndicatorView:(WXIndicatorView *)indicatorView
+{
+    NSAssert(_sliderView, @"");
+    [_sliderView setIndicator:indicatorView];
+}
+
+- (void)setNeighborSpace:(NSDictionary *)attributes{
+    if(attributes[@"neighborSpace"]) {
+        self->neighborSpace = [WXConvert WXPixelType:attributes[@"neighborSpace"] scaleFactor:self.weexInstance.pixelScaleFactor];
+    }
+}
+
+- (void)setNeighborAlpha:(NSDictionary *)attributes {
+    if (attributes[@"neighborAlpha"]) {
+        self->neighborAlpha = [WXConvert CGFloat:attributes[@"neighborAlpha"]];
+        self->neighborAlpha = self->neighborAlpha >= 0 ? self->neighborAlpha : 0;
+        self->neighborAlpha = self->neighborAlpha <= 1 ? self->neighborAlpha: 1;
+    }
+}
+
+- (void)setCurrentItemScale:(NSDictionary *)attributes {
+    if (attributes[@"currentItemScale"]) {
+        self->currentItemScale = [WXConvert CGFloat:attributes[@"currentItemScale"]];
+        self->currentItemScale = self->currentItemScale >= 0 ? self->currentItemScale : 0;
+        self->currentItemScale = self->currentItemScale <= 1 ? self->currentItemScale: 1;
+    }
+}
+
+- (void)setNeighborScale:(NSDictionary *)attributes
+{
+    if (attributes[@"neighborScale"]) {
+        self->neighborScale = [WXConvert CGFloat:attributes[@"neighborScale"]];
+        self->neighborScale = self->neighborScale >= 0? self->neighborScale : 0;
+        self->neighborScale = self->neighborScale <= 1? self->neighborScale :1;
+    }
+}
+
+#pragma mark Private Methods
+
+- (void)_startAutoPlayTimer
+{
+    if (!self.autoTimer || ![self.autoTimer isValid]) {
+        __weak __typeof__(self) weakSelf = self;
+        self.autoTimer = [NSTimer wx_scheduledTimerWithTimeInterval:_interval/1000.0f block:^() {
+            [weakSelf _autoPlayOnTimer];
+        } repeats:YES];
+        [[NSRunLoop currentRunLoop] addTimer:self.autoTimer forMode:NSRunLoopCommonModes];
+    }
+}
+
+- (void)_stopAutoPlayTimer
+{
+    if (self.autoTimer && [self.autoTimer isValid]) {
+        [self.autoTimer invalidate];
+        self.autoTimer = nil;
+    }
+}
+
+- (void)_autoPlayOnTimer
+{
+    WXSliderNeighborView *sliderNeighborView = (WXSliderNeighborView *)self.view;
+    
+    int indicatorCnt = 0;
+    for (int i = 0; i < [self.items count]; ++i) {
+        if ([self.items[i] isKindOfClass:[WXIndicatorView class]]) {
+            indicatorCnt++;
+        }
+    }
+    
+    self.currentIndex ++;
+    if (self.currentIndex >= self.items.count - indicatorCnt) {
+        self.currentIndex = 0;
+    }
+    
+    [sliderNeighborView setCurrentItemIndex:self.currentIndex];
+}
+
+#pragma mark sliderNeighbor Delegate && dataSource
+
+- (NSInteger)numberOfItemsInSliderNeighbor:(WXSliderNeighborView *)sliderNeighbor {
+    return [self.items count];
+}
+
+- (NSInteger)numberOfPlaceholdersInsliderNeighbor:(WXSliderNeighborView *)sliderNeighbor {
+    return 2;
+}
+
+- (UIView *)sliderNeighbor:(WXSliderNeighborView *)sliderNeighbor viewForItemAtIndex:(NSInteger)index reusingView:(UIView *)view {
+    
+    if (!view) {
+        if (index < [self.items count]) {
+            view = self.items[index];
+        }else {
+            return nil;
+        }
+    } else {
+        view.tag = 1;
+    }
+    
+    if (CGRectIsNull(_itemRect)) {
+        _itemRect = view.frame;
+    }
+    if (index == [self.items count] - 1) {
+        [self updateSliderPage:NO];
+    }
+    
+    return view;
+}
+
+- (BOOL)sliderNeighbor:(WXSliderNeighborView *)sliderNeighbor shouldSelectItemAtIndex:(NSInteger)index {
+    
+    return YES;
+}
+
+- (UIView *)sliderNeighbor:(WXSliderNeighborView *)sliderNeighbor placeholderViewAtIndex:(NSInteger)index reusingView:(UIView *)view
+{
+    
+    return view;
+}
+
+- (void)sliderNeighborDidEndScrollingAnimation:(WXSliderNeighborView *)sliderNeighbor
+{
+    [self updateSliderPage:YES];
+}
+
+- (void)sliderNeighbor:(WXSliderNeighborView *)sliderView didScrollToItemAtIndex:(NSInteger)index
+{
+    self.currentIndex = index;
+    
+    if (_sliderChangeEvent) {
+        [self fireEvent:@"change" params:@{@"index":@(index)} domChanges:@{@"attrs": @{@"index": @(index)}}];
+    }
+}
+
+- (void)sliderNeighborWillBeginDragging:(WXSliderNeighborView *)sliderNeighbor
+{
+    [self _stopAutoPlayTimer];
+}
+
+- (void)sliderNeighborDidEndDragging:(WXSliderNeighborView *)sliderNeighbor willDecelerate:(BOOL)decelerate {
+    if (_autoPlay) {
+        [self _startAutoPlayTimer];
+    }
+}
+
+- (void)updateSliderPage:(BOOL)animate
+{
+    __block UIView * currentView  = [self.sliderView itemViewAtIndex:[_sliderView currentItemIndex]];
+    __block UIView * lastView  = [self.sliderView itemViewAtIndex:[_sliderView lastItemIndex]];
+    __block UIView * nextView  = [self.sliderView itemViewAtIndex:[_sliderView nextItemIndex]];
+    
+    __block CGAffineTransform transfrom = CGAffineTransformIdentity;
+    float duration = 0;
+    __weak typeof(self) weakSelf = self;
+    if (animate) {
+        duration = DEFAULT_ANIMATION_DURATION;
+    }
+    
+    [UIView animateWithDuration:duration animations:^{
+        __strong typeof(self) strongSelf = weakSelf;
+        if (strongSelf) {
+            currentView.alpha = 1.0;
+            if (fabs(strongSelf->currentItemScale) > CGFLOAT_MIN) {
+                transfrom = CGAffineTransformConcat(transfrom,CGAffineTransformMakeScale(strongSelf->currentItemScale, strongSelf->currentItemScale));
+            }
+            currentView.transform = transfrom;
+            transfrom = CGAffineTransformIdentity;
+            if (fabs(strongSelf->neighborScale) <= CGFLOAT_MIN) {
+                strongSelf->neighborScale = DEFAULT_NEIGHBOR_ITEM_SCALE;
+            }
+            
+            CGFloat tx = 0.5*_itemRect.size.width*((1-self->neighborScale)+(1-self->currentItemScale))-self->neighborSpace;
+            transfrom = CGAffineTransformConcat(transfrom, CGAffineTransformMakeScale(strongSelf->neighborScale, strongSelf->neighborScale));
+            nextView.transform = CGAffineTransformConcat(transfrom,  CGAffineTransformMakeTranslation(-tx, 0));
+            lastView.transform = CGAffineTransformConcat(transfrom,  CGAffineTransformMakeTranslation(tx, 0));
+            lastView.alpha = strongSelf->neighborAlpha;
+            nextView.alpha = strongSelf->neighborAlpha;
+        }
+    }];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.m
deleted file mode 100644
index f5f9ce2..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.m
+++ /dev/null
@@ -1,151 +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 "WXSwitchComponent.h"
-#import "WXConvert.h"
-#import "WXComponent_internal.h"
-
-@interface WXSwitchView : UISwitch
-
-@end
-
-@implementation WXSwitchView
-
-@end
-
-@interface WXSwitchComponent()
-
-@property (nonatomic, strong)   WXSwitchView    *switchView;
-@property (nonatomic, assign)   BOOL    changeEvent;
-@property (nonatomic, assign)   BOOL    checked;
-@property (nonatomic, assign)   BOOL    disabled;
-
-//Background color when the switch is turned on.
-@property (nonatomic, strong)  UIColor *onTintColor;
-
-
-//Color of the foreground switch grip.
-@property (nonatomic, strong)  UIColor *thumbTintColor;
-
-//Border color and background color on Android when the switch is turned off
-@property (nonatomic, strong)  UIColor *tintColor;
-
-@end
-
-@implementation WXSwitchComponent
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
-        _checked = attributes[@"checked"] ? [WXConvert BOOL:attributes[@"checked"]] : NO;
-        _disabled = attributes[@"disabled"] ? [WXConvert BOOL:attributes[@"disabled"]] : NO;
-        
-        if(attributes[@"onTintColor"]){
-            _onTintColor = [WXConvert UIColor:attributes[@"onTintColor"]];
-        }
-
-        if(attributes[@"thumbTintColor"]){
-            _thumbTintColor = [WXConvert UIColor:attributes[@"thumbTintColor"]];
-        }
-
-        if(attributes[@"tintColor"]){
-            _tintColor = [WXConvert UIColor:attributes[@"tintColor"]];
-        }
-        
-        self.cssNode->style.dimensions[CSS_WIDTH] = 51;
-        self.cssNode->style.dimensions[CSS_HEIGHT] = 31;
-    }
-    return self;
-}
-
-- (UIView *)loadView
-{
-    return [[WXSwitchView alloc] init];
-}
-
-- (void)viewDidLoad
-{
-    _switchView = (WXSwitchView *)self.view;
-    _switchView.isAccessibilityElement = YES;
-    [_switchView setOn:_checked animated:YES];
-    [_switchView setEnabled:!_disabled];
-    [_switchView addTarget:self action:@selector(checkChanged) forControlEvents:UIControlEventValueChanged];
-    
-    if(_onTintColor){
-        _switchView.onTintColor = _onTintColor;
-    }
-
-    if(_tintColor){
-        _switchView.tintColor = _tintColor;
-    }
-
-    if(_thumbTintColor){
-        _switchView.thumbTintColor = _thumbTintColor;
-    }
-}
-
-- (void)addEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"change"]) {
-        _changeEvent = YES;
-    }
-}
-
-- (void)removeEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"change"]) {
-        _changeEvent = NO;
-    }
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    if (attributes[@"checked"]) {
-        _checked = [WXConvert BOOL:attributes[@"checked"]];
-        [_switchView setOn:_checked animated:YES];
-    }
-    else if (attributes[@"disabled"]) {
-        _disabled = [WXConvert BOOL:attributes[@"disabled"]];
-        [_switchView setEnabled:!_disabled];
-    }
-    
-    if(attributes[@"onTintColor"]){
-        _onTintColor = [WXConvert UIColor:attributes[@"onTintColor"]];
-        _switchView.onTintColor = _onTintColor;
-    }
-    
-    if(attributes[@"thumbTintColor"]){
-        _thumbTintColor = [WXConvert UIColor:attributes[@"thumbTintColor"]];
-        _switchView.thumbTintColor = _thumbTintColor;
-    }
-    
-    if(attributes[@"tintColor"]){
-        _tintColor = [WXConvert UIColor:attributes[@"tintColor"]];
-        _switchView.tintColor = _tintColor;
-    }
-}
-
-- (void)checkChanged
-{
-   if (_changeEvent) {
-        [self fireEvent:@"change" params:@{@"value":@([_switchView isOn])} domChanges:@{@"attrs": @{@"checked": @([_switchView isOn])}}];
-   }
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.mm
new file mode 100644
index 0000000..16903a0
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.mm
@@ -0,0 +1,162 @@
+/*
+ * 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 "WXSwitchComponent.h"
+#import "WXConvert.h"
+#import "WXComponent_internal.h"
+#import "WXComponent+Layout.h"
+
+@interface WXSwitchView : UISwitch
+
+@end
+
+@implementation WXSwitchView
+
+@end
+
+@interface WXSwitchComponent()
+
+@property (nonatomic, strong)   WXSwitchView    *switchView;
+@property (nonatomic, assign)   BOOL    changeEvent;
+@property (nonatomic, assign)   BOOL    checked;
+@property (nonatomic, assign)   BOOL    disabled;
+
+//Background color when the switch is turned on.
+@property (nonatomic, strong)  UIColor *onTintColor;
+
+
+//Color of the foreground switch grip.
+@property (nonatomic, strong)  UIColor *thumbTintColor;
+
+//Border color and background color on Android when the switch is turned off
+@property (nonatomic, strong)  UIColor *tintColor;
+
+@end
+
+@implementation WXSwitchComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        _checked = attributes[@"checked"] ? [WXConvert BOOL:attributes[@"checked"]] : NO;
+        _disabled = attributes[@"disabled"] ? [WXConvert BOOL:attributes[@"disabled"]] : NO;
+        
+        if(attributes[@"onTintColor"]){
+            _onTintColor = [WXConvert UIColor:attributes[@"onTintColor"]];
+        }
+
+        if(attributes[@"thumbTintColor"]){
+            _thumbTintColor = [WXConvert UIColor:attributes[@"thumbTintColor"]];
+        }
+
+        if(attributes[@"tintColor"]){
+            _tintColor = [WXConvert UIColor:attributes[@"tintColor"]];
+        }        
+//#ifndef USE_FLEX
+        if (![WXComponent isUseFlex])
+        {
+            self.cssNode->style.dimensions[CSS_WIDTH] = 51;
+            self.cssNode->style.dimensions[CSS_HEIGHT] = 31;
+        }
+//#else
+        else
+        {
+            self.flexCssNode->setStyleWidth(51,NO);
+            self.flexCssNode->setStyleHeight(31);
+        }
+//#endif
+    }
+    return self;
+}
+
+- (UIView *)loadView
+{
+    return [[WXSwitchView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+    _switchView = (WXSwitchView *)self.view;
+    _switchView.isAccessibilityElement = YES;
+    [_switchView setOn:_checked animated:YES];
+    [_switchView setEnabled:!_disabled];
+    [_switchView addTarget:self action:@selector(checkChanged) forControlEvents:UIControlEventValueChanged];
+    
+    if(_onTintColor){
+        _switchView.onTintColor = _onTintColor;
+    }
+
+    if(_tintColor){
+        _switchView.tintColor = _tintColor;
+    }
+
+    if(_thumbTintColor){
+        _switchView.thumbTintColor = _thumbTintColor;
+    }
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"change"]) {
+        _changeEvent = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"change"]) {
+        _changeEvent = NO;
+    }
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"checked"]) {
+        _checked = [WXConvert BOOL:attributes[@"checked"]];
+        [_switchView setOn:_checked animated:YES];
+    }
+    else if (attributes[@"disabled"]) {
+        _disabled = [WXConvert BOOL:attributes[@"disabled"]];
+        [_switchView setEnabled:!_disabled];
+    }
+    
+    if(attributes[@"onTintColor"]){
+        _onTintColor = [WXConvert UIColor:attributes[@"onTintColor"]];
+        _switchView.onTintColor = _onTintColor;
+    }
+    
+    if(attributes[@"thumbTintColor"]){
+        _thumbTintColor = [WXConvert UIColor:attributes[@"thumbTintColor"]];
+        _switchView.thumbTintColor = _thumbTintColor;
+    }
+    
+    if(attributes[@"tintColor"]){
+        _tintColor = [WXConvert UIColor:attributes[@"tintColor"]];
+        _switchView.tintColor = _tintColor;
+    }
+}
+
+- (void)checkChanged
+{
+   if (_changeEvent) {
+        [self fireEvent:@"change" params:@{@"value":@([_switchView isOn])} domChanges:@{@"attrs": @{@"checked": @([_switchView isOn])}}];
+   }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXTextAreaComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextAreaComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXTextAreaComponent.m
deleted file mode 100644
index 24ee17f..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXTextAreaComponent.m
+++ /dev/null
@@ -1,233 +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 "WXTextAreaComponent.h"
-#import "WXUtility.h"
-#import "WXComponent+Layout.h"
-#import "WXComponent_internal.h"
-
-#define CorrectX 4 //textview fill text 4 pixel from left. so placeholderlabel have 4 pixel too
-#define CorrectY 8 // textview fill text 8 pixel from top
-typedef UITextView WXTextAreaView;
-
-@interface WXTextAreaComponent()
-
-@property (nonatomic, strong) WXTextAreaView *textView;
-@property (nonatomic) NSUInteger rows;
-
-@end
-
-@implementation WXTextAreaComponent {
-    UIEdgeInsets _border;
-    UIEdgeInsets _padding;
-}
-
--(void)viewDidLoad
-{
-    _padding = UIEdgeInsetsZero;
-    _border = UIEdgeInsetsZero;
-    if (self.placeholderString) {
-        self.placeHolderLabel = [[UILabel alloc] init];
-        self.placeHolderLabel.numberOfLines = 0;
-        [_textView addSubview:self.placeHolderLabel];
-    }
-    // default placeholder hide from voice over
-    self.placeHolderLabel.isAccessibilityElement = NO;
-    _textView.isAccessibilityElement = YES;
-    _textView.delegate = self;
-    [_textView setNeedsDisplay];
-    [_textView setClipsToBounds:YES];
-    [super viewDidLoad];
-}
-
-- (void)viewWillUnload
-{
-    _textView = nil;
-}
-
-- (UIView *)loadView
-{
-    _textView = [[WXTextAreaView alloc] init];
-    return _textView;
-}
-
-#pragma mark measure frame
-- (CGSize (^)(CGSize))measureBlock
-{
-    __weak typeof(self) weakSelf = self;
-    return ^CGSize (CGSize constrainedSize) {
-        
-        CGSize computedSize = [[[NSString alloc] init]sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:weakSelf.textView.font.pointSize]}];
-        computedSize.height = _rows? computedSize.height *weakSelf.rows + (CorrectY + CorrectY/2):0;
-        if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
-            computedSize.width = MAX(computedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
-            computedSize.width = MIN(computedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_HEIGHT])) {
-            computedSize.height = MAX(computedSize.height, weakSelf.cssNode->style.minDimensions[CSS_HEIGHT]);
-        }
-        
-        if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT])) {
-            computedSize.height = MIN(computedSize.height, weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT]);
-        }
-        
-        return (CGSize) {
-            WXCeilPixelValue(computedSize.width),
-            WXCeilPixelValue(computedSize.height)
-        };
-    };
-}
-
-#pragma mark -Overwrite method
--(NSString *)text
-{
-    return _textView.text;
-}
-
-- (void)setText:(NSString *)text
-{
-    _textView.text = text;
-    if ([text length] >0) {
-        self.placeHolderLabel.text = @"";
-    }
-}
-
--(void)setTextColor:(UIColor *)color
-{
-    [_textView setTextColor:color];
-}
-
--(void)setTextAlignment:(NSTextAlignment)textAlignForStyle
-{
-    [_textView setTextAlignment:textAlignForStyle];
-}
-
--(void)setUserInteractionEnabled:(BOOL)userInteractionEnabled
-{
-    [_textView setUserInteractionEnabled:userInteractionEnabled];
-}
-
--(void)setEnabled:(BOOL)enabled
-{
-    _textView.editable = enabled;
-    _textView.selectable = enabled;
-}
-
--(void)setReturnKeyType:(UIReturnKeyType)returnKeyType
-{
-    [_textView setReturnKeyType:returnKeyType];
-}
-
--(void)setInputAccessoryView:(UIView *)inputAccessoryView
-{
-    [_textView setInputAccessoryView:inputAccessoryView];
-}
-
--(void)setEditSelectionRange:(NSInteger)selectionStart selectionEnd:(NSInteger)selectionEnd
-{
-    [self.textView becomeFirstResponder];
-    UITextPosition *startPos =  [self.textView positionFromPosition:self.textView.beginningOfDocument offset:selectionStart];
-    UITextPosition *endPos = [self.textView positionFromPosition:self.textView.beginningOfDocument offset:selectionEnd];
-    UITextRange *textRange = [self.textView textRangeFromPosition:startPos
-                                                       toPosition:endPos];
-    self.textView.selectedTextRange = textRange;
-}
-
--(NSDictionary *)getEditSelectionRange
-{
-    NSInteger selectionStart = [self.textView offsetFromPosition:self.textView.beginningOfDocument toPosition:self.textView.selectedTextRange.start];
-    NSInteger selectionEnd = [self.textView offsetFromPosition:self.textView.beginningOfDocument toPosition:self.textView.selectedTextRange.end];
-    NSDictionary *res = @{@"selectionStart":@(selectionStart),@"selectionEnd":@(selectionEnd)};
-    return res;
-}
-
--(void)setKeyboardType:(UIKeyboardType)keyboardType
-{
-    [_textView setKeyboardType:keyboardType];
-}
-
--(void)setSecureTextEntry:(BOOL)secureTextEntry
-{
-    [_textView setSecureTextEntry:secureTextEntry];
-}
-
--(void)setEditPadding:(UIEdgeInsets)padding
-{
-    _padding = padding;
-    [self _updateTextContentInset];
-}
-
--(void)setEditBorder:(UIEdgeInsets)border
-{
-    _border = border;
-    [self _updateTextContentInset];
-}
-
--(void)setAttributedPlaceholder:(NSMutableAttributedString *)attributedString font:(UIFont *)font
-{
-    if (self.placeholderColor) {
-        [attributedString addAttribute:NSForegroundColorAttributeName value:self.placeholderColor range:NSMakeRange(0, self.placeholderString.length)];
-        [attributedString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, self.placeholderString.length)];
-    }
-    self.placeHolderLabel.backgroundColor = [UIColor clearColor];
-    CGRect expectedLabelSize = [attributedString boundingRectWithSize:(CGSize){self.view.frame.size.width, CGFLOAT_MAX}
-                                                              options:NSStringDrawingUsesLineFragmentOrigin
-                                                              context:nil];
-    
-    self.placeHolderLabel.clipsToBounds = NO;
-    CGRect newFrame = self.placeHolderLabel.frame;
-    newFrame.size.height = ceil(expectedLabelSize.size.height);
-    newFrame.size.width = _textView.frame.size.width- CorrectX*2;
-    newFrame.origin.x = CorrectX + _padding.left + _border.left; // the cursor origin.x
-    self.placeHolderLabel.frame = newFrame;
-    self.placeHolderLabel.attributedText = attributedString;
-}
-
--(void)setFont:(UIFont *)font
-{
-    [_textView setFont:font];
-}
-
--(void)setRows:(NSUInteger)rows
-{
-    _rows = rows;
-    [self setNeedsLayout];
-}
-
-#pragma mark -Private Method
-- (void)_updateTextContentInset
-{
-    [_textView setTextContainerInset:UIEdgeInsetsMake(_padding.top + _border.top,
-                                                      _padding.left + _border.left,
-                                                      _padding.bottom + _border.bottom,
-                                                      _border.right + _border.right)];
-    
-    //when textview update, placeHolderLabel update too
-    CGRect newFrame = self.placeHolderLabel.frame;
-    newFrame.size.width = self.textView.frame.size.width - (_padding.left + _border.left) -CorrectX*2;
-    newFrame.origin.x = CorrectX + _padding.left + _border.left; // the cursor origin.x
-    newFrame.origin.y = _padding.top + _border.top;
-    self.placeHolderLabel.frame = newFrame;
-}
-
-@end


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp b/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp
new file mode 100644
index 0000000..7d34d83
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp
@@ -0,0 +1,1038 @@
+#include "WXCoreLayout.h"
+
+using namespace WeexCore;
+
+namespace WeexCore {
+
+  /**
+   * Entry function to calculate layout
+   */
+  void WXCoreLayoutNode::calculateLayout(const std::pair<float,float> &renderPageSize) {
+    BFCs.clear();
+    initFormatingContext(BFCs);
+    auto bfcDimension = calculateBFCDimension(renderPageSize);
+    if (std::get<0>(bfcDimension) || isDirty()) {
+      mChildrenFrozen.assign(getChildCount(kNonBFC), false);
+      measure(std::get<1>(bfcDimension), std::get<2>(bfcDimension), true);
+      checkSizeConstraints(this, false);
+    }
+    layout(mCssStyle->mMargin.getMargin(kMarginLeft),
+           mCssStyle->mMargin.getMargin(kMarginTop),
+           mCssStyle->mMargin.getMargin(kMarginLeft) + getLayoutWidth(),
+           mCssStyle->mMargin.getMargin(kMarginTop) + getLayoutHeight(),
+           false, &renderPageSize);
+    for (Index i = 0; i < getChildCount(kBFC); ++i) {
+      WXCoreLayoutNode *child = getChildAt(kBFC, i);
+      child->calculateLayout(renderPageSize);
+    }
+  }
+
+  void WXCoreLayoutNode::initFormatingContext(std::vector<WXCoreLayoutNode *> &BFCs) {
+    NonBFCs.clear();
+    for(auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
+      WXCoreLayoutNode* child = *it;
+      if (child != nullptr) {
+        if (isBFC(child)) {
+          BFCs.push_back(child);
+        } else {
+          NonBFCs.push_back(child);
+          child->initFormatingContext(BFCs);
+        }
+      }
+    }
+    reset();
+  }
+
+  std::tuple<bool, float, float> WXCoreLayoutNode::calculateBFCDimension(const std::pair<float,float>& renderPageSize) {
+    bool sizeChanged = false;
+    float width = mCssStyle->mStyleWidth, height = mCssStyle->mStyleHeight;
+    std::pair<bool,float> ret;
+    if (isBFC(this)) {
+      ret = calculateBFCWidth(width, renderPageSize.first);
+      sizeChanged |=ret.first;
+      width = ret.second;
+
+      ret = calculateBFCHeight(height,renderPageSize.second);
+      sizeChanged |=ret.first;
+      height = ret.second;
+    }
+    return std::make_tuple(sizeChanged, width, height);
+  }
+
+  std::pair<bool,float> WXCoreLayoutNode::calculateBFCWidth(float width, const float renderPageWidth){
+    bool sizeChanged = false;
+    if (isnan(width) &&
+        mParent != nullptr &&
+        !isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft)) &&
+        !isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeRight))) {
+      float containingBlockWidth = NAN;
+      switch (mCssStyle->mPositionType) {
+        case kAbsolute:
+          containingBlockWidth = mParent->mLayoutResult->mLayoutSize.width;
+          break;
+        case kFixed:
+          if (!isnan(renderPageWidth)) {
+            containingBlockWidth = renderPageWidth;
+          }
+          break;
+        default:
+              break;
+      }
+      if (!isnan(containingBlockWidth)) {
+        width = containingBlockWidth -
+            mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft) -
+            mCssStyle->mStylePosition.getPosition(kPositionEdgeRight);
+        setWidthMeasureMode(kExactly);
+        sizeChanged = true;
+      }
+    }
+    return std::make_pair(sizeChanged, width);
+  }
+
+
+  std::pair<bool,float> WXCoreLayoutNode::calculateBFCHeight(float height, const float renderPageHeight){
+    bool sizeChanged = false;
+    if (isnan(mCssStyle->mStyleHeight) &&
+        mParent != nullptr &&
+        !isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeTop)) &&
+        !isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom))) {
+      float containingBlockHeight = NAN;
+      switch (mCssStyle->mPositionType) {
+        case kAbsolute:
+          containingBlockHeight = mParent->mLayoutResult->mLayoutSize.height;
+          break;
+        case kFixed:
+          if (!isnan(renderPageHeight)) {
+            containingBlockHeight = renderPageHeight;
+          }
+          break;
+        default:
+          break;
+      }
+      if (!isnan(containingBlockHeight)) {
+        height = containingBlockHeight -
+            mCssStyle->mStylePosition.getPosition(kPositionEdgeTop) -
+            mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom);
+        setHeightMeasureMode(kExactly);
+        sizeChanged = true;
+      }
+    }
+    return std::make_pair(sizeChanged, height);
+  }
+
+  void WXCoreLayoutNode::measure(const float width, const float height, const bool hypotheticalMeasurment){
+    if(hypotheticalMeasurment){
+      //Only BFC will enter this case.
+      hypotheticalMeasure(width, height);
+    }
+
+    if(getChildCount(kNonBFC) > 0){
+      if((isMainAxisHorizontal(this) && widthDirty) || (!isMainAxisHorizontal(this) && heightDirty)){
+        measureInternalNode(width, height, false, false);
+      }
+      determineMainSize(width, height);
+      determineCrossSize(width, height, true);
+      measureInternalNode(width, height, true, false);
+      determineCrossSize(width, height, false);
+    }
+    else {
+      if (widthDirty || heightDirty) {
+        measureLeafNode(width, height, hypotheticalMeasurment, false);
+      }
+    }
+    clearDirty();
+  }
+
+  void WXCoreLayoutNode::hypotheticalMeasure(const float width, const float height, const bool stretch){
+    if (getChildCount(kNonBFC) > 0) {
+      measureInternalNode(width, height, true, true);
+    } else {
+      measureLeafNode(width, height, true, stretch);
+    }
+
+    widthDirty = false;
+    heightDirty = false;
+    mLayoutResult->mLayoutSize.hypotheticalWidth = mLayoutResult->mLayoutSize.width;
+    mLayoutResult->mLayoutSize.hypotheticalHeight = mLayoutResult->mLayoutSize.height;
+  }
+
+  void WXCoreLayoutNode::measureLeafNode(float width, float height, const bool hypothetical, const bool stretch) {
+    if ((measureFunc != nullptr) &&
+        (widthMeasureMode == kUnspecified
+            || heightMeasureMode == kUnspecified)) {
+      float constrainsWidth = width;
+      if(widthMeasureMode == kExactly && !isnan(width)){
+        constrainsWidth -= sumPaddingBorderAlongAxis(this, true);
+      }
+      WXCoreSize dimension = measureFunc(this, constrainsWidth,
+                                         (stretch && !isnan(width)) ? kExactly:widthMeasureMode,
+                                         height, heightMeasureMode);
+      if (widthMeasureMode == kUnspecified) {
+        float actualWidth = dimension.width + sumPaddingBorderAlongAxis(this, true);
+        if (isnan(width)) {
+          width = actualWidth;
+        } else if (!stretch) {
+          width = std::min(width, actualWidth);
+        }
+      }
+      if (heightMeasureMode == kUnspecified) {
+        float actualHeight = dimension.height + sumPaddingBorderAlongAxis(this, false);
+        if (isnan(height)) {
+          height = actualHeight;
+        } else if (!stretch) {
+          height = std::min(height, actualHeight);
+        }
+      }
+    } else {
+      width = widthMeasureMode == kUnspecified ? sumPaddingBorderAlongAxis(this, true)
+                                               : width;
+      height = heightMeasureMode == kUnspecified ? sumPaddingBorderAlongAxis(this, false)
+                                                 : height;
+    }
+    setMeasuredDimension(width, height);
+  }
+
+
+  /**
+   * Determine the main size by expanding the individual flexGrow attribute.
+   */
+  void WXCoreLayoutNode::determineMainSize(const float width, const float height) {
+      bool horizontal = isMainAxisHorizontal(this);
+      if((horizontal && widthMeasureMode == kExactly) || (!horizontal && heightMeasureMode == kExactly)) {
+        //The measureMode along main axis is exactly
+        float maxMainSize = horizontal ? width: height;
+        maxMainSize -= sumPaddingBorderAlongAxis(this, isMainAxisHorizontal(this));
+        Index childIndex = 0;
+        for (WXCoreFlexLine *flexLine : mFlexLines) {
+          childIndex = expandItemsInFlexLine(flexLine, maxMainSize, childIndex);
+        }
+      }
+    }
+
+
+  /**
+   * @param flexDirection         the flex direction attribute
+   * @param width                 stylewidth by this node
+   * @param height                styleheight by this node
+   * @param paddingAlongCrossAxis the padding value for this node along the cross axis
+   */
+    void WXCoreLayoutNode::determineCrossSize(const float width, const float height, const bool stretch) {
+      if (mFlexLines.size() == 1 && isCrossExactly()) {
+        bool horizontal = isMainAxisHorizontal(this);
+        float size = mFlexLines[0]->mCrossSize;
+        float paddingAlongCrossAxis = sumPaddingBorderAlongAxis(this, !horizontal);
+        if (horizontal) {
+          if (heightMeasureMode == kExactly) {
+            size = height - paddingAlongCrossAxis;
+          }
+        } else {
+          if (widthMeasureMode == kExactly) {
+            size = width - paddingAlongCrossAxis;
+          }
+        }
+        mFlexLines[0]->mCrossSize = size;
+      }
+      if (stretch) {
+        stretchViewCrossSize();
+      }
+    }
+
+
+    void WXCoreLayoutNode::measureInternalNode(const float width, const float height, const bool needMeasure,
+                                               const bool hypotheticalMeasurment) {
+      for (WXCoreFlexLine *flexLine : mFlexLines) {
+        if(flexLine!= nullptr) {
+          delete flexLine;
+        }
+        flexLine = nullptr;
+      }
+      mFlexLines.clear();
+      Index childCount = getChildCount(kNonBFC);
+      WXCoreFlexLine *flexLine = new WXCoreFlexLine();
+
+      for (Index i = 0; i < childCount; i++) {
+        WXCoreLayoutNode *child = getChildAt(kNonBFC, i);
+        if (child->mCssStyle->mAlignSelf == kAlignSelfStretch) {
+          flexLine->mIndicesAlignSelfStretch.push_back(i);
+        }
+        measureChild(child, flexLine->mMainSize, width, height, needMeasure, hypotheticalMeasurment);
+        checkSizeConstraints(child, hypotheticalMeasurment);
+
+        if (isWrapRequired(width, height, flexLine->mMainSize,
+                           calcItemSizeAlongAxis(child, isMainAxisHorizontal(this)))) {
+          if (flexLine->mItemCount > 0) {
+            mFlexLines.push_back(flexLine);
+          }
+          flexLine = new WXCoreFlexLine();
+          flexLine->mItemCount = 1;
+        } else {
+          flexLine->mItemCount++;
+        }
+        updateCurrentFlexline(childCount, flexLine, i, child, hypotheticalMeasurment || (!hypotheticalMeasurment && !needMeasure));
+      }
+      setMeasuredDimensionForFlex(width, widthMeasureMode, height, heightMeasureMode);
+    }
+
+    void WXCoreLayoutNode::updateCurrentFlexline(const Index childCount, WXCoreFlexLine* const flexLine, const Index i,
+                                                 const WXCoreLayoutNode* const child, const bool useHypotheticalSize){
+      flexLine->mMainSize += calcItemSizeAlongAxis(child, isMainAxisHorizontal(this), useHypotheticalSize);
+      sumFlexGrow(child, flexLine, i);
+      flexLine->mCrossSize =
+          std::max(flexLine->mCrossSize, calcItemSizeAlongAxis(child, !isMainAxisHorizontal(this), useHypotheticalSize));
+      if (i == childCount - 1 && flexLine->mItemCount != 0) {
+        mFlexLines.push_back(flexLine);
+      }
+    }
+
+    void WXCoreLayoutNode::measureChild(WXCoreLayoutNode* const child, const float currentMainSize,
+                                        const float parentWidth, const float parentHeight,
+                                        const bool needMeasure, const bool hypotheticalMeasurment) {
+      if (needMeasure && child->isDirty()) {
+        if (hypotheticalMeasurment) {
+          float childWidth = child->mCssStyle->mStyleWidth;
+          float childHeight = child->mCssStyle->mStyleHeight;
+          bool stretch = !isMainAxisHorizontal(this) &&
+              child->measureFunc != nullptr &&
+              widthMeasureMode == kExactly &&
+              isSingleFlexLine(parentHeight) &&
+              ((child->mCssStyle->mAlignSelf == kAlignSelfStretch) ||
+                  (mCssStyle->mAlignItems == kAlignItemsStretch
+                      && child->mCssStyle->mAlignSelf == kAlignSelfAuto));
+
+          adjustChildSize(child, currentMainSize, parentWidth,
+                          parentHeight, childWidth, childHeight);
+          child->hypotheticalMeasure(childWidth, childHeight, stretch);
+        } else {
+          if(isSingleFlexLine(isMainAxisHorizontal(this) ? parentWidth : parentHeight)
+              && !isMainAxisHorizontal(this) && child->widthMeasureMode == kUnspecified){
+            child->setLayoutWidth(parentWidth - sumPaddingBorderAlongAxis(this, true)
+                                      -child->mCssStyle->sumMarginOfDirection(true));
+            if(child->heightMeasureMode == kUnspecified && child->widthDirty) {
+              child->mLayoutResult->mLayoutSize.height = NAN;
+            }
+          }
+          child->measure(child->mLayoutResult->mLayoutSize.width,
+                         child->mLayoutResult->mLayoutSize.height, hypotheticalMeasurment);
+        }
+      }
+    }
+
+    void WXCoreLayoutNode::adjustChildSize(const WXCoreLayoutNode *child,
+                                        const float currentMainSize,
+                                        const float parentWidth,
+                                        const float parentHeight,
+                                        float &childWidth,
+                                        float &childHeight) const {
+      if(child->measureFunc == nullptr) {
+        if(!isnan(childWidth)){
+          childWidth = std::max(childWidth, child->sumPaddingBorderAlongAxis(child, true));
+        }
+        if(!isnan(childHeight)){
+          childHeight = std::max(childHeight, child->sumPaddingBorderAlongAxis(child, false));
+        }
+      }
+
+      if (isSingleFlexLine(isMainAxisHorizontal(this) ? parentWidth : parentHeight)) {
+        if (isMainAxisHorizontal(this)) {
+          if (!isnan(parentHeight) && isnan(child->mCssStyle->mStyleHeight)
+              && child->mCssStyle->mAlignSelf == kAlignSelfAuto
+              && mCssStyle->mAlignItems == kAlignItemsStretch) {
+            childHeight = parentHeight - sumPaddingBorderAlongAxis(this, false) -
+                child->mCssStyle->sumMarginOfDirection(false);
+          }
+        } else {
+          if (!isnan(parentWidth) && isnan(child->mCssStyle->mStyleWidth)) {
+            childWidth = parentWidth - sumPaddingBorderAlongAxis(this, true) -
+                child->mCssStyle->sumMarginOfDirection(true);
+          }
+       }
+      }
+    }
+
+    void WXCoreLayoutNode::checkSizeConstraints(WXCoreLayoutNode* const node, const bool hypotheticalMeasurment) {
+      bool widthRemeasure = false, heightRemeasure = false;
+      float nodeWidth,nodeHeight;
+      nodeWidth = node->mLayoutResult->mLayoutSize.width;
+      nodeHeight = node->mLayoutResult->mLayoutSize.height;
+
+      if (!isnan(node->mCssStyle->mMinWidth) &&
+          nodeWidth < node->mCssStyle->mMinWidth) {
+        widthRemeasure = true;
+        nodeWidth = node->mCssStyle->mMinWidth;
+      } else if (!isnan(node->mCssStyle->mMaxWidth)
+          && nodeWidth > node->mCssStyle->mMaxWidth) {
+        widthRemeasure = true;
+        nodeWidth = node->mCssStyle->mMaxWidth;
+      }
+
+      if (!isnan(node->mCssStyle->mMinHeight) &&
+          nodeHeight < node->mCssStyle->mMinHeight) {
+        heightRemeasure = true;
+        nodeHeight = node->mCssStyle->mMinHeight;
+      } else if (!isnan(node->mCssStyle->mMaxHeight) &&
+          nodeHeight > node->mCssStyle->mMaxHeight) {
+        heightRemeasure = true;
+        nodeHeight = node->mCssStyle->mMaxHeight;
+      }
+
+      node->setWidthMeasureMode(widthRemeasure ? kExactly : node->widthMeasureMode);
+      node->setHeightMeasureMode(heightRemeasure ? kExactly : node->heightMeasureMode);
+
+      if (hypotheticalMeasurment) {
+        if (widthRemeasure) {
+          node->setLayoutWidth(nodeWidth);
+          node->mLayoutResult->mLayoutSize.hypotheticalWidth = nodeWidth;
+        }
+        if (heightRemeasure) {
+          node->setLayoutHeight(nodeHeight);
+          node->mLayoutResult->mLayoutSize.hypotheticalHeight = nodeHeight;
+        }
+      } else {
+        if (widthRemeasure || heightRemeasure) {
+          node->measure(nodeWidth, nodeHeight, hypotheticalMeasurment);
+        }
+      }
+    }
+
+    Index WXCoreLayoutNode::expandItemsInFlexLine(WXCoreFlexLine* const flexLine,
+                                      const float maxMainSize,
+                                      const Index startIndex) {
+      Index childIndex = startIndex;
+      if (flexLine->mTotalFlexGrow <= 0) {
+        childIndex += flexLine->mItemCount;
+      } else {
+        bool needsReexpand = false;
+        const float unitSpace = (maxMainSize - flexLine->mMainSize + flexLine->mTotalFlexibleSize) /
+                                (flexLine->mTotalFlexGrow > 1 ? flexLine->mTotalFlexGrow : 1);
+        float sizeBeforeExpand = flexLine->mMainSize;
+        flexLine->mMainSize = 0;
+
+        for (Index i = 0; i < flexLine->mItemCount; i++) {
+          WXCoreLayoutNode *child = getChildAt(kNonBFC, childIndex);
+          if (!mChildrenFrozen[childIndex]) {
+            float childSizeAlongMainAxis = unitSpace * child->mCssStyle->mFlexGrow;
+            std::pair<bool, float> limitSize = limitChildMainSize(flexLine, child,
+                                                                childSizeAlongMainAxis, childIndex);
+            needsReexpand = limitSize.first;
+            adjustChildSize(child, limitSize.second);
+          }
+          flexLine->mMainSize += calcItemSizeAlongAxis(child, isMainAxisHorizontal(this));
+          childIndex++;
+        }
+
+        if (needsReexpand && sizeBeforeExpand != flexLine->mMainSize) {
+          // Re-invoke the method with the same startIndex to distribute the positive free space
+          // that wasn't fully distributed (because of maximum/minimum length constraint)
+          expandItemsInFlexLine(flexLine, maxMainSize, startIndex);
+        }
+      }
+      return childIndex;
+    }
+
+    void WXCoreLayoutNode::adjustChildSize(WXCoreLayoutNode* const child, const float childMainSize) {
+      if (isMainAxisHorizontal(this)) {
+        child->setWidthMeasureMode(kExactly);
+        child->setLayoutWidth(childMainSize);
+      } else {
+        child->setHeightMeasureMode(kExactly);
+        child->setLayoutHeight(childMainSize);
+      }
+    }
+
+    void WXCoreLayoutNode::stretchViewCrossSize(){
+      if (mCssStyle->mAlignItems == kAlignItemsStretch) {
+        Index viewIndex = 0;
+        for (Index i = 0; i< mFlexLines.size(); i++ ) {
+            WXCoreFlexLine *flexLine = mFlexLines.at(i);
+            for (Index j = 0; j < flexLine->mItemCount; j++, viewIndex++) {
+                WXCoreLayoutNode* child = getChildAt(kNonBFC, viewIndex);
+              if (child->mCssStyle->mAlignSelf == kAlignSelfAuto ||
+                  child->mCssStyle->mAlignSelf == kAlignSelfStretch) {
+                stretchViewCrossSize(child, flexLine->mCrossSize);
+              }
+          }
+        }
+      } else {
+        for (WXCoreFlexLine *flexLine : mFlexLines) {
+          for (auto index : flexLine->mIndicesAlignSelfStretch) {
+            stretchViewCrossSize(getChildAt(kNonBFC, index), flexLine->mCrossSize);
+          }
+        }
+      }
+    }
+
+    void WXCoreLayoutNode::stretchViewCrossSize(WXCoreLayoutNode* const child, float crossSize){
+      if (isMainAxisHorizontal(this)) {
+        if (child->heightMeasureMode != kExactly) {
+            crossSize -=
+                child->mCssStyle->mMargin.getMargin(kMarginTop) +
+                    child->mCssStyle->mMargin.getMargin(kMarginBottom);
+          child->setHeightMeasureMode(kExactly);
+          child->setLayoutHeight(std::max(0.f, crossSize));
+        }
+      } else {
+        if (child->widthMeasureMode != kExactly) {
+            crossSize -=
+                child->mCssStyle->mMargin.getMargin(kMarginLeft) +
+                    child->mCssStyle->mMargin.getMargin(kMarginRight);
+          child->setWidthMeasureMode(kExactly);
+          child->setLayoutWidth(std::max(0.f, crossSize));
+        }
+      }
+    }
+
+    void WXCoreLayoutNode::setFrame(const float l, const float t, const float r, const float b) {
+      if (mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeLeft) != l
+          || mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeTop) != t
+          || mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeRight) != r
+          || mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeBottom) != b) {
+        setHasNewLayout(true);
+        setFrame(&mLayoutResult->mLayoutPosition, l, t, r, b);
+      }
+    }
+
+  void WXCoreLayoutNode::setFrame(WXCorePosition* position,const float l, const float t, const float r, const float b){
+    position->setPosition(kPositionEdgeLeft, l);
+    position->setPosition(kPositionEdgeTop, t);
+    position->setPosition(kPositionEdgeRight, r);
+    position->setPosition(kPositionEdgeBottom, b);
+  }
+
+  void WXCoreLayoutNode::layout(float left, float top, float right, float bottom, const bool absoluteFlexItem, const std::pair<float,float>* const renderPageSize) {
+    if(absoluteFlexItem) {
+      absoultePositon = new WXCorePosition();
+      setFrame(absoultePositon, left, top, right, bottom);
+    }
+    else{
+      switch (mCssStyle->mPositionType) {
+        case kFixed:
+        case kAbsolute:
+          calcAbsoluteOffset(left, top, right, bottom, renderPageSize);
+          break;
+        default:
+        case kRelative:
+          calcRelativeOffset(left, top, right, bottom);
+          break;
+      }
+      setFrame(left, top, right, bottom);
+      onLayout(left, top, right, bottom);
+    }
+  }
+
+  void WXCoreLayoutNode::calcRelativeOffset(float &left, float &top, float &right, float &bottom) const {
+    if (!isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft))) {
+      left += mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft);
+      right += mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft);
+    } else if (!isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeRight))) {
+      left -= mCssStyle->mStylePosition.getPosition(kPositionEdgeRight);
+      right -= mCssStyle->mStylePosition.getPosition(kPositionEdgeRight);
+    }
+
+    if (!isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeTop))) {
+      top += mCssStyle->mStylePosition.getPosition(kPositionEdgeTop);
+      bottom += mCssStyle->mStylePosition.getPosition(kPositionEdgeTop);
+    } else if (!isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom))) {
+      top -= mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom);
+      bottom -= mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom);
+    }
+  }
+
+  void WXCoreLayoutNode::calcAbsoluteOffset(float &left, float &top, float &right, float &bottom, const std::pair<float,float>* const renderPageSize){
+    WXCorePadding parentPadding;
+    WXCoreBorderWidth parentBorder;
+    WXCoreSize parentSize;
+    if (mCssStyle->mPositionType == kAbsolute && mParent != nullptr) {
+      parentPadding = mParent->mCssStyle->mPadding;
+      parentBorder = mParent->mCssStyle->mBorderWidth;
+      parentSize = mParent->mLayoutResult->mLayoutSize;
+      positionAbsoluteFlexItem(left, top, right, bottom);
+    } else if(mCssStyle->mPositionType == kFixed && renderPageSize!= nullptr){
+      parentSize.width = renderPageSize->first;
+      parentSize.height = renderPageSize->second;
+    }
+    updateLeftRightForAbsolute(left, right, parentPadding, parentBorder, parentSize);
+    updateTopBottomForAbsolute(top, bottom, parentPadding, parentBorder, parentSize);
+  }
+
+  void WXCoreLayoutNode::positionAbsoluteFlexItem(float &left, float &top, float &right, float &bottom){
+    if ((isnan(getStylePositionLeft()) && isnan(getStylePositionRight())) ||
+        (isnan(getStylePositionTop()) && isnan(getStylePositionBottom()))) {
+      WXCoreFlexLine tempLine;
+      mParent->updateFlexLineForAbsoluteItem(this, &tempLine);
+      mParent->onLayout(mParent->getLayoutPositionLeft(),
+                        mParent->getLayoutPositionTop(),
+                        mParent->getLayoutPositionRight(),
+                        mParent->getLayoutPositionBottom(),
+                        this, &tempLine);
+      if(absoultePositon != nullptr) {
+        if (isnan(getStylePositionLeft()) && isnan(getStylePositionRight())) {
+          left = absoultePositon->getPosition(kPositionEdgeLeft);
+          right = absoultePositon->getPosition(kPositionEdgeRight);
+        }
+        if (isnan(getStylePositionTop()) && isnan(getStylePositionBottom())) {
+          top = absoultePositon->getPosition(kPositionEdgeTop);
+          bottom = absoultePositon->getPosition(kPositionEdgeBottom);
+        }
+        delete absoultePositon;
+        absoultePositon = nullptr;
+      }
+    }
+  }
+
+  void WXCoreLayoutNode::updateFlexLineForAbsoluteItem(WXCoreLayoutNode *const absoluteFlexItem, WXCoreFlexLine *const flexLine){
+    flexLine->mMainSize = isMainAxisHorizontal(this) ?
+                         absoluteFlexItem->getLayoutWidth() + absoluteFlexItem->getMarginLeft()
+                             + absoluteFlexItem->getMarginRight() :
+                         absoluteFlexItem->getLayoutHeight() + absoluteFlexItem->getMarginTop()
+                             + absoluteFlexItem->getMarginBottom();
+    flexLine->mCrossSize = isMainAxisHorizontal(this) ?
+                          absoluteFlexItem->getLayoutHeight() + absoluteFlexItem->getMarginTop()
+                              + absoluteFlexItem->getMarginBottom() :
+                          absoluteFlexItem->getLayoutWidth() + absoluteFlexItem->getMarginLeft()
+                              + absoluteFlexItem->getMarginRight();
+    flexLine->mItemCount = 1;
+  }
+
+  void WXCoreLayoutNode::onLayout(const float left, const float top, const float right, const float bottom,
+                                  WXCoreLayoutNode *const absoulteItem, WXCoreFlexLine *const flexLine) {
+    switch (mCssStyle->mFlexDirection) {
+      case kFlexDirectionRow:
+        layoutHorizontal(false, left, top, right, bottom, absoulteItem, flexLine);
+        break;
+      case kFlexDirectionRowReverse:
+        layoutHorizontal(true, left, top, right, bottom, absoulteItem, flexLine);
+        break;
+      case kFlexDirectionColumnReverse:
+        layoutVertical(mCssStyle->mFlexWrap == kWrapReverse, true, left, top, right, bottom, absoulteItem, flexLine);
+        break;
+      case kFlexDirectionColumn:
+      default:
+        layoutVertical(mCssStyle->mFlexWrap == kWrapReverse, false, left, top, right, bottom, absoulteItem, flexLine);
+        break;
+    }
+  }
+
+  /**
+   * Sub method for {@link WXCoreLayoutNode #onLayout(int, int, int, int)} when the
+   * {@link #mFlexDirection} is either {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row} or
+   * {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row_REVERSE}.
+   *
+   * @param isRtl  {@code true} if the horizontal layout direction is mStyleRight to mStyleLeft, {@code
+   *               false} otherwise.
+   * @param left   the mStyleLeft position of this View
+   * @param top    the mStyleTop position of this View
+   * @param right  the mStyleRight position of this View
+   * @param bottom the mStyleBottom position of this View
+   */
+  void WXCoreLayoutNode::layoutHorizontal(const bool isRtl,
+                                          const float left, const float top,
+                                          const float right, const float bottom,
+                                          WXCoreLayoutNode *const absoulteItem,
+                                          WXCoreFlexLine *const flexLine) {
+    Index currentViewIndex = 0;
+    float height = bottom - top;
+    float width = right - left;
+
+    // childBottom is used if the mFlexWrap is FLEX_WRAP_WRAP_REVERSE otherwise
+    // childTop is used to align the vertical position of the children views.
+    float childBottom = height - getPaddingBottom() - getBorderWidthBottom();
+    float childTop = getPaddingTop() + getBorderWidthTop();
+
+    // Used only for RTL layout
+    // Use float to reduce the round error that may happen in when justifyContent ==
+    // SPACE_BETWEEN or SPACE_AROUND
+    float childLeft, childRight;
+    const std::vector<WXCoreFlexLine*> &lines = (flexLine == nullptr? mFlexLines: std::vector<WXCoreFlexLine*>{flexLine});
+
+    for (WXCoreFlexLine *flexLine: lines) {
+      float spaceBetweenItem = 0.f;
+      layoutFlexlineHorizontal(width, flexLine, childLeft, childRight, spaceBetweenItem);
+      spaceBetweenItem = std::max(spaceBetweenItem, 0.f);
+
+      if(absoulteItem == nullptr) {
+        for (Index j = 0; j < flexLine->mItemCount; j++) {
+          WXCoreLayoutNode *child = getChildAt(kNonBFC, currentViewIndex);
+          if (child == nullptr) {
+            continue;
+          }
+          layoutSingleChildHorizontal(isRtl, false, childBottom, childTop,
+                                     flexLine, child, childLeft, childRight);
+          childLeft += child->mLayoutResult->mLayoutSize.width + spaceBetweenItem + child->getMarginRight();
+          childRight -= child->mLayoutResult->mLayoutSize.width + spaceBetweenItem + child->getMarginLeft();
+          currentViewIndex++;
+        }
+        childTop += flexLine->mCrossSize;
+        childBottom -= flexLine->mCrossSize;
+      }
+      else{
+        layoutSingleChildHorizontal(isRtl, true, childBottom, childTop,
+                                   flexLine, absoulteItem, childLeft, childRight);
+      }
+    }
+  }
+
+  void WXCoreLayoutNode::layoutFlexlineHorizontal(const float width,
+                              const WXCoreFlexLine *const flexLine,
+                              float &childLeft,
+                              float &childRight,
+                              float &spaceBetweenItem) const {
+    Index visibleCount, visibleItem;
+    float denominator;
+    switch (mCssStyle->mJustifyContent) {
+      case kJustifyFlexEnd:
+        childLeft = width - flexLine->mMainSize - getPaddingRight() - getBorderWidthRight();
+        childRight = width - getPaddingLeft() - getBorderWidthLeft();
+        break;
+      case kJustifyCenter:
+        childLeft = (width - flexLine->mMainSize - mCssStyle->sumPaddingBorderOfEdge(kRight)
+            + mCssStyle->sumPaddingBorderOfEdge(kLeft)) / 2;
+        childRight = childLeft + flexLine->mMainSize;
+        break;
+      case kJustifySpaceAround:
+        visibleCount = flexLine->mItemCount;
+        if (visibleCount != 0) {
+          spaceBetweenItem =
+              (width - flexLine->mMainSize - sumPaddingBorderAlongAxis(this, true)) / visibleCount;
+        }
+        childLeft = getPaddingLeft() + getBorderWidthLeft() + spaceBetweenItem / 2.f;
+        childRight = width - getPaddingRight() - getBorderWidthRight() - spaceBetweenItem / 2.f;
+        break;
+      case kJustifySpaceBetween:
+        childLeft = getPaddingLeft() + getBorderWidthLeft();
+        visibleItem = flexLine->mItemCount;
+        denominator = visibleItem != 1 ? visibleItem - 1 : 1.f;
+        spaceBetweenItem =
+            (width - flexLine->mMainSize - sumPaddingBorderAlongAxis(this, true)) / denominator;
+        childRight = width - getPaddingRight() - getBorderWidthRight();
+        break;
+      case kJustifyFlexStart:
+      default:
+        childLeft = getPaddingLeft() + getBorderWidthLeft();
+        childRight = width - getPaddingRight() - getBorderWidthRight();
+        break;
+    }
+  }
+
+  void WXCoreLayoutNode::layoutSingleChildHorizontal(const bool isRtl, const bool absoulteItem,
+                                                  float childBottom, float childTop,
+                                                  WXCoreFlexLine *const flexLine,
+                                                  WXCoreLayoutNode *const child,
+                                                  float &childLeft, float &childRight) {
+    childLeft += child->getMarginLeft();
+    childRight -= child->getMarginRight();
+    if (mCssStyle->mFlexWrap == kWrapReverse) {
+      if (isRtl) {
+        layoutSingleChildHorizontal(child,
+                                    flexLine,
+                                    mCssStyle->mFlexWrap,
+                                    mCssStyle->mAlignItems,
+                                    childRight - child->mLayoutResult->mLayoutSize.width,
+                                    childBottom - child->mLayoutResult->mLayoutSize.height,
+                                    childRight,
+                                    childBottom,
+                                    absoulteItem);
+      } else {
+        layoutSingleChildHorizontal(child,
+                                    flexLine,
+                                    mCssStyle->mFlexWrap,
+                                    mCssStyle->mAlignItems,
+                                    childLeft,
+                                    childBottom - child->mLayoutResult->mLayoutSize.height,
+                                    childLeft + child->mLayoutResult->mLayoutSize.width,
+                                    childBottom,
+                                    absoulteItem);
+      }
+    } else {
+      if (isRtl) {
+        layoutSingleChildHorizontal(child, flexLine, mCssStyle->mFlexWrap, mCssStyle->mAlignItems,
+                                    childRight - child->mLayoutResult->mLayoutSize.width, childTop,
+                                    childRight, childTop + child->mLayoutResult->mLayoutSize.height,
+                                    absoulteItem);
+      } else {
+        layoutSingleChildHorizontal(child, flexLine, mCssStyle->mFlexWrap, mCssStyle->mAlignItems,
+                                    childLeft, childTop,
+                                    childLeft + child->mLayoutResult->mLayoutSize.width,
+                                    childTop + child->mLayoutResult->mLayoutSize.height,
+                                    absoulteItem);
+      }
+    }
+  }
+
+  /**
+   * Place a single View when the layout direction is horizontal ({@link #mFlexDirection} is
+   * either {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row} or
+   * {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row_REVERSE}).
+   *
+   * @param node       the View to be placed
+   * @param flexLine   the {@link WXCoreFlexLine} where the View belongs to
+   * @param flexWrap   the flex wrap attribute of this BasicLayoutNode
+   * @param alignItems the align items attribute of this BasicLayoutNode
+   * @param left       the mStyleLeft position of the View, which the View's margin is already taken
+   *                   into account
+   * @param top        the mStyleTop position of the flex line where the View belongs to. The actual
+   *                   View's mStyleTop position is shifted depending on the flexWrap and alignItems
+   *                   attributes
+   * @param right      the mStyleRight position of the View, which the View's margin is already taken
+   *                   into account
+   * @param bottom     the mStyleBottom position of the flex line where the View belongs to. The actual
+   *                   View's mStyleBottom position is shifted depending on the flexWrap and alignItems
+   *                   attributes
+   */
+  void WXCoreLayoutNode::layoutSingleChildHorizontal(WXCoreLayoutNode *const node, WXCoreFlexLine* const flexLine,
+                                                     const WXCoreFlexWrap flexWrap, WXCoreAlignItems alignItems,
+                                                     const float left, const float top, const float right, const float bottom, const bool absoluteFlexItem) {
+    if (node->mCssStyle->mAlignSelf != kAlignSelfAuto) {
+      // Expecting the values for alignItems and alignSelf match except for ALIGN_SELF_AUTO.
+      // Assigning the alignSelf value as alignItems should work.
+      alignItems = static_cast<WXCoreAlignItems>(node->mCssStyle->mAlignSelf);
+    }
+
+    float crossSize = flexLine->mCrossSize;
+
+    switch (alignItems) {
+      case kAlignItemsFlexStart:
+      case kAlignItemsStretch:
+        if (flexWrap != kWrapReverse) {
+          node->layout(left, top + node->getMarginTop(), right, bottom + node->getMarginTop(), absoluteFlexItem);
+        } else {
+          node->layout(left, top - node->getMarginBottom(), right, bottom - node->getMarginBottom(), absoluteFlexItem);
+        }
+        break;
+      case kAlignItemsFlexEnd:
+        if (flexWrap != kWrapReverse) {
+          node->layout(left,
+                       top + crossSize - node->mLayoutResult->mLayoutSize.height - node->getMarginBottom(),
+                       right, top + crossSize - node->getMarginBottom(), absoluteFlexItem);
+        } else {
+          // If the flexWrap == FLEX_WRAP_WRAP_REVERSE, the direction of the
+          // flexEnd is flipped (from mStyleTop to mStyleBottom).
+          node->layout(left, top - crossSize + node->mLayoutResult->mLayoutSize.height + node->getMarginTop(),
+                       right, bottom - crossSize + node->mLayoutResult->mLayoutSize.height + node->getMarginTop(), absoluteFlexItem);
+        }
+        break;
+      case kAlignItemsCenter:
+        float topFromCrossAxis = (crossSize - node->mLayoutResult->mLayoutSize.height
+                                  + node->getMarginTop() - node->getMarginBottom()) / 2;
+        if (flexWrap != kWrapReverse) {
+          node->layout(left, top + topFromCrossAxis,
+                       right, top + topFromCrossAxis + node->mLayoutResult->mLayoutSize.height, absoluteFlexItem);
+        } else {
+          node->layout(left, top - topFromCrossAxis,
+                       right, top - topFromCrossAxis + node->mLayoutResult->mLayoutSize.height, absoluteFlexItem);
+        }
+        break;
+    }
+  }
+
+  /**
+   * Sub method for {@link WXCoreLayoutNode #onLayout(int, int, int, int)} when the
+   * {@link #mFlexDirection} is either {@link WXCoreFlexDirection #WXCore_Flex_Direction_Column} or
+   * {@link WXCoreFlexDirection #WXCore_Flex_Direction_Column_Reverse}.
+   *
+   * @param isRtl           {@code true} if the horizontal layout direction is mStyleRight to mStyleLeft,
+   *                        {@code false}
+   *                        otherwise
+   * @param fromBottomToTop {@code true} if the layout direction is mStyleBottom to mStyleTop, {@code false}
+   *                        otherwise
+   * @param left            the mStyleLeft position of this View
+   * @param top             the mStyleTop position of this View
+   * @param right           the mStyleRight position of this View
+   * @param bottom          the mStyleBottom position of this View
+   */
+  void
+  WXCoreLayoutNode::layoutVertical(const bool isRtl,
+                                   const bool fromBottomToTop,
+                                   const float left, const float top,
+                                   const float right, const float bottom,
+                                   WXCoreLayoutNode *const absoulteItem,
+                                   WXCoreFlexLine *const flexLine) {
+    float childLeft = getPaddingLeft() + getBorderWidthLeft();
+    Index currentViewIndex = 0;
+    float width = right - left;
+    float height = bottom - top;
+
+    // childRight is used if the mFlexWrap is FLEX_WRAP_WRAP_REVERSE otherwise
+    // childLeft is used to align the horizontal position of the children views.
+    float childRight = width - getPaddingRight() - getBorderWidthRight();
+
+    // Use float to reduce the round error that may happen in when justifyContent ==
+    // SPACE_BETWEEN or SPACE_AROUND
+    float childTop, childBottom;
+    const std::vector<WXCoreFlexLine*> &lines = (flexLine == nullptr? mFlexLines: std::vector<WXCoreFlexLine*>{flexLine});
+
+    for (WXCoreFlexLine *flexLine : lines) {
+      float spaceBetweenItem = 0.f;
+      layoutFlexlineVertical(height, flexLine, childTop, childBottom, spaceBetweenItem);
+      spaceBetweenItem = std::max(spaceBetweenItem, 0.f);
+      if(absoulteItem == nullptr) {
+        for (Index j = 0; j < flexLine->mItemCount; j++) {
+          WXCoreLayoutNode *child = getChildAt(kNonBFC, currentViewIndex);
+          if (child == nullptr) {
+            continue;
+          }
+          layoutSingleChildVertical(isRtl, fromBottomToTop, false,
+                                    childLeft, childRight, flexLine,
+                                    child, childTop, childBottom);
+          childTop += child->mLayoutResult->mLayoutSize.height + spaceBetweenItem + child->getMarginBottom();
+          childBottom -= child->mLayoutResult->mLayoutSize.height + spaceBetweenItem + child->getMarginTop();
+          currentViewIndex++;
+        }
+        childLeft += flexLine->mCrossSize;
+        childRight -= flexLine->mCrossSize;
+      }
+      else{
+        layoutSingleChildVertical(isRtl, fromBottomToTop, true,
+                                  childLeft, childRight, flexLine,
+                                  absoulteItem, childTop, childBottom);
+      }
+    }
+  }
+
+  void WXCoreLayoutNode::layoutFlexlineVertical(const float height,
+                            const WXCoreFlexLine *const flexLine,
+                            float &childTop,
+                            float &childBottom,
+                            float &spaceBetweenItem) const {
+    Index visibleCount, visibleItem;
+    float denominator;
+    switch (mCssStyle->mJustifyContent) {
+      case kJustifyFlexEnd:
+        childTop = height - flexLine->mMainSize - getPaddingBottom() - getBorderWidthBottom();
+        childBottom = height - getPaddingTop() - getBorderWidthTop();
+        break;
+      case kJustifyCenter:
+        childTop = (height - flexLine->mMainSize - mCssStyle->sumPaddingBorderOfEdge(kBottom)
+            + mCssStyle->sumPaddingBorderOfEdge(kTop)) / 2;
+        childBottom = childTop + flexLine->mMainSize;
+        break;
+      case kJustifySpaceAround:
+        visibleCount = flexLine->mItemCount;
+        if (visibleCount != 0) {
+          spaceBetweenItem = (height - flexLine->mMainSize - sumPaddingBorderAlongAxis(this, false))
+              / visibleCount;
+        }
+        childTop = getPaddingTop() + getBorderWidthTop() + spaceBetweenItem / 2;
+        childBottom = height - getPaddingBottom() - getBorderWidthBottom() - spaceBetweenItem / 2;
+        break;
+      case kJustifySpaceBetween:
+        childTop = getPaddingTop() + getBorderWidthTop();
+        visibleItem = flexLine->mItemCount;
+        denominator = visibleItem != 1 ? visibleItem - 1 : 1.f;
+        spaceBetweenItem =
+            (height - flexLine->mMainSize - sumPaddingBorderAlongAxis(this, false)) / denominator;
+        childBottom = height - getPaddingBottom() - getBorderWidthBottom();
+        break;
+      case kJustifyFlexStart:
+      default:
+        childTop = getPaddingTop() + getBorderWidthTop();
+        childBottom = height - getPaddingBottom() - getBorderWidthBottom();
+        break;
+    }
+  }
+
+  void WXCoreLayoutNode::layoutSingleChildVertical(const bool isRtl, const bool fromBottomToTop,
+                                                   const bool absoluteFlexItem,
+                                                   const float childLeft, const float childRight,
+                                                   WXCoreFlexLine *const flexLine,
+                                                   WXCoreLayoutNode *const child,
+                                                   float &childTop, float &childBottom) {
+    childTop += child->getMarginTop();
+    childBottom -= child->getMarginBottom();
+    if (isRtl) {
+      if (fromBottomToTop) {
+        layoutSingleChildVertical(child, flexLine, true,
+                                  mCssStyle->mAlignItems,
+                                  childRight - child->mLayoutResult->mLayoutSize.width,
+                                  childBottom - child->mLayoutResult->mLayoutSize.height,
+                                  childRight, childBottom, absoluteFlexItem);
+      } else {
+        layoutSingleChildVertical(child, flexLine, true, mCssStyle->mAlignItems,
+                                  childRight - child->mLayoutResult->mLayoutSize.width, childTop,
+                                  childRight, childTop + child->mLayoutResult->mLayoutSize.height,
+                                  absoluteFlexItem);
+      }
+    } else {
+      if (fromBottomToTop) {
+        layoutSingleChildVertical(child, flexLine, false, mCssStyle->mAlignItems,
+                                  childLeft, childBottom - child->mLayoutResult->mLayoutSize.height,
+                                  childLeft + child->mLayoutResult->mLayoutSize.width, childBottom,
+                                  absoluteFlexItem);
+      } else {
+        layoutSingleChildVertical(child, flexLine, false, mCssStyle->mAlignItems,
+                                  childLeft, childTop,
+                                  childLeft + child->mLayoutResult->mLayoutSize.width,
+                                  childTop + child->mLayoutResult->mLayoutSize.height,
+                                  absoluteFlexItem);
+      }
+    }
+  }
+
+  /**
+   * Place a single View when the layout direction is vertical ({@link #mFlexDirection} is
+   * either {@link WXCoreFlexDirection #WXCore_Flex_Direction_Column} or
+   * {@link WXCoreFlexDirection #WXCore_Flex_Direction_Column_Reverse}).
+   *
+   * @param node       the View to be placed
+   * @param flexLine   the {@link FlexLine} where the View belongs to
+   * @param isRtl      {@code true} if the layout direction is mStyleRight to mStyleLeft, {@code false}
+   *                   otherwise
+   * @param alignItems the align items attribute of this BasicLayoutNode
+   * @param left       the mStyleLeft position of the flex line where the View belongs to. The actual
+   *                   View's mStyleLeft position is shifted depending on the isRtl and alignItems
+   *                   attributes
+   * @param top        the mStyleTop position of the View, which the View's margin is already taken
+   *                   into account
+   * @param right      the mStyleRight position of the flex line where the View belongs to. The actual
+   *                   View's mStyleRight position is shifted depending on the isRtl and alignItems
+   *                   attributes
+   * @param bottom     the mStyleBottom position of the View, which the View's margin is already taken
+   *                   into account
+   */
+  void WXCoreLayoutNode::layoutSingleChildVertical(WXCoreLayoutNode* const node, WXCoreFlexLine* const flexLine, const bool isRtl,
+                                                   WXCoreAlignItems alignItems, const float left, const float top, const float right,
+                                                   const float bottom, const bool absoluteFlexItem) {
+    if (node->mCssStyle->mAlignSelf != kAlignSelfAuto) {
+      // Expecting the values for alignItems and alignSelf match except for ALIGN_SELF_AUTO.
+      // Assigning the alignSelf value as alignItems should work.
+      alignItems = static_cast<WXCoreAlignItems>(node->mCssStyle->mAlignSelf);
+    }
+
+    float crossSize = flexLine->mCrossSize;
+
+    switch (alignItems) {
+      case kAlignItemsFlexStart:
+      case kAlignItemsStretch:
+        if (!isRtl) {
+          node->layout(left + node->getMarginLeft(), top, right + node->getMarginLeft(), bottom, absoluteFlexItem);
+        } else {
+          node->layout(left - node->getMarginRight(), top, right - node->getMarginRight(), bottom, absoluteFlexItem);
+        }
+        break;
+      case kAlignItemsFlexEnd:
+        if (!isRtl) {
+          node->layout(left + crossSize - node->mLayoutResult->mLayoutSize.width - node->getMarginRight(),
+                       top, right + crossSize - node->mLayoutResult->mLayoutSize.width - node->getMarginRight(),
+                       bottom, absoluteFlexItem);
+        } else {
+          // If the flexWrap == FLEX_WRAP_WRAP_REVERSE, the direction of the
+          // flexEnd is flipped (from mStyleLeft to mStyleRight).
+          node->layout(left - crossSize + node->mLayoutResult->mLayoutSize.width + node->getMarginLeft(), top,
+                       right - crossSize + node->mLayoutResult->mLayoutSize.width + node->getMarginLeft(),
+                       bottom, absoluteFlexItem);
+        }
+        break;
+      case kAlignItemsCenter:
+        float leftFromCrossAxis = (crossSize - node->mLayoutResult->mLayoutSize.width
+                                   + node->getMarginLeft()
+                                   - node->getMarginRight()) / 2.f;
+        if (!isRtl) {
+          node->layout(left + leftFromCrossAxis, top, right + leftFromCrossAxis, bottom, absoluteFlexItem);
+        } else {
+          node->layout(left - leftFromCrossAxis, top, right - leftFromCrossAxis, bottom, absoluteFlexItem);
+        }
+        break;
+    }
+  }
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h b/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h
new file mode 100644
index 0000000..498c243
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h
@@ -0,0 +1,1073 @@
+#ifdef __cplusplus
+
+#ifndef WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H
+#define WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H
+
+#include "WXCoreStyle.h"
+#include "WXCoreFlexEnum.h"
+#include <vector>
+#include <iostream>
+#include <string>
+#include <algorithm>
+
+namespace WeexCore {
+
+  class WXCoreLayoutNode;
+
+  class WXCoreFlexLine;
+
+  enum FormattingContext {
+    kBFC,
+    kNonBFC,
+  } ;
+
+  enum MeasureMode {
+    kUnspecified,
+    kExactly,
+  } ;
+
+  struct WXCoreSize {
+   private:
+    float hypotheticalWidth;
+    float hypotheticalHeight;
+   public:
+    friend class WXCoreLayoutNode;
+    float width;
+    float height;
+
+    WXCoreSize() : hypotheticalWidth(NAN),
+                   hypotheticalHeight(NAN),
+                   width(0), height(0) {}
+
+    inline void reset() {
+      hypotheticalWidth = NAN ;
+      hypotheticalHeight = NAN;
+      width = 0;
+      height = 0;
+    }
+
+    inline bool isNAN() {
+      return isnan(width) || isnan(height);
+    }
+  };
+
+  /**
+   * layout-result:layout-height、layout-width、position(left、right、top、bottom)
+   */
+  struct WXCorelayoutResult {
+    WXCoreSize mLayoutSize;
+    WXCorePosition mLayoutPosition;
+
+    inline bool isNAN() {
+      return mLayoutSize.isNAN() || mLayoutPosition.isNAN();
+    }
+
+    inline void reset() {
+      mLayoutSize.reset();
+      mLayoutPosition.reset();
+    }
+  };
+
+  typedef WXCoreSize(*WXCoreMeasureFunc)(WXCoreLayoutNode *node, float width,
+                                         MeasureMode widthMeasureMode,
+                                         float height, MeasureMode heightMeasureMode);
+
+  using Index = std::vector<WXCoreLayoutNode *>::size_type;
+
+  /**
+   * flie line
+   */
+  class WXCoreFlexLine {
+  public:
+    float mMainSize;
+
+    float mCrossSize;
+
+    Index mItemCount;
+
+    float mTotalFlexGrow;
+
+    float mTotalFlexibleSize;
+
+    /**
+     * Store the indices of the children views whose mAlignSelf property is stretch.
+     * The stored indices are the absolute indices including all children in the Flexbox,
+     * not the relative indices in this flex line.
+     */
+    std::vector<Index> mIndicesAlignSelfStretch;
+
+    WXCoreFlexLine() : mMainSize(0),
+                       mCrossSize(0),
+                       mItemCount(0),
+                       mTotalFlexGrow(0),
+                       mTotalFlexibleSize(0) {
+    }
+
+    ~WXCoreFlexLine() {
+      mMainSize = 0;
+      mCrossSize = 0;
+      mItemCount = 0;
+      mTotalFlexGrow = 0;
+      mTotalFlexibleSize = 0;
+      mIndicesAlignSelfStretch.clear();
+    }
+  };
+
+  /**
+   * Layout node
+   */
+  class WXCoreLayoutNode {
+
+  public:
+      WXCoreLayoutNode() :
+              mParent(nullptr),
+              dirty(true),
+              widthDirty{false},
+              heightDirty{false},
+              mHasNewLayout(true),
+              mIsDestroy(false),
+              measureFunc(nullptr) {
+        mCssStyle = new WXCoreCSSStyle();
+        mLayoutResult = new WXCorelayoutResult();
+      }
+
+
+      ~WXCoreLayoutNode() {
+          mIsDestroy = true;
+        mHasNewLayout = true;
+        dirty = true;
+        measureFunc = nullptr;
+        mParent = nullptr;
+        mChildList.clear();
+        BFCs.clear();
+        NonBFCs.clear();
+        mChildrenFrozen.clear();
+
+        for (WXCoreFlexLine *flexLine : mFlexLines) {
+          if (flexLine != nullptr) {
+            delete flexLine;
+            flexLine = nullptr;
+          }
+        }
+        mFlexLines.clear();
+
+        if (mCssStyle != nullptr) {
+          delete mCssStyle;
+          mCssStyle = nullptr;
+        }
+
+        if (mLayoutResult != nullptr) {
+          delete mLayoutResult;
+          mLayoutResult = nullptr;
+        }
+      }
+
+  private:
+
+    /**
+     * Holds the 'frozen' state of children during measure. If a view is frozen it will no longer
+     * expand regardless of mFlexGrow. Items are indexed by the child's
+     * reordered index.
+     */
+    std::vector<bool> mChildrenFrozen;
+
+    std::vector<WXCoreFlexLine *> mFlexLines;
+
+    std::vector<WXCoreLayoutNode *> mChildList;
+
+    std::vector<WXCoreLayoutNode *> BFCs;
+
+    std::vector<WXCoreLayoutNode *> NonBFCs;
+
+    WXCoreLayoutNode *mParent = nullptr;
+
+    WXCoreCSSStyle *mCssStyle = nullptr;
+
+    MeasureMode widthMeasureMode = kUnspecified;
+
+    MeasureMode heightMeasureMode = kUnspecified;
+
+    WXCorelayoutResult *mLayoutResult = nullptr;
+
+    WXCorePosition *absoultePositon = nullptr;
+
+    bool mHasNewLayout;
+
+    bool dirty, widthDirty, heightDirty;
+
+    bool mIsDestroy = true;
+
+    WXCoreMeasureFunc measureFunc = nullptr;
+
+    void *context;
+
+    /** ================================ Cache:Last calculate result =================================== **/
+
+  public:
+
+
+    /** ================================ Engine Entry Function =================================== **/
+
+    void calculateLayout(const std::pair<float,float>&);
+
+    /** ================================ measureFunc =================================== **/
+
+    inline void setMeasureFunc(WXCoreMeasureFunc measure) {
+      measureFunc = measure;
+      markDirty();
+    }
+
+    inline WXCoreMeasureFunc getMeasureFunc() const {
+      return measureFunc;
+    }
+
+    inline bool haveMeasureFunc() const {
+      return measureFunc != nullptr;
+    }
+
+    /** ================================ context =================================== **/
+
+
+    inline void *getContext() const {
+      return context;
+    }
+
+    inline void setContext(void * const context) {
+      this->context = context;
+    }
+
+    inline void copyStyle(WXCoreLayoutNode *srcNode) {
+      if (memcmp(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle)) != 0) {
+        memcpy(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle));
+        markDirty();
+      }
+    }
+
+    inline void copyMeasureFunc(WXCoreLayoutNode *srcNode) {
+      if (memcmp(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc)) != 0) {
+        memcpy(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc));
+        markDirty();
+      }
+    }
+
+  private:
+
+    /** ================================ measure =================================== **/
+
+    inline void reset() {
+      if (isDirty()) {
+        mLayoutResult->reset();
+        for (WXCoreFlexLine *flexLine : mFlexLines) {
+          if (flexLine != nullptr) {
+            delete flexLine;
+            flexLine = nullptr;
+          }
+        }
+        mFlexLines.clear();
+
+        mChildrenFrozen.assign(getChildCount(kNonBFC), false);
+      }
+      widthMeasureMode = isnan(mCssStyle->mStyleWidth) ? kUnspecified : kExactly;
+      heightMeasureMode = isnan(mCssStyle->mStyleHeight) ? kUnspecified : kExactly;
+    }
+
+    inline void setLayoutWidth(const float width) {
+      if (mLayoutResult->mLayoutSize.width != width &&
+          (!isnan(width) || !isnan(mLayoutResult->mLayoutSize.width))) {
+        mLayoutResult->mLayoutSize.width = width;
+        widthDirty = true;
+        markDirty(false);
+      }
+    }
+
+    inline void setLayoutHeight(const float height) {
+      if (mLayoutResult->mLayoutSize.height != height &&
+          (!isnan(height) || !isnan(mLayoutResult->mLayoutSize.height))) {
+        mLayoutResult->mLayoutSize.height = height;
+        heightDirty = true;
+        markDirty(false);
+      }
+    }
+
+    inline void setWidthMeasureMode(const MeasureMode measureMode) {
+      if (widthMeasureMode != measureMode) {
+        widthMeasureMode = measureMode;
+        if (getChildCount(kNonBFC) > 0) {
+          widthDirty = true;
+        }
+      }
+    }
+
+    inline void setHeightMeasureMode(const MeasureMode measureMode) {
+      if (heightMeasureMode != measureMode) {
+        heightMeasureMode = measureMode;
+        if (getChildCount(kNonBFC) > 0) {
+          heightDirty = true;
+        }
+      }
+    }
+
+    inline float firstLineCrossSize() const {
+      float sum = sumPaddingBorderAlongAxis(this, !isMainAxisHorizontal(this));
+      if (!mFlexLines.empty()) {
+        sum += mFlexLines[0]->mCrossSize;
+      }
+      return sum;
+    }
+
+    inline float getSumOfCrossSize() const {
+      float sum = sumPaddingBorderAlongAxis(this, !isMainAxisHorizontal(this));
+      for (WXCoreFlexLine *flexLine: mFlexLines) {
+        sum += flexLine->mCrossSize;
+      }
+      return sum;
+    }
+
+    inline bool isMainAxisHorizontal(const WXCoreLayoutNode* const node) const {
+      return node->mCssStyle->mFlexDirection == kFlexDirectionRow ||
+             node->mCssStyle->mFlexDirection == kFlexDirectionRowReverse;
+    }
+
+    inline bool isCrossExactly() const {
+      return isMainAxisHorizontal(this) ? heightMeasureMode == kExactly
+                                        : widthMeasureMode == kExactly;
+    }
+
+    inline float sumPaddingBorderAlongAxis(const WXCoreLayoutNode* const node, bool horizontal) const {
+      float paddingBorderAlongAxis;
+      if (horizontal) {
+        paddingBorderAlongAxis =
+            node->mCssStyle->mPadding.getPadding(kPaddingLeft) +
+            node->mCssStyle->mPadding.getPadding(kPaddingRight) +
+            node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthLeft) +
+            node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthRight);
+      } else {
+        paddingBorderAlongAxis =
+            node->mCssStyle->mPadding.getPadding(kPaddingTop) +
+            node->mCssStyle->mPadding.getPadding(kPaddingBottom) +
+            node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthTop) +
+            node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthBottom);
+      }
+      return paddingBorderAlongAxis;
+    }
+
+    inline bool isWrapRequired(const float &width, const float &height,
+                               const float &currentLength, const float &childLength) const {
+      float freeMainSize = calcFreeSpaceAlongMainAxis(width, height, currentLength);
+      return !isSingleFlexLine(freeMainSize) && freeMainSize < childLength;
+    }
+
+    //If width/height is NAN, ret is NAN, which property we use on purpose.
+    virtual float calcFreeSpaceAlongMainAxis(const float &width, const float &height, const float &currentLength) const{
+      float ret;
+      if(isMainAxisHorizontal(this)){
+        ret = width - sumPaddingBorderAlongAxis(this, true) - currentLength;
+      }
+      else{
+        ret = height - sumPaddingBorderAlongAxis(this, false) - currentLength;
+      }
+      return ret;
+    }
+
+    inline bool isSingleFlexLine(const float &mainSize) const {
+      return mCssStyle->mFlexWrap == kNoWrap || isnan(mainSize);
+    }
+
+    inline void sumFlexGrow(const WXCoreLayoutNode* const child, WXCoreFlexLine* const flexLine, Index i){
+      if (child->mCssStyle->mFlexGrow > 0) {
+        flexLine->mTotalFlexGrow += child->mCssStyle->mFlexGrow;
+        mChildrenFrozen[i] = false;
+        if (isMainAxisHorizontal(this)) {
+          if (!isnan(child->mLayoutResult->mLayoutSize.hypotheticalWidth)) {
+            flexLine->mTotalFlexibleSize += child->mLayoutResult->mLayoutSize.hypotheticalWidth;
+          }
+        } else {
+          if (!isnan(child->mLayoutResult->mLayoutSize.hypotheticalHeight)) {
+            flexLine->mTotalFlexibleSize += child->mLayoutResult->mLayoutSize.hypotheticalHeight;
+          }
+        }
+      } else {
+        mChildrenFrozen[i] = true;
+      }
+    }
+
+    inline void setMeasuredDimensionForFlex(
+        const float width, const MeasureMode widthMeasureMode,
+        const float height, const MeasureMode heightMeasureMode){
+      float actualWidth, actualHeight;
+      if (isMainAxisHorizontal(this)) {
+        actualWidth = widthMeasureMode == kExactly ? width : getLargestMainSize();
+        actualHeight = heightMeasureMode == kExactly ? height : getSumOfCrossSize();
+      } else {
+        actualHeight = heightMeasureMode == kExactly ? height : getLargestMainSize();
+        actualWidth = widthMeasureMode == kExactly ? width : firstLineCrossSize();
+      }
+      setMeasuredDimension(actualWidth, actualHeight);
+    }
+
+    inline float calcItemSizeAlongAxis(const WXCoreLayoutNode* const node, const bool horizontal, const bool useHypotheticalSize = false) const {
+      float ret;
+      if (horizontal) {
+        ret = node->mCssStyle->mMargin.getMargin(kMarginLeft) +
+            node->mCssStyle->mMargin.getMargin(kMarginRight);
+        ret += useHypotheticalSize ? node->mLayoutResult->mLayoutSize.hypotheticalWidth
+                                   : node->mLayoutResult->mLayoutSize.width;
+      } else {
+        ret = node->mCssStyle->mMargin.getMargin(kMarginTop) +
+            node->mCssStyle->mMargin.getMargin(kMarginBottom);
+        ret += useHypotheticalSize ? node->mLayoutResult->mLayoutSize.hypotheticalHeight
+                                   : node->mLayoutResult->mLayoutSize.height;
+      }
+      return ret;
+    }
+
+    inline void limitMainSizeForFlexGrow(WXCoreFlexLine* const flexLine, const Index childIndex,
+                                  const float flexGrow) {
+      mChildrenFrozen[childIndex] = true;
+      flexLine->mTotalFlexGrow -= flexGrow;
+    }
+
+    inline void setMeasuredDimension(const float width, const float height) {
+      mLayoutResult->mLayoutSize.width = width;
+      mLayoutResult->mLayoutSize.height = height;
+    }
+
+    inline std::pair<bool, float> limitChildMainSize(WXCoreFlexLine* const flexLine, const WXCoreLayoutNode* const child,
+                                                                       float childSizeAlongMainAxis, const Index childIndex){
+      bool needsReexpand = false;
+      if (isMainAxisHorizontal(this)) {
+        if (!isnan(child->mCssStyle->mMaxWidth) &&
+            childSizeAlongMainAxis > child->mCssStyle->mMaxWidth) {
+          needsReexpand = true;
+          childSizeAlongMainAxis = child->mCssStyle->mMaxWidth;
+        } else if (!isnan(child->mCssStyle->mMinWidth) &&
+            childSizeAlongMainAxis < child->mCssStyle->mMinWidth) {
+          needsReexpand = true;
+          childSizeAlongMainAxis = child->mCssStyle->mMinWidth;
+        }
+      } else {
+        if (!isnan(child->mCssStyle->mMaxHeight) &&
+            childSizeAlongMainAxis > child->mCssStyle->mMaxHeight) {
+          needsReexpand = true;
+          childSizeAlongMainAxis = child->mCssStyle->mMaxHeight;
+        } else if (!isnan(child->mCssStyle->mMinHeight) &&
+            childSizeAlongMainAxis < child->mCssStyle->mMinHeight) {
+          needsReexpand = true;
+          childSizeAlongMainAxis = child->mCssStyle->mMinHeight;
+        }
+      }
+      limitMainSizeForFlexGrow(flexLine, childIndex, child->mCssStyle->mFlexGrow);
+      return std::make_pair(needsReexpand, childSizeAlongMainAxis);
+    }
+
+    void updateLeftRightForAbsolute(float &left, float &right,
+                                    const WXCorePadding &parentPadding,
+                                    const WXCoreBorderWidth &parentBorder,
+                                    const WXCoreSize &parentSize) const {
+      if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft))) {
+        if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeRight))) {
+          ;
+        } else {
+          right += parentSize.width -
+              (parentBorder.getBorderWidth(kBorderWidthRight) +
+                  mCssStyle->mStylePosition.getPosition(kPositionEdgeRight)
+                  + mLayoutResult->mLayoutSize.width);
+          left += parentSize.width -
+              (parentBorder.getBorderWidth(kBorderWidthRight) +
+                  mCssStyle->mStylePosition.getPosition(kPositionEdgeRight)
+                  + mLayoutResult->mLayoutSize.width);
+        }
+      } else {
+        left += parentBorder.getBorderWidth(kBorderWidthLeft) +
+            mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft);
+        right += parentBorder.getBorderWidth(kBorderWidthLeft) +
+            mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft);
+      }
+    }
+
+    void updateTopBottomForAbsolute(float &top, float &bottom,
+                                    const WXCorePadding &parentPadding,
+                                    const WXCoreBorderWidth &parentBorder,
+                                    const WXCoreSize &parentSize) const {
+      if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeTop))) {
+        if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom))) {
+          ;
+        } else {
+          top += parentSize.height -
+              (parentBorder.getBorderWidth(kBorderWidthBottom) +
+                  mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom)
+                  + mLayoutResult->mLayoutSize.height);
+          bottom += parentSize.height -
+              (parentBorder.getBorderWidth(kBorderWidthBottom) +
+                  mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom)
+                  + mLayoutResult->mLayoutSize.height);
+        }
+      } else {
+        top += parentBorder.getBorderWidth(kBorderWidthTop) +
+            mCssStyle->mStylePosition.getPosition(kPositionEdgeTop);
+        bottom += parentBorder.getBorderWidth(kBorderWidthTop) +
+            mCssStyle->mStylePosition.getPosition(kPositionEdgeTop);
+      }
+    }
+
+    /** ================================ other =================================== **/
+
+    inline void clearDirty() {
+      dirty = false;
+      widthDirty = false;
+      heightDirty = false;
+    }
+
+    void
+    measure(float, float, bool);
+
+    void hypotheticalMeasure(float, float, bool = false);
+
+    void measureLeafNode(float, float, bool, bool);
+
+    void measureInternalNode(float, float, bool, bool);
+
+    void updateCurrentFlexline(Index, WXCoreFlexLine *, Index, const WXCoreLayoutNode *, bool);
+
+    void measureChild(WXCoreLayoutNode* , float, float, float, bool, bool);
+
+    void adjustChildSize(WXCoreLayoutNode *, float);
+
+    void adjustChildSize(const WXCoreLayoutNode *child,
+                         const float currentMainSize,
+                         const float parentWidth,
+                         const float parentHeight,
+                         float &childWidth,
+                         float &childHeight) const;
+
+    void stretchViewCrossSize();
+
+    void stretchViewCrossSize(WXCoreLayoutNode *, float);
+
+    Index expandItemsInFlexLine(WXCoreFlexLine *, float, Index);
+
+    void checkSizeConstraints(WXCoreLayoutNode *, bool);
+
+    void
+    determineMainSize(float width, float height);
+
+    void
+    determineCrossSize(float, float, bool);
+
+    void setFrame(float, float, float, float);
+
+    void setFrame(WXCorePosition*,float, float, float, float);
+
+    /** ================================ layout =================================== **/
+
+    void layout(float left, float top, float right, float bottom, bool, const std::pair<float,float>* = nullptr);
+
+    void calcRelativeOffset(float &left, float &top, float &right, float &bottom) const ;
+
+    void calcAbsoluteOffset(float &left, float &top, float &right, float &bottom, const std::pair<float,float>* = nullptr);
+
+    void positionAbsoluteFlexItem(float &left, float &top, float &right, float &bottom);
+
+    void onLayout(float left, float top, float right, float bottom, WXCoreLayoutNode* = nullptr, WXCoreFlexLine *const flexLine = nullptr);
+
+    void layoutHorizontal(bool isRtl, float left, float top, float right, float bottom,
+                          WXCoreLayoutNode*, WXCoreFlexLine *const flexLine);
+
+    void layoutFlexlineHorizontal(const float width,
+                                         const WXCoreFlexLine *const flexLine,
+                                         float &childLeft,
+                                         float &childRight,
+                                         float &spaceBetweenItem) const;
+
+    void layoutSingleChildHorizontal(WXCoreLayoutNode *node, WXCoreFlexLine *flexLine,
+                                     WXCoreFlexWrap flexWrap, WXCoreAlignItems alignItems,
+                                     float, float, float, float, bool);
+
+    void layoutSingleChildHorizontal(const bool isRtl,
+                                    const bool,
+                                    float childBottom, float childTop,
+                                    WXCoreFlexLine *const flexLine,
+                                    WXCoreLayoutNode *const child,
+                                    float&, float&);
+
+    void layoutVertical(bool isRtl, bool fromBottomToTop, float left, float top, float right, float bottom,
+                        WXCoreLayoutNode*, WXCoreFlexLine *const flexLine);
+
+    void layoutFlexlineVertical(const float height,
+                                const WXCoreFlexLine *const flexLine,
+                                float &childTop,
+                                float &childBottom,
+                                float &spaceBetweenItem) const;
+    void layoutSingleChildVertical(WXCoreLayoutNode *node, WXCoreFlexLine *flexLine,
+                                   bool isRtl, WXCoreAlignItems alignItems,
+                                   float, float, float, float, bool);
+
+    void layoutSingleChildVertical(const bool isRtl, const bool fromBottomToTop,
+                                   const bool absoluteFlexItem,
+                                   const float childLeft, const float childRight,
+                                   WXCoreFlexLine *const flexLine,
+                                   WXCoreLayoutNode *const child,
+                                   float& ,float&);
+
+    void updateFlexLineForAbsoluteItem(WXCoreLayoutNode *const absoluteFlexItem, WXCoreFlexLine *const flexLine);
+
+    void initFormatingContext(std::vector<WXCoreLayoutNode *> &BFCs);
+
+    std::pair<bool,float> calculateBFCWidth(float, float);
+
+    std::pair<bool,float> calculateBFCHeight(float, float);
+
+    std::tuple<bool, float, float> calculateBFCDimension(const std::pair<float,float>&);
+
+    virtual void onLayoutBefore() {
+
+    }
+
+    virtual void onLayoutAfter(float width, float height) {
+
+    }
+
+
+  public:
+
+    /** ================================ tree =================================== **/
+
+    inline Index getChildCount(FormattingContext formattingContext) const {
+      switch (formattingContext) {
+        case kNonBFC:
+          return NonBFCs.size();
+        case kBFC:
+          return BFCs.size();
+        default:
+          return mChildList.size();
+      }
+    }
+
+    inline Index getChildCount() const {
+      return mChildList.size();
+    }
+
+    inline std::vector<WXCoreLayoutNode *>::const_iterator ChildListIterBegin() {
+      return mChildList.cbegin();
+    }
+
+    inline std::vector<WXCoreLayoutNode *>::const_iterator ChildListIterEnd() {
+      return mChildList.cend();
+    }
+
+    inline void removeChild(const WXCoreLayoutNode* const child) {
+      for (int index = 0; index < mChildList.size(); index++) {
+        if (child == mChildList[index]) {
+          mChildList.erase(mChildList.begin() + index);
+          break;
+        }
+      }
+      markDirty();
+    }
+
+    inline void addChildAt(WXCoreLayoutNode* const child, Index index) {
+      mChildList.insert(mChildList.begin() + index, child);
+      child->mParent = this;
+      markDirty();
+    }
+
+    inline WXCoreLayoutNode *getChildAt(const FormattingContext formattingContext, const Index index) const {
+      switch (formattingContext) {
+        case kNonBFC:
+          return NonBFCs[index];
+        case kBFC:
+          return BFCs[index];
+        default:
+          return mChildList[index];
+      }
+    }
+
+    inline WXCoreLayoutNode *getChildAt(const Index index) const {
+      return mChildList[index];
+    }
+
+    inline WXCoreLayoutNode *getParent() const {
+      return mParent;
+    }
+
+    inline bool isBFC(WXCoreLayoutNode* const node) const {
+      return node->mCssStyle->mPositionType == kAbsolute || node->mCssStyle->mPositionType == kFixed;
+    }
+
+    /** ================================ margin =================================== **/
+
+    inline float getMarginTop() const {
+      return mCssStyle->mMargin.getMargin(kMarginTop);
+    }
+
+    inline float getMarginBottom() const {
+      return mCssStyle->mMargin.getMargin(kMarginBottom);
+    }
+
+    inline float getMarginLeft() const  {
+      return mCssStyle->mMargin.getMargin(kMarginLeft);
+    }
+
+    inline float getMarginRight() const {
+      return mCssStyle->mMargin.getMargin(kMarginRight);
+    }
+
+    inline void setMargin(const WXCoreMarginEdge &edge, const float margin) {
+      if (mCssStyle->mMargin.setMargin(edge, margin)) {
+        markDirty();
+      }
+    }
+
+    inline const WXCoreMargin &GetMargins() const {
+      return mCssStyle->mMargin;
+    }
+
+    /** ================================ padding =================================== **/
+
+    inline float getPaddingLeft() const {
+      return mCssStyle->mPadding.getPadding(kPaddingLeft);
+    }
+
+    inline float getPaddingRight() const {
+      return mCssStyle->mPadding.getPadding(kPaddingRight);
+    }
+
+    inline float getPaddingTop() const {
+      return mCssStyle->mPadding.getPadding(kPaddingTop);
+    }
+
+    inline float getPaddingBottom() const {
+      return mCssStyle->mPadding.getPadding(kPaddingBottom);
+    }
+
+    inline void setPadding(const WXCorePaddingEdge edge, const float padding) {
+      if (mCssStyle->mPadding.setPadding(edge, padding)) {
+        markDirty();
+      }
+    }
+
+    inline const WXCorePadding &GetPaddings() const {
+      return mCssStyle->mPadding;
+    }
+
+    /** ================================ border-width =================================== **/
+
+    inline float getBorderWidthLeft() const {
+      return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthLeft);
+    }
+
+    inline float getBorderWidthRight() const {
+      return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthRight);
+    }
+
+    inline float getBorderWidthTop() const {
+      return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthTop);
+    }
+
+    inline float getBorderWidthBottom() const {
+      return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthBottom);
+    }
+
+    inline void setBorderWidth(const WXCoreBorderWidthEdge edge, const float borderWidth) {
+      if (mCssStyle->mBorderWidth.setBorderWidth(edge, borderWidth)) {
+        markDirty();
+      }
+    }
+
+    inline const WXCoreBorderWidth &GetBorders() const {
+      return mCssStyle->mBorderWidth;
+    }
+
+    /** ================================ position-type =================================== **/
+
+    inline void setStylePositionType(const WXCorePositionType positionType) {
+      if (mCssStyle->mPositionType != positionType) {
+        mCssStyle->mPositionType = positionType;
+        markDirty();
+      }
+    }
+
+    inline WXCorePositionType getStypePositionType() const {
+      return mCssStyle->mPositionType;
+    }
+
+
+    /** ================================ position =================================== **/
+
+    inline float getStylePositionTop() const {
+      return mCssStyle->mStylePosition.getPosition(kPositionEdgeTop);
+    }
+
+    inline float getStylePositionBottom() const {
+      return mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom);
+    }
+
+    inline float getStylePositionLeft() const {
+      return mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft);
+    }
+
+    inline float getStylePositionRight() const {
+      return mCssStyle->mStylePosition.getPosition(kPositionEdgeRight);
+    }
+
+    inline void setStylePosition(const WXCorePositionEdge edge, const float positionRight) {
+      if (mCssStyle->mStylePosition.setPosition(edge, positionRight))
+        markDirty();
+    }
+
+
+    /** ================================ dimension =================================== **/
+
+    inline void setStyleWidthLevel(const DimensionLevel level) const {
+      if (mCssStyle->mStyleWidthLevel != level) {
+        mCssStyle->mStyleWidthLevel = level;
+      }
+    }
+
+    inline void setStyleHeightLevel(const DimensionLevel level) const {
+      if (mCssStyle->mStyleHeightLevel != level) {
+        mCssStyle->mStyleHeightLevel = level;
+      }
+    }
+
+    inline DimensionLevel getStyleHeightLevel() const {
+      return mCssStyle->mStyleHeightLevel;
+    }
+
+    inline DimensionLevel getStyleWidthLevel() const {
+      return mCssStyle->mStyleWidthLevel;
+    }
+
+    inline void setStyleWidth(const float width, const bool updating) {
+      if (mCssStyle->mStyleWidth != width) {
+        mCssStyle->mStyleWidth = width;
+        markDirty();
+        if(updating) {
+          markChildrenDirty(true);
+        }
+      }
+    }
+
+    inline void setStyleWidthToNAN() {
+      if (!isnan(mCssStyle->mStyleWidth)) {
+        mCssStyle->mStyleWidth = NAN;
+        markDirty();
+        markChildrenDirty(true);
+      }
+    }
+
+    inline float getStyleWidth() const {
+      return mCssStyle->mStyleWidth;
+    }
+
+    inline void setStyleHeight(const float height) {
+      if (mCssStyle->mStyleHeight != height) {
+        mCssStyle->mStyleHeight = height;
+        markDirty();
+      }
+    }
+
+    inline float getStyleHeight() const {
+      return mCssStyle->mStyleHeight;
+    }
+
+    inline void setMinWidth(const float minWidth, const bool updating) {
+      if (mCssStyle->mMinWidth != minWidth) {
+        mCssStyle->mMinWidth = minWidth;
+        markDirty();
+        if(updating) {
+          markChildrenDirty(true);
+        }
+      }
+    }
+
+    inline float getMinWidth() const {
+      return mCssStyle->mMinWidth;
+    }
+
+    inline void setMaxWidth(const float maxWidth, const bool updating) {
+      if (mCssStyle->mMaxWidth != maxWidth) {
+        mCssStyle->mMaxWidth = maxWidth;
+        markDirty();
+        if(updating) {
+          markChildrenDirty(true);
+        }
+      }
+    }
+
+    inline float getMaxWidth() const {
+      return mCssStyle->mMaxWidth;
+    }
+
+    inline void setMinHeight(const float minHeight) {
+      if (mCssStyle->mMinHeight != minHeight) {
+        mCssStyle->mMinHeight = minHeight;
+        markDirty();
+      }
+    }
+
+    inline float getMinHeight() const {
+      return mCssStyle->mMinHeight;
+    }
+
+    inline void setMaxHeight(const float maxHeight) {
+      if (mCssStyle->mMaxHeight != maxHeight) {
+        mCssStyle->mMaxHeight = maxHeight;
+        markDirty();
+      }
+    }
+
+    inline float getMaxHeight() const {
+      return mCssStyle->mMaxHeight;
+    }
+
+
+    /** ================================ flex-style =================================== **/
+
+    inline void setFlexDirection(const WXCoreFlexDirection flexDirection, const bool updating) {
+      if (mCssStyle->mFlexDirection != flexDirection) {
+        mCssStyle->mFlexDirection = flexDirection;
+        markDirty();
+        if (updating) {
+          for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
+            (*it)->markDirty(false);
+          }
+        }
+      }
+    }
+
+    inline WXCoreFlexDirection getFlexDirection() const {
+      return mCssStyle->mFlexDirection;
+    }
+
+    inline void setFlexWrap(const WXCoreFlexWrap flexWrap) {
+      if (mCssStyle->mFlexWrap != flexWrap) {
+        mCssStyle->mFlexWrap = flexWrap;
+        markDirty();
+      }
+    }
+
+    inline WXCoreFlexWrap getFlexWrap() const {
+      return mCssStyle->mFlexWrap;
+    }
+
+    inline void setJustifyContent(const WXCoreJustifyContent justifyContent) {
+      if (mCssStyle->mJustifyContent != justifyContent) {
+        mCssStyle->mJustifyContent = justifyContent;
+      }
+    }
+
+    inline WXCoreJustifyContent getJustifyContent() const {
+      return mCssStyle->mJustifyContent;
+    }
+
+    inline void setAlignItems(const WXCoreAlignItems alignItems) {
+      if (mCssStyle->mAlignItems != alignItems) {
+        mCssStyle->mAlignItems = alignItems;
+        markDirty();
+      }
+    }
+
+    inline WXCoreAlignItems getAlignItems() const {
+      return mCssStyle->mAlignItems;
+    }
+
+    inline void setAlignSelf(const WXCoreAlignSelf alignSelf) {
+      if (mCssStyle->mAlignSelf != alignSelf) {
+        mCssStyle->mAlignSelf = alignSelf;
+        markDirty();
+      }
+    }
+
+    inline WXCoreAlignSelf getAlignSelf() const {
+      return mCssStyle->mAlignSelf;
+    }
+
+    virtual void setFlex(const float flex) {
+      if (mCssStyle->mFlexGrow != flex) {
+        mCssStyle->mFlexGrow = flex;
+        markDirty();
+      }
+    }
+
+    inline float getFlex() const {
+      return mCssStyle->mFlexGrow;
+    }
+
+    /** ================================ layout-result =================================== **/
+
+    inline float getLayoutWidth() const {
+      return mLayoutResult->mLayoutSize.width;
+    }
+
+    inline float getLayoutHeight() const {
+      return mLayoutResult->mLayoutSize.height;
+    }
+
+    inline float getLayoutPositionTop() const {
+      return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeTop);
+    }
+
+    inline float getLayoutPositionBottom() const {
+      return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeBottom);
+    }
+
+    inline float getLayoutPositionLeft() const {
+      return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeLeft);
+    }
+
+    inline float getLayoutPositionRight() const  {
+      return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeRight);
+    }
+
+    inline bool hasNewLayout() const {
+      return mHasNewLayout;
+    }
+
+    inline bool isDirty() const {
+      return dirty;
+    }
+
+    inline void markDirty(const bool recursion = true) {
+      if (!isDirty()) {
+        dirty = true;
+        if (getParent() != nullptr && recursion) {
+          getParent()->markDirty();
+        }
+      }
+    }
+
+    bool markChildrenDirty(const bool updatedNode = false) {
+      bool ret = false;
+      if(getChildCount() == 0){
+        if(measureFunc!= nullptr){
+          ret = true;
+        }
+      }
+      else {
+        //isnan(mCssStyle->mStyleWidth) XOR updatedNode
+        if(isnan(mCssStyle->mStyleWidth) != updatedNode){
+          for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
+            ret = ((*it)->markChildrenDirty() || ret) ;
+          }
+        }
+      }
+      dirty = ret || dirty;
+      return ret;
+    }
+
+    inline void setHasNewLayout(const bool hasNewLayout) {
+      this->mHasNewLayout = hasNewLayout;
+    }
+
+    inline float getLargestMainSize() const {
+      float largestSize = 0;
+      for (WXCoreFlexLine *flexLine : mFlexLines) {
+        largestSize = std::max(largestSize, flexLine->mMainSize);
+      }
+      return largestSize + sumPaddingBorderAlongAxis(this, isMainAxisHorizontal(this));
+    }
+  };
+}
+#endif //WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H
+#endif


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.mm b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.mm
new file mode 100644
index 0000000..8406cfe
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.mm
@@ -0,0 +1,768 @@
+
+/*
+ * 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 "WXRecyclerComponent.h"
+#import "WXComponent_internal.h"
+#import "WXSDKInstance_private.h"
+#import "WXRecyclerDataController.h"
+#import "WXRecyclerUpdateController.h"
+#import "WXMultiColumnLayout.h"
+#import "WXHeaderComponent.h"
+#import "WXFooterComponent.h"
+#import "WXCellComponent.h"
+#import "WXAssert.h"
+#import "WXConvert.h"
+#import "WXUtility.h"
+#import "WXMonitor.h"
+#import "NSObject+WXSwizzle.h"
+#import "WXComponent+Events.h"
+#import "WXRecyclerDragController.h"
+#import "WXComponent+Layout.h"
+#import "WXScrollerComponent+Layout.h"
+
+static NSString * const kCollectionCellReuseIdentifier = @"WXRecyclerCell";
+static NSString * const kCollectionHeaderReuseIdentifier = @"WXRecyclerHeader";
+static float const kRecyclerNormalColumnGap = 32;
+
+typedef enum : NSUInteger {
+    WXRecyclerLayoutTypeMultiColumn,
+    WXRecyclerLayoutTypeFlex,
+    WXRecyclerLayoutTypeGrid,
+} WXRecyclerLayoutType;
+
+@interface WXCollectionView : UICollectionView
+
+@end
+
+@implementation WXCollectionView
+
+- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index
+{
+    [super insertSubview:view atIndex:index];
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    [self.wx_component layoutDidFinish];
+}
+
+- (void)setContentOffset:(CGPoint)contentOffset
+{
+    // FIXME: side effect caused by hooking _adjustContentOffsetIfNecessary.
+    // When UICollectionView is pulled down and finger releases,contentOffset will be set from -xxxx to about -0.5(greater than -0.5), then contentOffset will be reset to zero by calling _adjustContentOffsetIfNecessary.
+    // So hooking _adjustContentOffsetIfNecessary will always cause remaining 1px space between list's top and navigator.
+    // Demo: http://dotwe.org/895630945793a9a044e49abe39cbb77f
+    // Have to reset contentOffset to zero manually here.
+    if (fabs(contentOffset.y) < 0.5) {
+        contentOffset.y = 0;
+    }
+    if (isnan(contentOffset.x)) {
+        contentOffset.x = 0;
+    }
+    if(isnan(contentOffset.y)) {
+        contentOffset.y = 0;
+    }
+    
+    [super setContentOffset:contentOffset];
+}
+
+@end
+
+@interface WXCollectionViewCell : UICollectionViewCell
+
+@end
+
+@implementation WXCollectionViewCell
+
+- (void)prepareForReuse
+{
+    [super prepareForReuse];
+    
+    WXCellComponent *cellComponent = (WXCellComponent *)self.wx_component;
+    if (cellComponent.isRecycle && [cellComponent isViewLoaded] && [self.contentView.subviews containsObject:cellComponent.view]) {
+        [cellComponent _unloadViewWithReusing:YES];
+    }
+}
+
+@end
+
+@interface WXRecyclerComponent () <UICollectionViewDataSource, UICollectionViewDelegate, WXMultiColumnLayoutDelegate, WXRecyclerUpdateControllerDelegate, WXCellRenderDelegate, WXHeaderRenderDelegate, WXRecyclerDragControllerDelegate>
+
+@property (nonatomic, strong, readonly) WXRecyclerDataController *dataController;
+@property (nonatomic, strong, readonly) WXRecyclerUpdateController *updateController;
+@property (nonatomic, weak, readonly) UICollectionView *collectionView;
+@property (nonatomic, strong) WXRecyclerDragController *dragController;
+
+@end
+
+@implementation WXRecyclerComponent
+{
+    WXRecyclerLayoutType _layoutType;
+    UICollectionViewLayout *_collectionViewlayout;
+    
+    UIEdgeInsets _padding;
+    NSUInteger _previousLoadMoreCellNumber;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        [self _fillPadding];
+        
+        if ([type isEqualToString:@"waterfall"] || (attributes[@"layout"] && [attributes[@"layout"] isEqualToString:@"multi-column"])) {
+            // TODO: abstraction
+            _layoutType = WXRecyclerLayoutTypeMultiColumn;
+            CGFloat scaleFactor = weexInstance.pixelScaleFactor;
+            _collectionViewlayout = [WXMultiColumnLayout new];
+            WXMultiColumnLayout *layout = (WXMultiColumnLayout *)_collectionViewlayout;
+            layout.columnWidth = [WXConvert WXLength:attributes[@"columnWidth"] isFloat:YES scaleFactor:scaleFactor] ? : [WXLength lengthWithFloat:0.0 type:WXLengthTypeAuto];
+            layout.columnCount = [WXConvert WXLength:attributes[@"columnCount"] isFloat:NO scaleFactor:1.0] ? : [WXLength lengthWithInt:1 type:WXLengthTypeFixed];
+            if (attributes[@"leftGap"]) {
+                layout.leftGap = [WXConvert WXPixelType:attributes[@"leftGap"] scaleFactor:scaleFactor];
+            }
+            if (attributes[@"rightGap"]) {
+                layout.rightGap = [WXConvert WXPixelType:attributes[@"rightGap"] scaleFactor:scaleFactor];
+            }
+            layout.columnGap = [self _floatValueForColumnGap:([WXConvert WXLength:attributes[@"columnGap"] isFloat:YES scaleFactor:scaleFactor] ? : [WXLength lengthWithFloat:0.0 type:WXLengthTypeNormal])];
+            
+            layout.delegate = self;
+        } else {
+            _collectionViewlayout = [UICollectionViewLayout new];
+        }
+        
+        _dataController = [WXRecyclerDataController new];
+        _updateController = [WXRecyclerUpdateController new];
+        _updateController.delegate = self;
+        [self fixFlicker];
+        
+        if ([attributes[@"draggable"] boolValue]) {
+            // lazy load
+            _dragController = [WXRecyclerDragController new];
+            _dragController.delegate = self;
+            if([attributes[@"dragTriggerType"]  isEqual: @"pan"]){
+                _dragController.dragTriggerType = WXRecyclerDragTriggerPan;
+            }
+            _dragController.isDragable = YES;
+        }
+    }
+    
+    return self;
+}
+
+- (void)dealloc
+{
+    _collectionView.delegate = nil;
+    _collectionView.dataSource = nil;
+}
+
+#pragma mark - Public Subclass Methods
+
+- (UIView *)loadView
+{
+    return [[WXCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_collectionViewlayout];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    
+    _collectionView = (UICollectionView *)self.view;
+    _collectionView.allowsSelection = NO;
+    _collectionView.allowsMultipleSelection = NO;
+    _collectionView.dataSource = self;
+    _collectionView.delegate = self;
+    
+    [_collectionView registerClass:[WXCollectionViewCell class] forCellWithReuseIdentifier:kCollectionCellReuseIdentifier];
+    [_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:kCollectionSupplementaryViewKindHeader withReuseIdentifier:kCollectionHeaderReuseIdentifier];
+    
+    _dragController.dragingCell = [[WXCollectionViewCell alloc] initWithFrame:CGRectMake(0, 0, 100, 100/2.0f)];
+    _dragController.collectionView = _collectionView;
+    
+    [self performUpdatesWithCompletion:^(BOOL finished) {
+        
+    }];
+}
+
+- (void)viewWillUnload
+{
+    [super viewWillUnload];
+    
+    _collectionView.dataSource = nil;
+    _collectionView.delegate = nil;
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    [super updateAttributes:attributes];
+    
+    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
+        CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
+        WXMultiColumnLayout *layout = (WXMultiColumnLayout *)_collectionViewlayout;
+        BOOL needUpdateLayout = NO;
+        
+        if ([attributes[@"draggable"] boolValue]) {
+            if (!_dragController) {  // lazy load
+                _dragController = [WXRecyclerDragController new];
+                _dragController.delegate = self;
+            }
+            if([attributes[@"dragTriggerType"]  isEqual: @"pan"]){
+                _dragController.dragTriggerType = WXRecyclerDragTriggerPan;
+            }
+            _dragController.isDragable = YES;
+        } else {
+            _dragController.isDragable = NO;
+        }
+        
+        if (attributes[@"columnWidth"]) {
+            layout.columnWidth = [WXConvert WXLength:attributes[@"columnWidth"] isFloat:YES scaleFactor:scaleFactor];
+            needUpdateLayout = YES;
+        }
+        
+        if (attributes[@"columnCount"]) {
+            layout.columnCount = [WXConvert WXLength:attributes[@"columnCount"] isFloat:NO scaleFactor:1.0];
+            
+            needUpdateLayout = YES;
+        }
+        if (attributes[@"columnGap"]) {
+            layout.columnGap = [self _floatValueForColumnGap:([WXConvert WXLength:attributes[@"columnGap"] isFloat:YES scaleFactor:scaleFactor])];
+            needUpdateLayout = YES;
+        }
+        if (attributes[@"leftGap"]) {
+            layout.leftGap = [WXConvert WXPixelType:attributes[@"leftGap"] scaleFactor:scaleFactor];
+        }
+        if (attributes[@"rightGap"]) {
+            layout.rightGap = [WXConvert WXPixelType:attributes[@"rightGap"] scaleFactor:scaleFactor];
+        }
+        
+        if (needUpdateLayout) {
+            for (WXComponent *component in self.subcomponents) {
+                [component setNeedsLayout];
+            }
+            
+            [self.collectionView reloadData];
+            [self.collectionView.collectionViewLayout invalidateLayout];
+        }
+    }
+    
+}
+
+- (void)setContentSize:(CGSize)contentSize
+{
+    // Do Nothing
+}
+
+- (void)adjustSticky
+{
+    // Do Nothing, sticky is adjusted by layout
+}
+
+#pragma mark - Private Subclass Methods
+
+- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles
+{
+    [super _updateStylesOnComponentThread:styles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
+    
+    [self _fillPadding];
+}
+
+- (void)_handleFirstScreenTime
+{
+    // Do Nothing, firstScreenTime is set by cellDidRendered:
+}
+
+- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset animated:(BOOL)animated
+{
+    CGPoint contentOffset = _collectionView.contentOffset;
+    CGFloat contentOffsetY = 0;
+    
+    CGRect rect;
+    while (component) {
+        if ([component isKindOfClass:[WXCellComponent class]]) {
+            NSIndexPath *toIndexPath = [self.dataController indexPathForCell:(WXCellComponent *)component];
+            UICollectionViewLayoutAttributes *attributes = [_collectionView layoutAttributesForItemAtIndexPath:toIndexPath];
+            rect = attributes.frame;
+            break;
+        }
+        if ([component isKindOfClass:[WXHeaderComponent class]]) {
+            NSUInteger toIndex = [self.dataController indexForHeader:(WXHeaderComponent *)component];
+            UICollectionViewLayoutAttributes *attributes = [_collectionView layoutAttributesForSupplementaryElementOfKind:kCollectionSupplementaryViewKindHeader atIndexPath:[NSIndexPath indexPathWithIndex:toIndex]];
+            rect = attributes.frame;
+            break;
+        }
+        contentOffsetY += component.calculatedFrame.origin.y;
+        component = component.supercomponent;
+    }
+    
+    contentOffsetY += rect.origin.y;
+    contentOffsetY += offset * self.weexInstance.pixelScaleFactor;
+    
+    if (_collectionView.contentSize.height >= _collectionView.frame.size.height && contentOffsetY > _collectionView.contentSize.height - _collectionView.frame.size.height) {
+        contentOffset.y = _collectionView.contentSize.height - _collectionView.frame.size.height;
+    } else {
+        contentOffset.y = contentOffsetY;
+    }
+    
+    [_collectionView setContentOffset:contentOffset animated:animated];
+    
+}
+
+- (void)performUpdatesWithCompletion:(void (^)(BOOL finished))completion
+{
+    WXAssertMainThread();
+    
+    //TODO: support completion
+    
+    if (![self isViewLoaded]) {
+        completion(NO);
+    }
+    
+    NSArray *oldData = [self.dataController.sections copy];
+    NSArray *newData = [self _sectionArrayFromComponents:self.subcomponents];
+    
+    [_updateController performUpdatesWithNewData:newData oldData:oldData view:_collectionView];
+}
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    if ([subcomponent isKindOfClass:[WXCellComponent class]]) {
+        ((WXCellComponent *)subcomponent).delegate = self;
+    } else if ([subcomponent isKindOfClass:[WXHeaderComponent class]]) {
+        ((WXHeaderComponent *)subcomponent).delegate = self;
+    }
+    
+    [super _insertSubcomponent:subcomponent atIndex:index];
+    
+    if (![subcomponent isKindOfClass:[WXHeaderComponent class]]
+        && ![subcomponent isKindOfClass:[WXCellComponent class]]) {
+        return;
+    }
+    
+    WXPerformBlockOnMainThread(^{
+        [self performUpdatesWithCompletion:^(BOOL finished) {
+            
+        }];
+    });
+}
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    //Here will not insert cell/header/footer's view again
+    if (![subcomponent isKindOfClass:[WXCellComponent class]]
+        && ![subcomponent isKindOfClass:[WXHeaderComponent class]]
+        && ![subcomponent isKindOfClass:[WXFooterComponent class]]) {
+        [super insertSubview:subcomponent atIndex:index];
+    }
+}
+
+#pragma mark - WXRecyclerUpdateControllerDelegate
+
+- (void)updateController:(WXRecyclerUpdateController *)controller willPerformUpdateWithNewData:(NSArray<WXSectionDataController *> *)newData
+{
+    if (newData) {
+        [self.dataController updateData:newData];
+    }
+}
+
+- (void)updateController:(WXRecyclerUpdateController *)controller didPerformUpdateWithFinished:(BOOL)finished
+{
+    
+}
+
+#pragma mark - UICollectionViewDataSource
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
+{
+    WXLogDebug(@"section number:%li", (long)[self.dataController numberOfSections]);
+    return [self.dataController numberOfSections];
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
+{
+    NSInteger numberOfItems = [self.dataController numberOfItemsInSection:section];
+    
+    WXLogDebug(@"Number of items is %ld in section:%ld", (long)numberOfItems, (long)section);
+    
+    return numberOfItems;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"Getting cell at indexPath:%@", indexPath);
+    
+    WXCollectionViewCell *cellView = [_collectionView dequeueReusableCellWithReuseIdentifier:kCollectionCellReuseIdentifier forIndexPath:indexPath];
+    
+    UIView *contentView = [self.dataController cellForItemAtIndexPath:indexPath];
+    
+    cellView.wx_component = contentView.wx_component;
+    
+    [self.dragController goThroughAnchor:cellView.wx_component indexPath:indexPath];
+    
+    if (contentView.superview == cellView.contentView) {
+        return cellView;
+    }
+    
+    for (UIView *view in cellView.contentView.subviews) {
+        [view removeFromSuperview];
+    }
+    
+    [cellView.contentView addSubview:contentView];
+    [cellView setAccessibilityIdentifier:contentView.accessibilityIdentifier];
+    
+    return cellView;
+}
+
+- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
+{
+    UICollectionReusableView *reusableView = nil;
+    if ([kind isEqualToString:kCollectionSupplementaryViewKindHeader]) {
+        reusableView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kCollectionHeaderReuseIdentifier forIndexPath:indexPath];
+        UIView *contentView = [self.dataController viewForHeaderAtIndexPath:indexPath];
+        if (contentView.superview != reusableView) {
+            for (UIView *view in reusableView.subviews) {
+                [view removeFromSuperview];
+            }
+            
+            [reusableView addSubview:contentView];
+        }
+    }
+    
+    return reusableView;
+}
+
+#pragma mark - UICollectionViewDelegate
+
+- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"will display cell:%@, at index path:%@", cell, indexPath);
+}
+
+- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"Did end displaying cell:%@, at index path:%@", cell, indexPath);
+}
+
+#pragma mark - WXMultiColumnLayoutDelegate
+
+- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView insetForLayout:(UICollectionViewLayout *)collectionViewLayout
+{
+    return _padding;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView contentWidthForLayout:(UICollectionViewLayout *)collectionViewLayout
+{
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+    }
+//#else
+    else
+    {
+        return self.flexScrollerCSSNode->getStyleWidth();
+    }
+//#endif
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    CGSize itemSize = [self.dataController sizeForItemAtIndexPath:indexPath];
+    return itemSize.height;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForHeaderInSection:(NSInteger)section
+{
+    CGSize headerSize = [self.dataController sizeForHeaderAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
+    return headerSize.height;
+}
+
+- (BOOL)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout hasHeaderInSection:(NSInteger)section
+{
+    return [self.dataController hasHeaderInSection:section];
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout isNeedStickyForHeaderInSection:(NSInteger)section
+{
+    return [self.dataController isStickyForHeaderAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
+}
+
+#pragma mark - WXHeaderRenderDelegate
+
+- (float)headerWidthForLayout:(WXHeaderComponent *)header
+{
+    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
+        return ((WXMultiColumnLayout *)_collectionViewlayout).computedHeaderWidth;
+    }
+    
+    return 0.0;
+}
+
+- (void)headerDidLayout:(WXHeaderComponent *)header
+{
+    WXPerformBlockOnMainThread(^{
+        [self.collectionView.collectionViewLayout invalidateLayout];
+    });
+}
+
+- (void)headerDidRemove:(WXHeaderComponent *)header
+{
+    WXPerformBlockOnMainThread(^{
+        [self performUpdatesWithCompletion:^(BOOL finished) {
+            
+        }];
+    });
+}
+
+#pragma mark - WXCellRenderDelegate
+
+- (float)containerWidthForLayout:(WXCellComponent *)cell
+{
+    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
+        return ((WXMultiColumnLayout *)_collectionViewlayout).computedColumnWidth;
+    }
+    
+    return 0.0;
+}
+
+- (void)cellDidLayout:(WXCellComponent *)cell
+{
+    BOOL previousLayoutComplete = cell.isLayoutComplete;
+    cell.isLayoutComplete = YES;
+    WXPerformBlockOnMainThread(^{
+        if (previousLayoutComplete) {
+            [self.updateController reloadItemsAtIndexPath:[self.dataController indexPathForCell:cell]];
+        } else {
+            [self performUpdatesWithCompletion:^(BOOL finished) {
+            }];
+        }
+    });
+}
+
+- (void)cellDidRendered:(WXCellComponent *)cell
+{
+    if (WX_MONITOR_INSTANCE_PERF_IS_RECORDED(WXPTFirstScreenRender, self.weexInstance) && !self.weexInstance.onRenderProgress) {
+        return;
+    }
+    
+    NSIndexPath *indexPath = [self.dataController indexPathForCell:cell];
+    
+    UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath];
+    CGRect cellRect = attributes.frame;
+    if (cellRect.origin.y + cellRect.size.height >= _collectionView.frame.size.height) {
+        WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, self.weexInstance);
+    }
+    
+    if (self.weexInstance.onRenderProgress) {
+        CGRect renderRect = [_collectionView convertRect:cellRect toView:self.weexInstance.rootView];
+        self.weexInstance.onRenderProgress(renderRect);
+    }
+}
+
+- (void)cellDidRemove:(WXCellComponent *)cell
+{
+    if (cell.isLayoutComplete) {
+        WXPerformBlockOnMainThread(^{
+            [self performUpdatesWithCompletion:^(BOOL finished) {
+            }];
+        });
+    }
+}
+
+- (void)cell:(WXCellComponent *)cell didMoveToIndex:(NSUInteger)index
+{
+    if (cell.isLayoutComplete) {
+        WXPerformBlockOnMainThread(^{
+            [self performUpdatesWithCompletion:^(BOOL finished) {
+            }];
+        });
+    }
+}
+
+#pragma mark - Load More Event
+
+- (void)setLoadmoreretry:(NSUInteger)loadmoreretry
+{
+    if (loadmoreretry != self.loadmoreretry) {
+        _previousLoadMoreCellNumber = 0;
+    }
+    
+    [super setLoadmoreretry:loadmoreretry];
+}
+
+- (void)loadMore
+{
+    [super loadMore];
+    
+    _previousLoadMoreCellNumber = [self totalNumberOfCells];
+}
+
+- (BOOL)isNeedLoadMore
+{
+    BOOL superNeedLoadMore = [super isNeedLoadMore];
+    return superNeedLoadMore && _previousLoadMoreCellNumber != [self totalNumberOfCells];
+}
+
+- (NSUInteger)totalNumberOfCells
+{
+    NSUInteger cellNumber = 0;
+    NSUInteger sectionCount = [_collectionView numberOfSections];
+    for (int section = 0; section < sectionCount; section ++) {
+        cellNumber += [_collectionView numberOfItemsInSection:section];
+    }
+    
+    return cellNumber;
+}
+
+- (void)resetLoadmore{
+    [super resetLoadmore];
+    _previousLoadMoreCellNumber = 0;
+}
+
+#pragma mark - Private
+
+- (float)_floatValueForColumnGap:(WXLength *)gap
+{
+    if (gap.isNormal) {
+        return kRecyclerNormalColumnGap * self.weexInstance.pixelScaleFactor;
+    } else {
+        return gap.floatValue;
+    }
+}
+
+- (void)_fillPadding
+{
+    UIEdgeInsets padding;
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        padding = {
+            WXFloorPixelValue(self.cssNode->style.padding[CSS_TOP] + self.cssNode->style.border[CSS_TOP]),
+            WXFloorPixelValue(self.cssNode->style.padding[CSS_LEFT] + self.cssNode->style.border[CSS_LEFT]),
+            WXFloorPixelValue(self.cssNode->style.padding[CSS_BOTTOM] + self.cssNode->style.border[CSS_BOTTOM]),
+            WXFloorPixelValue(self.cssNode->style.padding[CSS_RIGHT] + self.cssNode->style.border[CSS_RIGHT])
+        };
+    }
+//#else
+    else
+    {
+        padding = {
+            WXFloorPixelValue(self.flexCssNode->getPaddingTop() + self.flexCssNode->getBorderWidthTop()),
+            WXFloorPixelValue(self.flexCssNode->getPaddingLeft() + self.flexCssNode->getBorderWidthLeft()),
+            WXFloorPixelValue(self.flexCssNode->getPaddingBottom() + self.flexCssNode->getBorderWidthBottom()),
+            WXFloorPixelValue(self.flexCssNode->getPaddingRight() + self.flexCssNode->getBorderWidthRight())
+        };
+    }
+//#endif
+    
+    
+    if (!UIEdgeInsetsEqualToEdgeInsets(padding, _padding)) {
+        _padding = padding;
+        [self setNeedsLayout];
+        
+        for (WXComponent *component in self.subcomponents) {
+            [component setNeedsLayout];
+        }
+        
+        if (_collectionView) {
+            WXPerformBlockOnMainThread(^{
+                [_collectionView.collectionViewLayout invalidateLayout];
+            });
+        }
+    }
+}
+
+- (NSArray<WXSectionDataController *> *)_sectionArrayFromComponents:(NSArray<WXComponent *> *)components
+{
+    NSMutableArray<WXSectionDataController *> *sectionArray = [NSMutableArray array];
+    NSMutableArray<WXCellComponent *> *cellArray = [NSMutableArray array];
+    WXSectionDataController *currentSection;
+    
+    for (int i = 0; i < components.count; i++) {
+        if (!currentSection) {
+            currentSection = [WXSectionDataController new];
+        }
+        
+        WXComponent* component = components[i];
+        
+        if ([component isKindOfClass:[WXHeaderComponent class]]) {
+            if (i != 0 && (currentSection.headerComponent || cellArray.count > 0)) {
+                currentSection.cellComponents = [cellArray copy];
+                [sectionArray addObject:currentSection];
+                currentSection = [WXSectionDataController new];
+                [cellArray removeAllObjects];
+            }
+            currentSection.headerComponent = (WXHeaderComponent *)component;
+        } else if ([component isKindOfClass:[WXCellComponent class]]
+                   && ((WXCellComponent *)component).isLayoutComplete) {
+            [cellArray addObject:(WXCellComponent *)component];
+        } else if ([component isKindOfClass:[WXFooterComponent class]]) {
+            currentSection.footerComponent = component;
+        } else {
+            continue;
+        }
+    }
+    
+    if (cellArray.count > 0 || currentSection.headerComponent) {
+        currentSection.cellComponents = [cellArray copy];
+        [sectionArray addObject:currentSection];
+    }
+    
+    return sectionArray;
+}
+
+- (void)fixFlicker
+{
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        // FIXME:(ง •̀_•́)ง┻━┻ Stupid scoll view, always reset content offset to zero by calling _adjustContentOffsetIfNecessary after insert cells.
+        // So if you pull down list while list is rendering, the list will be flickering.
+        // Demo:
+        // Have to hook _adjustContentOffsetIfNecessary here.
+        // Any other more elegant way?
+        NSString *a = @"ntOffsetIfNe";
+        NSString *b = @"adjustConte";
+        
+        NSString *originSelector = [NSString stringWithFormat:@"_%@%@cessary", b, a];
+        [[self class] weex_swizzle:[WXCollectionView class] Method:NSSelectorFromString(originSelector) withMethod:@selector(fixedFlickerSelector)];
+    });
+}
+
+#define mark dragControllerDelegate
+
+- (void)updateDataSource{
+    NSMutableArray *oldComponents = [[NSMutableArray alloc] initWithArray:self.dataController.sections[self.dragController.startIndexPath.section].cellComponents];
+    if(oldComponents.count > 1){
+        WXCellComponent *startComponent = self.dataController.sections[self.dragController.startIndexPath.section].cellComponents[self.dragController.startIndexPath.item];
+        [oldComponents removeObject:startComponent];
+        [oldComponents insertObject:startComponent atIndex:self.dragController.targetIndexPath.item];
+        self.dataController.sections[self.dragController.startIndexPath.section].cellComponents = oldComponents;
+    }
+}
+
+- (void)dragFireEvent:(NSString *)eventName params:(NSDictionary *)params{
+    [self fireEvent:eventName params:params];
+}
+
+- (void)fixedFlickerSelector
+{
+    // DO NOT delete this method.
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
deleted file mode 100644
index b8feb31..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
+++ /dev/null
@@ -1,145 +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 "WXSDKInstance.h"
-#import "WXLog.h"
-#import "WXCellComponent.h"
-#import "WXListComponent.h"
-#import "WXComponent_internal.h"
-#import "WXDiffUtil.h"
-
-@interface WXCellComponent ()
-
-@end
-
-@implementation WXCellComponent
-{
-    NSIndexPath *_indexPathBeforeMove;
-    BOOL _isUseContainerWidth;
-}
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    
-    if (self) {
-        _async = attributes[@"async"] ? [WXConvert BOOL:attributes[@"async"]] : YES;
-        _isRecycle = attributes[@"recycle"] ? [WXConvert BOOL:attributes[@"recycle"]] : YES;
-        _insertAnimation = [WXConvert UITableViewRowAnimation:attributes[@"insertAnimation"]];
-        _deleteAnimation = [WXConvert UITableViewRowAnimation:attributes[@"deleteAnimation"]];
-        _keepScrollPosition = attributes[@"keepScrollPosition"] ? [WXConvert BOOL:attributes[@"keepScrollPosition"]] : NO;
-        _lazyCreateView = YES;
-        _isNeedJoinLayoutSystem = NO;
-        if (attributes[@"zIndex"]) {
-            _zIndex = [WXConvert NSString:attributes[@"zIndex"]];
-        }
-    }
-    
-    return self;
-}
-
-- (void)dealloc
-{
-    
-}
-
-- (BOOL)weex_isEqualTo:(id<WXDiffable>)object
-{
-    return self == object;
-}
-
-- (void)_frameDidCalculated:(BOOL)isChanged
-{
-    [super _frameDidCalculated:isChanged];
-    
-    if (isChanged) {
-        [self.delegate cellDidLayout:self];
-    }
-}
-
-- (void)didFinishDrawingLayer:(BOOL)success
-{
-    [self.delegate cellDidRendered:self];
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    if (attributes[@"async"]) {
-        _async = [WXConvert BOOL:attributes[@"async"]];
-    }
-    
-    if (attributes[@"recycle"]) {
-        _isRecycle = [WXConvert BOOL:attributes[@"recycle"]];
-    }
-    
-    if (attributes[@"insertAnimation"]) {
-        _insertAnimation = [WXConvert UITableViewRowAnimation:attributes[@"insertAnimation"]];
-    }
-    
-    if (attributes[@"deleteAnimation"]) {
-        _deleteAnimation = [WXConvert UITableViewRowAnimation:attributes[@"deleteAnimation"]];
-    }
-    
-    if (attributes[@"keepScrollPosition"]) {
-        _keepScrollPosition = [WXConvert BOOL:attributes[@"keepScrollPosition"]];
-    }
-}
-
-- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
-{
-    if (self.delegate == (id<WXCellRenderDelegate>)newSupercomponent) {
-        [self.delegate cell:self didMoveToIndex:index];
-        [super _removeFromSupercomponent];
-        [newSupercomponent _insertSubcomponent:self atIndex:index];
-    } else {
-        [super _moveToSupercomponent:newSupercomponent atIndex:index];
-    }
-}
-
-- (void)_removeFromSupercomponent
-{
-    [super _removeFromSupercomponent];
-    
-    [self.delegate cellDidRemove:self];
-}
-
-- (void)removeFromSuperview
-{
-    // do nothing
-}
-
-- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
-{
-    if (self.delegate && (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) || _isUseContainerWidth)) {
-        self.cssNode->style.dimensions[CSS_WIDTH] = [self.delegate containerWidthForLayout:self];
-        //TODO: set _isUseContainerWidth to NO if updateStyles have width
-        _isUseContainerWidth = YES;
-    }
-    
-    if ([self needsLayout]) {
-        layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
-        if ([WXLog logLevel] >= WXLogLevelDebug) {
-            print_css_node(self.cssNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
-        }
-    }
-    
-    [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
-}
-@end
-

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.mm
new file mode 100644
index 0000000..62a542c
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.mm
@@ -0,0 +1,174 @@
+/*
+ * 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 "WXSDKInstance.h"
+#import "WXLog.h"
+#import "WXCellComponent.h"
+#import "WXListComponent.h"
+#import "WXComponent_internal.h"
+#import "WXDiffUtil.h"
+#import "WXComponent+Layout.h"
+
+@interface WXCellComponent ()
+
+@end
+
+@implementation WXCellComponent
+{
+    NSIndexPath *_indexPathBeforeMove;
+    BOOL _isUseContainerWidth;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> init Cell: ref:%@, styles:%@",ref,styles);
+#endif
+    
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    
+    if (self) {
+        _async = attributes[@"async"] ? [WXConvert BOOL:attributes[@"async"]] : YES;
+        _isRecycle = attributes[@"recycle"] ? [WXConvert BOOL:attributes[@"recycle"]] : YES;
+        _insertAnimation = [WXConvert UITableViewRowAnimation:attributes[@"insertAnimation"]];
+        _deleteAnimation = [WXConvert UITableViewRowAnimation:attributes[@"deleteAnimation"]];
+        _keepScrollPosition = attributes[@"keepScrollPosition"] ? [WXConvert BOOL:attributes[@"keepScrollPosition"]] : NO;
+        _lazyCreateView = YES;
+        _isNeedJoinLayoutSystem = NO;
+        if (attributes[@"zIndex"]) {
+            _zIndex = [WXConvert NSString:attributes[@"zIndex"]];
+        }
+    }
+    
+    return self;
+}
+
+- (void)dealloc
+{
+    
+}
+
+- (BOOL)weex_isEqualTo:(id<WXDiffable>)object
+{
+    return self == object;
+}
+
+- (void)_frameDidCalculated:(BOOL)isChanged
+{
+    [super _frameDidCalculated:isChanged];
+    
+    if (isChanged) {
+        [self.delegate cellDidLayout:self];
+    }
+}
+
+- (void)didFinishDrawingLayer:(BOOL)success
+{
+    [self.delegate cellDidRendered:self];
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"async"]) {
+        _async = [WXConvert BOOL:attributes[@"async"]];
+    }
+    
+    if (attributes[@"recycle"]) {
+        _isRecycle = [WXConvert BOOL:attributes[@"recycle"]];
+    }
+    
+    if (attributes[@"insertAnimation"]) {
+        _insertAnimation = [WXConvert UITableViewRowAnimation:attributes[@"insertAnimation"]];
+    }
+    
+    if (attributes[@"deleteAnimation"]) {
+        _deleteAnimation = [WXConvert UITableViewRowAnimation:attributes[@"deleteAnimation"]];
+    }
+    
+    if (attributes[@"keepScrollPosition"]) {
+        _keepScrollPosition = [WXConvert BOOL:attributes[@"keepScrollPosition"]];
+    }
+}
+
+- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
+{
+    if (self.delegate == (id<WXCellRenderDelegate>)newSupercomponent) {
+        [self.delegate cell:self didMoveToIndex:index];
+        [super _removeFromSupercomponent];
+        [newSupercomponent _insertSubcomponent:self atIndex:index];
+    } else {
+        [super _moveToSupercomponent:newSupercomponent atIndex:index];
+    }
+}
+
+- (void)_removeFromSupercomponent
+{
+    [super _removeFromSupercomponent];
+    
+    [self.delegate cellDidRemove:self];
+}
+
+- (void)removeFromSuperview
+{
+    // do nothing
+}
+
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
+{
+    
+//#ifndef USE_FLEX
+    if (![WXComponent isUseFlex]) {
+        if (self.delegate && (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) || _isUseContainerWidth)) {
+            self.cssNode->style.dimensions[CSS_WIDTH] = [self.delegate containerWidthForLayout:self];
+            //TODO: set _isUseContainerWidth to NO if updateStyles have width
+            _isUseContainerWidth = YES;
+        }
+        
+        if ([self needsLayout]) {
+            layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
+            if ([WXLog logLevel] >= WXLogLevelDebug) {
+                print_css_node(self.cssNode, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN));
+            }
+        }
+    }
+   
+//#else
+    else
+    {
+        if (self.delegate && (flexIsUndefined(self.flexCssNode->getStyleWidth()) || _isUseContainerWidth)) {
+            self.flexCssNode->setStyleWidth([self.delegate containerWidthForLayout:self],NO);
+            _isUseContainerWidth = YES;
+        }
+        
+        if ([self needsLayout]) {
+            std::pair<float, float> renderPageSize;
+            renderPageSize.first = self.weexInstance.frame.size.width;
+            renderPageSize.second = self.weexInstance.frame.size.height;
+            self.flexCssNode->calculateLayout(renderPageSize);
+            if ([WXLog logLevel] >= WXLogLevelDebug) {
+                
+            }
+        }
+    }
+  
+//#endif
+    [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+}
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/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 bf54a91..5f63065 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
+++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
@@ -36,15 +36,6 @@ typedef id (^WXDataBindingBlock)(NSDictionary *data, BOOL *needUpdate);
 @package
     NSString *_type;
     NSMutableArray *_subcomponents;
-    /**
-     *  Layout
-     */
-    css_node_t *_cssNode;
-    BOOL _isLayoutDirty;
-    CGRect _calculatedFrame;
-    CGPoint _absolutePosition;
-    WXPositionType _positionType;
-    
     
     //Transition
     WXTransition *_transition;
@@ -212,6 +203,8 @@ typedef id (^WXDataBindingBlock)(NSDictionary *data, BOOL *needUpdate);
 
 - (void)_initCSSNodeWithStyles:(NSDictionary *)styles;
 
+- (void)_initFlexCssNodeWithStyles:(NSDictionary *)styles;
+
 - (void)_updateCSSNodeStyles:(NSDictionary *)styles;
 
 - (void)_resetCSSNodeStyles:(NSArray *)styles;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
deleted file mode 100644
index 929dd1a..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
+++ /dev/null
@@ -1,681 +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 "WXCycleSliderComponent.h"
-#import "WXIndicatorComponent.h"
-#import "WXComponent_internal.h"
-#import "NSTimer+Weex.h"
-#import "WXSDKManager.h"
-#import "WXUtility.h"
-
-typedef NS_ENUM(NSInteger, Direction) {
-    DirectionNone = 1 << 0,
-    DirectionLeft = 1 << 1,
-    DirectionRight = 1 << 2
-};
-
-@class WXRecycleSliderView;
-@class WXIndicatorView;
-
-@protocol WXRecycleSliderViewDelegate <UIScrollViewDelegate>
-
-- (void)recycleSliderView:(WXRecycleSliderView *)recycleSliderView didScroll:(UIScrollView *)scrollView;
-- (void)recycleSliderView:(WXRecycleSliderView *)recycleSliderView didScrollToItemAtIndex:(NSInteger)index;
-- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
-- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
-
-@end
-
-@interface WXRecycleSliderView : UIView <UIScrollViewDelegate>
-
-@property (nonatomic, strong) WXIndicatorView *indicator;
-@property (nonatomic, weak) id<WXRecycleSliderViewDelegate> delegate;
-
-@property (nonatomic, strong) UIScrollView *scrollView;
-@property (nonatomic, strong) NSMutableArray *itemViews;
-@property (nonatomic, assign) Direction direction;
-@property (nonatomic, assign) NSInteger currentIndex;
-@property (nonatomic, assign) NSInteger nextIndex;
-@property (nonatomic, assign) CGRect currentItemFrame;
-@property (nonatomic, assign) CGRect nextItemFrame;
-@property (nonatomic, assign) BOOL infinite;
-
-- (void)insertItemView:(UIView *)view atIndex:(NSInteger)index;
-- (void)removeItemView:(UIView *)view;
-
-@end
-
-@implementation WXRecycleSliderView
-
-- (id)initWithFrame:(CGRect)frame
-{
-    self = [super initWithFrame:frame];
-    if (self) {
-        _currentIndex = 0;
-        _itemViews = [[NSMutableArray alloc] init];
-        _scrollView = [[UIScrollView alloc] init];
-        _scrollView.backgroundColor = [UIColor clearColor];
-        _scrollView.delegate = self;
-        _scrollView.showsHorizontalScrollIndicator = NO;
-        _scrollView.showsVerticalScrollIndicator = NO;
-        _scrollView.scrollsToTop = NO;
-        [self addSubview:_scrollView];
-    }
-    return self;
-}
-
-- (void)dealloc
-{
-    if (_scrollView) {
-        _scrollView.delegate = nil;
-    }
-}
-
-- (void)layoutSubviews
-{
-    [super layoutSubviews];
-    [self resetAllViewsFrame];
-}
-
-- (void)accessibilityDecrement
-{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
-    [self.wx_component performSelector:NSSelectorFromString(@"resumeAutoPlay:") withObject:@(false)];
-#pragma clang diagnostic pop
-    
-    [self nextPage];
-}
-
-- (void)accessibilityIncrement
-{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
-    [self.wx_component performSelector:NSSelectorFromString(@"resumeAutoPlay:") withObject:@(false)];
-#pragma clang diagnostic pop
-    
-    [self lastPage];
-}
-
-- (void)accessibilityElementDidLoseFocus
-{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
-    [self.wx_component performSelector:NSSelectorFromString(@"resumeAutoPlay:") withObject:@(true)];
-#pragma clang diagnostic pop
-}
-
-#pragma mark Private Methods
-- (CGFloat)height {
-    return self.frame.size.height;
-}
-
-- (CGFloat)width {
-    return self.frame.size.width;
-}
-
-- (UIView *)getItemAtIndex:(NSInteger)index
-{
-    if (self.itemViews.count > index) {
-        return [self.itemViews objectAtIndex:index];
-    }else{
-        return nil;
-    }
-}
-
-- (void)setCurrentIndex:(NSInteger)currentIndex
-{
-    if (currentIndex >= _itemViews.count || currentIndex < 0) {
-        currentIndex = 0;
-    }
-    NSInteger oldIndex = _currentIndex;
-    _currentIndex = currentIndex;
-    if (_infinite) {
-        if (_direction == DirectionRight) {
-            self.nextItemFrame = CGRectMake(0, 0, self.width, self.height);
-            self.nextIndex = self.currentIndex - 1;
-            if (self.nextIndex < 0)
-            {
-                self.nextIndex = _itemViews.count - 1;
-            }
-        }else if (_direction == DirectionLeft) {
-            self.nextItemFrame = CGRectMake(self.width * 2, 0, self.width, self.height);
-            self.nextIndex = _itemViews.count?(self.currentIndex + 1) % _itemViews.count:0;
-        }else {
-            self.nextIndex = _itemViews.count?(self.currentIndex + 1) % _itemViews.count:0;
-        }
-        [self resetAllViewsFrame];
-    } else {
-        [_scrollView setContentOffset:CGPointMake(_currentIndex * self.width, 0) animated:YES];
-    }
-    [self resetIndicatorPoint];
-    if (self.delegate && [self.delegate respondsToSelector:@selector(recycleSliderView:didScrollToItemAtIndex:)]) {
-        if (oldIndex != _currentIndex) {
-            [self.delegate recycleSliderView:self didScrollToItemAtIndex:_currentIndex];
-        }
-    }
-}
-
-- (void)resetIndicatorPoint
-{
-    [self.indicator setPointCount:self.itemViews.count];
-    [self.indicator setCurrentPoint:_currentIndex];
-}
-
-#pragma mark  Scroll & Frames
-- (void)setDirection:(Direction)direction {
-    if (_direction == direction) return;
-    _direction = direction;
-    if (_direction == DirectionNone) return;
-    if (_direction == DirectionRight) {
-        self.nextItemFrame = CGRectMake(0, 0, self.width, self.height);
-        self.nextIndex = self.currentIndex - 1;
-        if (self.nextIndex < 0)
-        {
-            self.nextIndex = _itemViews.count - 1;
-        }
-        UIView *view = [self getItemAtIndex:_nextIndex];
-        if (view) {
-            view.frame = _nextItemFrame;
-        }
-    }else if (_direction == DirectionLeft){
-        self.nextItemFrame = CGRectMake(self.width * 2, 0, self.width, self.height);
-        self.nextIndex = _itemViews.count?(self.currentIndex + 1) % _itemViews.count:0;
-        UIView *view = [self getItemAtIndex:_nextIndex];
-        if (view) {
-            view.frame = _nextItemFrame;
-        }
-    }
-}
-
-- (void)resetAllViewsFrame
-{
-    if (_infinite && _itemViews.count > 1) {
-        self.scrollView.frame = CGRectMake(0, 0, self.width, self.height);
-        self.scrollView.contentOffset = CGPointMake(self.width, 0);
-        if (self.itemViews.count > 1) {
-            self.scrollView.contentSize = CGSizeMake(self.width * 3, 0);
-        } else {
-            self.scrollView.contentSize = CGSizeZero;
-        }
-        _currentItemFrame = CGRectMake(self.width, 0, self.width, self.height);
-        for (int i = 0; i < self.itemViews.count; i++) {
-            UIView *view = [self.itemViews objectAtIndex:i];
-            if (i != self.currentIndex) {
-                view.frame = CGRectMake(self.frame.size.width * 3, 0, self.width, self.height);;
-            }
-        }
-        [self getItemAtIndex:_currentIndex].frame = _currentItemFrame;
-        if (_itemViews.count == 2) {
-            _nextItemFrame = CGRectMake(self.width * 2, 0, self.width, self.height);
-            [self getItemAtIndex:_nextIndex].frame = _nextItemFrame;
-        }
-    } else {
-        self.scrollView.frame = self.bounds;
-        self.scrollView.contentSize = CGSizeMake(self.width * _itemViews.count, self.height);
-        self.scrollView.contentOffset = CGPointMake(_currentIndex * self.width, 0);
-        for (int i = 0; i < _itemViews.count; i ++) {
-            UIView *view = [_itemViews objectAtIndex:i];
-            view.frame = CGRectMake(i * self.width, 0, self.width, self.height);
-        }
-        [self.scrollView setContentOffset:CGPointMake(_currentIndex * self.width, 0) animated:NO];
-    }
-    [self resetIndicatorPoint];
-}
-
-- (void)nextPage {
-    if (_itemViews.count > 1) {
-        if (_infinite) {
-            [self.scrollView setContentOffset:CGPointMake(self.width * 2, 0) animated:YES];
-        } else {
-            // the currentindex will be set at the end of animation
-            NSInteger nextIndex = self.currentIndex + 1;
-            if(nextIndex < _itemViews.count) {
-                [self.scrollView setContentOffset:CGPointMake(nextIndex * self.width, 0) animated:YES];
-            }
-        }
-    }
-}
-
-- (void)lastPage
-{
-    
-    NSInteger lastIndex = [self currentIndex]-1;
-    if (_itemViews.count > 1) {
-        if (_infinite) {
-            if (lastIndex < 0) {
-                lastIndex = [_itemViews count]-1;
-            }
-        }
-        [self setCurrentIndex:lastIndex];
-    }
-}
-
-- (void)resetScrollView
-{
-    if (WXFloatEqual(self.scrollView.contentOffset.x / self.width , 1.0))
-    {
-        return;
-    }
-    [self setCurrentIndex:self.nextIndex];
-    self.scrollView.contentOffset = CGPointMake(self.width, 0);
-}
-
-#pragma mark Public Methods
-
-- (void)setIndicator:(WXIndicatorView *)indicator
-{
-    _indicator = indicator;
-    [_indicator setPointCount:self.itemViews.count];
-    [_indicator setCurrentPoint:_currentIndex];
-}
-
-- (void)insertItemView:(UIView *)view atIndex:(NSInteger)index
-{
-    if (![self.itemViews containsObject:view]) {
-        view.tag = self.itemViews.count;
-        if (index < 0) {
-            [self.itemViews addObject:view];
-        } else {
-            [self.itemViews insertObject:view atIndex:index];
-        }
-    }
-    
-    if (![self.scrollView.subviews containsObject:view]) {
-        if (index < 0) {
-            [self.scrollView addSubview:view];
-        } else {
-            [self.scrollView insertSubview:view atIndex:index];
-        }
-    }
-    [self layoutSubviews];
-    [self setCurrentIndex:_currentIndex];
-}
-
-- (void)removeItemView:(UIView *)view
-{
-    if ([self.itemViews containsObject:view]) {
-        [self.itemViews removeObject:view];
-    }
-    
-    if ([self.scrollView.subviews containsObject:view]) {
-        [view removeFromSuperview];
-    }
-    [self layoutSubviews];
-    [self setCurrentIndex:_currentIndex];
-}
-
-#pragma mark ScrollView Delegate
-
-- (void)scrollViewDidScroll:(UIScrollView *)scrollView
-{
-    if (_infinite) {
-        CGFloat offX = scrollView.contentOffset.x;
-        self.direction = offX > self.width ? DirectionLeft : offX < self.width ? DirectionRight : DirectionNone;
-    }
-    if (self.delegate && [self.delegate respondsToSelector:@selector(recycleSliderView:didScroll:)]) {
-        [self.delegate recycleSliderView:self didScroll:self.scrollView];
-    }
-}
-
-- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
-{
-    if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) {
-        [self.delegate scrollViewWillBeginDragging:self.scrollView];
-    }
-}
-
-- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
-{
-    if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewDidEndDragging: willDecelerate:)]) {
-        [self.delegate scrollViewDidEndDragging:self.scrollView willDecelerate:decelerate];
-    }
-}
-
-- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
-    if (_infinite) {
-        [self resetScrollView];
-    } else {
-        NSInteger index = _scrollView.contentOffset.x / self.width;
-        [self setCurrentIndex:index];
-    }
-}
-
-- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
-    if (_infinite) {
-        [self resetScrollView];
-    } else {
-        NSInteger index = _scrollView.contentOffset.x / self.width;
-        [self setCurrentIndex:index];
-    }
-}
-
-@end
-
-@interface WXCycleSliderComponent () <WXRecycleSliderViewDelegate,WXIndicatorComponentDelegate>
-
-@property (nonatomic, strong) WXRecycleSliderView *recycleSliderView;
-@property (nonatomic, strong) NSTimer *autoTimer;
-@property (nonatomic, assign) NSInteger currentIndex;
-@property (nonatomic, assign) BOOL  autoPlay;
-@property (nonatomic, assign) NSUInteger interval;
-@property (nonatomic, assign) NSInteger index;
-@property (nonatomic, assign) CGFloat lastOffsetXRatio;
-@property (nonatomic, assign) CGFloat offsetXAccuracy;
-@property (nonatomic, assign) BOOL  sliderChangeEvent;
-@property (nonatomic, assign) BOOL  sliderScrollEvent;
-@property (nonatomic, assign) BOOL  sliderScrollStartEvent;
-@property (nonatomic, assign) BOOL  sliderScrollEndEvent;
-@property (nonatomic, assign) BOOL  sliderStartEventFired;
-@property (nonatomic, strong) NSMutableArray *childrenView;
-@property (nonatomic, assign) BOOL scrollable;
-@property (nonatomic, assign) BOOL infinite;
-
-@end
-
-@implementation WXCycleSliderComponent
-
-- (void) dealloc
-{
-    [self _stopAutoPlayTimer];
-}
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
-        _sliderChangeEvent = NO;
-        _sliderScrollEvent = NO;
-        _interval = 3000;
-        _childrenView = [NSMutableArray new];
-        _lastOffsetXRatio = 0;
-        
-        if (attributes[@"autoPlay"]) {
-            _autoPlay = [WXConvert BOOL:attributes[@"autoPlay"]];
-        }
-        
-        if (attributes[@"interval"]) {
-            _interval = [WXConvert NSInteger:attributes[@"interval"]];
-        }
-        
-        if (attributes[@"index"]) {
-            _index = [WXConvert NSInteger:attributes[@"index"]];
-        }
-        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
-        if (attributes[@"offsetXAccuracy"]) {
-            _offsetXAccuracy = [WXConvert CGFloat:attributes[@"offsetXAccuracy"]];
-        }
-        _infinite = attributes[@"infinite"] ? [WXConvert BOOL:attributes[@"infinite"]] : YES;
-        self.cssNode->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
-    }
-    return self;
-}
-
-- (UIView *)loadView
-{
-    return [[WXRecycleSliderView alloc] init];
-}
-
-- (void)viewDidLoad
-{
-    [super viewDidLoad];
-    
-    _recycleSliderView = (WXRecycleSliderView *)self.view;
-    _recycleSliderView.delegate = self;
-    _recycleSliderView.scrollView.pagingEnabled = YES;
-    _recycleSliderView.exclusiveTouch = YES;
-    _recycleSliderView.scrollView.scrollEnabled = _scrollable;
-    _recycleSliderView.infinite = _infinite;
-    UIAccessibilityTraits traits = UIAccessibilityTraitAdjustable;
-    if (_autoPlay) {
-        traits |= UIAccessibilityTraitUpdatesFrequently;
-        [self _startAutoPlayTimer];
-    } else {
-        [self _stopAutoPlayTimer];
-    }
-     _recycleSliderView.accessibilityTraits = traits;
-}
-
-- (void)layoutDidFinish
-{
-    _recycleSliderView.currentIndex = _index;
-}
-
-- (void)viewDidUnload
-{
-    [_childrenView removeAllObjects];
-}
-
-- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    if (subcomponent->_positionType == WXPositionTypeFixed) {
-        [self.weexInstance.rootView addSubview:subcomponent.view];
-        return;
-    }
-    
-    // use _lazyCreateView to forbid component like cell's view creating
-    if(_lazyCreateView) {
-        subcomponent->_lazyCreateView = YES;
-    }
-    
-    if (!subcomponent->_lazyCreateView || (self->_lazyCreateView && [self isViewLoaded])) {
-        UIView *view = subcomponent.view;
-        
-        if(index < 0) {
-            [self.childrenView addObject:view];
-        }
-        else {
-            [self.childrenView insertObject:view atIndex:index];
-        }
-        
-        WXRecycleSliderView *recycleSliderView = (WXRecycleSliderView *)self.view;
-        if ([view isKindOfClass:[WXIndicatorView class]]) {
-            ((WXIndicatorComponent *)subcomponent).delegate = self;
-            [recycleSliderView addSubview:view];
-            [self setIndicatorView:(WXIndicatorView *)view];
-            return;
-        }
-        
-        subcomponent.isViewFrameSyncWithCalculated = NO;
-        
-        if (index == -1) {
-            [recycleSliderView insertItemView:view atIndex:index];
-        } else {
-            NSInteger offset = 0;
-            for (int i = 0; i < [self.childrenView count]; ++i) {
-                if (index == i) break;
-                
-                if ([self.childrenView[i] isKindOfClass:[WXIndicatorView class]]) {
-                    offset++;
-                }
-            }
-            [recycleSliderView insertItemView:view atIndex:index - offset];
-            
-            // check if should apply current contentOffset
-            // in case inserting subviews after layoutDidFinish
-            if (index-offset == _index && _index>0) {
-                recycleSliderView.currentIndex = _index;
-            }
-        }
-        [recycleSliderView layoutSubviews];
-    }
-}
-
-- (void)willRemoveSubview:(WXComponent *)component
-{
-    UIView *view = component.view;
-    
-    if(self.childrenView && [self.childrenView containsObject:view]) {
-        [self.childrenView removeObject:view];
-    }
-    
-    WXRecycleSliderView *recycleSliderView = (WXRecycleSliderView *)_view;
-    [recycleSliderView removeItemView:view];
-    [recycleSliderView setCurrentIndex:0];
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    if (attributes[@"autoPlay"]) {
-        _autoPlay = [WXConvert BOOL:attributes[@"autoPlay"]];
-        if (_autoPlay) {
-            [self _startAutoPlayTimer];
-        } else {
-            [self _stopAutoPlayTimer];
-        }
-    }
-    
-    if (attributes[@"interval"]) {
-        _interval = [WXConvert NSInteger:attributes[@"interval"]];
-        [self _stopAutoPlayTimer];
-        
-        if (_autoPlay) {
-            [self _startAutoPlayTimer];
-        } 
-    }
-    
-    if (attributes[@"index"]) {
-        _index = [WXConvert NSInteger:attributes[@"index"]];
-        self.currentIndex = _index;
-        self.recycleSliderView.currentIndex = _index;
-    }
-    
-    if (attributes[@"scrollable"]) {
-        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
-        ((WXRecycleSliderView *)self.view).scrollView.scrollEnabled = _scrollable;
-    }
-    
-    if (attributes[@"offsetXAccuracy"]) {
-        _offsetXAccuracy = [WXConvert CGFloat:attributes[@"offsetXAccuracy"]];
-    }
-    if (attributes[@"infinite"]) {
-        _infinite = [WXConvert BOOL:attributes[@"infinite"]];
-    }
-}
-
-- (void)addEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"change"]) {
-        _sliderChangeEvent = YES;
-    }
-    if ([eventName isEqualToString:@"scroll"]) {
-        _sliderScrollEvent = YES;
-    }
-}
-
-- (void)removeEvent:(NSString *)eventName
-{
-    if ([eventName isEqualToString:@"change"]) {
-        _sliderChangeEvent = NO;
-    }
-    if ([eventName isEqualToString:@"scroll"]) {
-        _sliderScrollEvent = NO;
-    }
-}
-
-#pragma mark WXIndicatorComponentDelegate Methods
-
--(void)setIndicatorView:(WXIndicatorView *)indicatorView
-{
-    NSAssert(_recycleSliderView, @"");
-    [_recycleSliderView setIndicator:indicatorView];
-}
-
-- (void)resumeAutoPlay:(id)resume
-{
-    if (_autoPlay) {
-        if ([resume boolValue]) {
-            [self _startAutoPlayTimer];
-        } else {
-            [self _stopAutoPlayTimer];
-        }
-    }
-}
-
-#pragma mark Private Methods
-
-- (void)_startAutoPlayTimer
-{
-    if (!self.autoTimer || ![self.autoTimer isValid]) {
-        __weak __typeof__(self) weakSelf = self;
-        self.autoTimer = [NSTimer wx_scheduledTimerWithTimeInterval:_interval/1000.0f block:^() {
-            [weakSelf _autoPlayOnTimer];
-        } repeats:YES];
-        [[NSRunLoop currentRunLoop] addTimer:self.autoTimer forMode:NSRunLoopCommonModes];
-    }
-}
-
-- (void)_stopAutoPlayTimer
-{
-    if (self.autoTimer && [self.autoTimer isValid]) {
-        [self.autoTimer invalidate];
-        self.autoTimer = nil;
-    }
-}
-
-- (void)_autoPlayOnTimer
-{
-    if (!_infinite && (_currentIndex == _recycleSliderView.itemViews.count - 1)) {
-        [self _stopAutoPlayTimer];
-    }else {
-        [self.recycleSliderView nextPage];
-    }
-}
-
-#pragma mark ScrollView Delegate
-
-- (void)recycleSliderView:(WXRecycleSliderView *)recycleSliderView didScroll:(UIScrollView *)scrollView
-{
-    if (_sliderScrollEvent) {
-        CGFloat width = scrollView.frame.size.width;
-        CGFloat XDeviation = 0;
-        if (_infinite) {
-            XDeviation = - (scrollView.contentOffset.x - width);
-        } else {
-            XDeviation = - (scrollView.contentOffset.x - width * _currentIndex);
-        }
-        CGFloat offsetXRatio = (XDeviation / width);
-        if (fabs(offsetXRatio - _lastOffsetXRatio) >= _offsetXAccuracy) {
-            _lastOffsetXRatio = offsetXRatio;
-            [self fireEvent:@"scroll" params:@{@"offsetXRatio":[NSNumber numberWithFloat:offsetXRatio]} domChanges:nil];
-        }
-    }
-}
-
-- (void)recycleSliderView:(WXRecycleSliderView *)recycleSliderView didScrollToItemAtIndex:(NSInteger)index
-{
-    
-    if (_sliderChangeEvent) {
-        [self fireEvent:@"change" params:@{@"index":@(index)} domChanges:@{@"attrs": @{@"index": @(index)}}];
-    }
-    self.currentIndex = index;
-}
-
-- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
-{
-    [self _stopAutoPlayTimer];
-}
-
-- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
-{
-    if (_autoPlay) {
-        [self _startAutoPlayTimer];
-    }
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
new file mode 100644
index 0000000..db77b46
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
@@ -0,0 +1,692 @@
+/*
+ * 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 "WXCycleSliderComponent.h"
+#import "WXIndicatorComponent.h"
+#import "WXComponent_internal.h"
+#import "NSTimer+Weex.h"
+#import "WXSDKManager.h"
+#import "WXUtility.h"
+#import "WXComponent+Layout.h"
+
+typedef NS_ENUM(NSInteger, Direction) {
+    DirectionNone = 1 << 0,
+    DirectionLeft = 1 << 1,
+    DirectionRight = 1 << 2
+};
+
+@class WXRecycleSliderView;
+@class WXIndicatorView;
+
+@protocol WXRecycleSliderViewDelegate <UIScrollViewDelegate>
+
+- (void)recycleSliderView:(WXRecycleSliderView *)recycleSliderView didScroll:(UIScrollView *)scrollView;
+- (void)recycleSliderView:(WXRecycleSliderView *)recycleSliderView didScrollToItemAtIndex:(NSInteger)index;
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
+
+@end
+
+@interface WXRecycleSliderView : UIView <UIScrollViewDelegate>
+
+@property (nonatomic, strong) WXIndicatorView *indicator;
+@property (nonatomic, weak) id<WXRecycleSliderViewDelegate> delegate;
+
+@property (nonatomic, strong) UIScrollView *scrollView;
+@property (nonatomic, strong) NSMutableArray *itemViews;
+@property (nonatomic, assign) Direction direction;
+@property (nonatomic, assign) NSInteger currentIndex;
+@property (nonatomic, assign) NSInteger nextIndex;
+@property (nonatomic, assign) CGRect currentItemFrame;
+@property (nonatomic, assign) CGRect nextItemFrame;
+@property (nonatomic, assign) BOOL infinite;
+
+- (void)insertItemView:(UIView *)view atIndex:(NSInteger)index;
+- (void)removeItemView:(UIView *)view;
+
+@end
+
+@implementation WXRecycleSliderView
+
+- (id)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        _currentIndex = 0;
+        _itemViews = [[NSMutableArray alloc] init];
+        _scrollView = [[UIScrollView alloc] init];
+        _scrollView.backgroundColor = [UIColor clearColor];
+        _scrollView.delegate = self;
+        _scrollView.showsHorizontalScrollIndicator = NO;
+        _scrollView.showsVerticalScrollIndicator = NO;
+        _scrollView.scrollsToTop = NO;
+        [self addSubview:_scrollView];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    if (_scrollView) {
+        _scrollView.delegate = nil;
+    }
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    [self resetAllViewsFrame];
+}
+
+- (void)accessibilityDecrement
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+    [self.wx_component performSelector:NSSelectorFromString(@"resumeAutoPlay:") withObject:@(false)];
+#pragma clang diagnostic pop
+    
+    [self nextPage];
+}
+
+- (void)accessibilityIncrement
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+    [self.wx_component performSelector:NSSelectorFromString(@"resumeAutoPlay:") withObject:@(false)];
+#pragma clang diagnostic pop
+    
+    [self lastPage];
+}
+
+- (void)accessibilityElementDidLoseFocus
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+    [self.wx_component performSelector:NSSelectorFromString(@"resumeAutoPlay:") withObject:@(true)];
+#pragma clang diagnostic pop
+}
+
+#pragma mark Private Methods
+- (CGFloat)height {
+    return self.frame.size.height;
+}
+
+- (CGFloat)width {
+    return self.frame.size.width;
+}
+
+- (UIView *)getItemAtIndex:(NSInteger)index
+{
+    if (self.itemViews.count > index) {
+        return [self.itemViews objectAtIndex:index];
+    }else{
+        return nil;
+    }
+}
+
+- (void)setCurrentIndex:(NSInteger)currentIndex
+{
+    if (currentIndex >= _itemViews.count || currentIndex < 0) {
+        currentIndex = 0;
+    }
+    NSInteger oldIndex = _currentIndex;
+    _currentIndex = currentIndex;
+    if (_infinite) {
+        if (_direction == DirectionRight) {
+            self.nextItemFrame = CGRectMake(0, 0, self.width, self.height);
+            self.nextIndex = self.currentIndex - 1;
+            if (self.nextIndex < 0)
+            {
+                self.nextIndex = _itemViews.count - 1;
+            }
+        }else if (_direction == DirectionLeft) {
+            self.nextItemFrame = CGRectMake(self.width * 2, 0, self.width, self.height);
+            self.nextIndex = _itemViews.count?(self.currentIndex + 1) % _itemViews.count:0;
+        }else {
+            self.nextIndex = _itemViews.count?(self.currentIndex + 1) % _itemViews.count:0;
+        }
+        [self resetAllViewsFrame];
+    } else {
+        [_scrollView setContentOffset:CGPointMake(_currentIndex * self.width, 0) animated:YES];
+    }
+    [self resetIndicatorPoint];
+    if (self.delegate && [self.delegate respondsToSelector:@selector(recycleSliderView:didScrollToItemAtIndex:)]) {
+        if (oldIndex != _currentIndex) {
+            [self.delegate recycleSliderView:self didScrollToItemAtIndex:_currentIndex];
+        }
+    }
+}
+
+- (void)resetIndicatorPoint
+{
+    [self.indicator setPointCount:self.itemViews.count];
+    [self.indicator setCurrentPoint:_currentIndex];
+}
+
+#pragma mark  Scroll & Frames
+- (void)setDirection:(Direction)direction {
+    if (_direction == direction) return;
+    _direction = direction;
+    if (_direction == DirectionNone) return;
+    if (_direction == DirectionRight) {
+        self.nextItemFrame = CGRectMake(0, 0, self.width, self.height);
+        self.nextIndex = self.currentIndex - 1;
+        if (self.nextIndex < 0)
+        {
+            self.nextIndex = _itemViews.count - 1;
+        }
+        UIView *view = [self getItemAtIndex:_nextIndex];
+        if (view) {
+            view.frame = _nextItemFrame;
+        }
+    }else if (_direction == DirectionLeft){
+        self.nextItemFrame = CGRectMake(self.width * 2, 0, self.width, self.height);
+        self.nextIndex = _itemViews.count?(self.currentIndex + 1) % _itemViews.count:0;
+        UIView *view = [self getItemAtIndex:_nextIndex];
+        if (view) {
+            view.frame = _nextItemFrame;
+        }
+    }
+}
+
+- (void)resetAllViewsFrame
+{
+    if (_infinite && _itemViews.count > 1) {
+        self.scrollView.frame = CGRectMake(0, 0, self.width, self.height);
+        self.scrollView.contentOffset = CGPointMake(self.width, 0);
+        if (self.itemViews.count > 1) {
+            self.scrollView.contentSize = CGSizeMake(self.width * 3, 0);
+        } else {
+            self.scrollView.contentSize = CGSizeZero;
+        }
+        _currentItemFrame = CGRectMake(self.width, 0, self.width, self.height);
+        for (int i = 0; i < self.itemViews.count; i++) {
+            UIView *view = [self.itemViews objectAtIndex:i];
+            if (i != self.currentIndex) {
+                view.frame = CGRectMake(self.frame.size.width * 3, 0, self.width, self.height);;
+            }
+        }
+        [self getItemAtIndex:_currentIndex].frame = _currentItemFrame;
+        if (_itemViews.count == 2) {
+            _nextItemFrame = CGRectMake(self.width * 2, 0, self.width, self.height);
+            [self getItemAtIndex:_nextIndex].frame = _nextItemFrame;
+        }
+    } else {
+        self.scrollView.frame = self.bounds;
+        self.scrollView.contentSize = CGSizeMake(self.width * _itemViews.count, self.height);
+        self.scrollView.contentOffset = CGPointMake(_currentIndex * self.width, 0);
+        for (int i = 0; i < _itemViews.count; i ++) {
+            UIView *view = [_itemViews objectAtIndex:i];
+            view.frame = CGRectMake(i * self.width, 0, self.width, self.height);
+        }
+        [self.scrollView setContentOffset:CGPointMake(_currentIndex * self.width, 0) animated:NO];
+    }
+    [self resetIndicatorPoint];
+}
+
+- (void)nextPage {
+    if (_itemViews.count > 1) {
+        if (_infinite) {
+            [self.scrollView setContentOffset:CGPointMake(self.width * 2, 0) animated:YES];
+        } else {
+            // the currentindex will be set at the end of animation
+            NSInteger nextIndex = self.currentIndex + 1;
+            if(nextIndex < _itemViews.count) {
+                [self.scrollView setContentOffset:CGPointMake(nextIndex * self.width, 0) animated:YES];
+            }
+        }
+    }
+}
+
+- (void)lastPage
+{
+    
+    NSInteger lastIndex = [self currentIndex]-1;
+    if (_itemViews.count > 1) {
+        if (_infinite) {
+            if (lastIndex < 0) {
+                lastIndex = [_itemViews count]-1;
+            }
+        }
+        [self setCurrentIndex:lastIndex];
+    }
+}
+
+- (void)resetScrollView
+{
+    if (WXFloatEqual(self.scrollView.contentOffset.x / self.width , 1.0))
+    {
+        return;
+    }
+    [self setCurrentIndex:self.nextIndex];
+    self.scrollView.contentOffset = CGPointMake(self.width, 0);
+}
+
+#pragma mark Public Methods
+
+- (void)setIndicator:(WXIndicatorView *)indicator
+{
+    _indicator = indicator;
+    [_indicator setPointCount:self.itemViews.count];
+    [_indicator setCurrentPoint:_currentIndex];
+}
+
+- (void)insertItemView:(UIView *)view atIndex:(NSInteger)index
+{
+    if (![self.itemViews containsObject:view]) {
+        view.tag = self.itemViews.count;
+        if (index < 0) {
+            [self.itemViews addObject:view];
+        } else {
+            [self.itemViews insertObject:view atIndex:index];
+        }
+    }
+    
+    if (![self.scrollView.subviews containsObject:view]) {
+        if (index < 0) {
+            [self.scrollView addSubview:view];
+        } else {
+            [self.scrollView insertSubview:view atIndex:index];
+        }
+    }
+    [self layoutSubviews];
+    [self setCurrentIndex:_currentIndex];
+}
+
+- (void)removeItemView:(UIView *)view
+{
+    if ([self.itemViews containsObject:view]) {
+        [self.itemViews removeObject:view];
+    }
+    
+    if ([self.scrollView.subviews containsObject:view]) {
+        [view removeFromSuperview];
+    }
+    [self layoutSubviews];
+    [self setCurrentIndex:_currentIndex];
+}
+
+#pragma mark ScrollView Delegate
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView
+{
+    if (_infinite) {
+        CGFloat offX = scrollView.contentOffset.x;
+        self.direction = offX > self.width ? DirectionLeft : offX < self.width ? DirectionRight : DirectionNone;
+    }
+    if (self.delegate && [self.delegate respondsToSelector:@selector(recycleSliderView:didScroll:)]) {
+        [self.delegate recycleSliderView:self didScroll:self.scrollView];
+    }
+}
+
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
+{
+    if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) {
+        [self.delegate scrollViewWillBeginDragging:self.scrollView];
+    }
+}
+
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
+{
+    if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewDidEndDragging: willDecelerate:)]) {
+        [self.delegate scrollViewDidEndDragging:self.scrollView willDecelerate:decelerate];
+    }
+}
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+    if (_infinite) {
+        [self resetScrollView];
+    } else {
+        NSInteger index = _scrollView.contentOffset.x / self.width;
+        [self setCurrentIndex:index];
+    }
+}
+
+- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
+    if (_infinite) {
+        [self resetScrollView];
+    } else {
+        NSInteger index = _scrollView.contentOffset.x / self.width;
+        [self setCurrentIndex:index];
+    }
+}
+
+@end
+
+@interface WXCycleSliderComponent () <WXRecycleSliderViewDelegate,WXIndicatorComponentDelegate>
+
+@property (nonatomic, strong) WXRecycleSliderView *recycleSliderView;
+@property (nonatomic, strong) NSTimer *autoTimer;
+@property (nonatomic, assign) NSInteger currentIndex;
+@property (nonatomic, assign) BOOL  autoPlay;
+@property (nonatomic, assign) NSUInteger interval;
+@property (nonatomic, assign) NSInteger index;
+@property (nonatomic, assign) CGFloat lastOffsetXRatio;
+@property (nonatomic, assign) CGFloat offsetXAccuracy;
+@property (nonatomic, assign) BOOL  sliderChangeEvent;
+@property (nonatomic, assign) BOOL  sliderScrollEvent;
+@property (nonatomic, assign) BOOL  sliderScrollStartEvent;
+@property (nonatomic, assign) BOOL  sliderScrollEndEvent;
+@property (nonatomic, assign) BOOL  sliderStartEventFired;
+@property (nonatomic, strong) NSMutableArray *childrenView;
+@property (nonatomic, assign) BOOL scrollable;
+@property (nonatomic, assign) BOOL infinite;
+
+@end
+
+@implementation WXCycleSliderComponent
+
+- (void) dealloc
+{
+    [self _stopAutoPlayTimer];
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        _sliderChangeEvent = NO;
+        _sliderScrollEvent = NO;
+        _interval = 3000;
+        _childrenView = [NSMutableArray new];
+        _lastOffsetXRatio = 0;
+        
+        if (attributes[@"autoPlay"]) {
+            _autoPlay = [WXConvert BOOL:attributes[@"autoPlay"]];
+        }
+        
+        if (attributes[@"interval"]) {
+            _interval = [WXConvert NSInteger:attributes[@"interval"]];
+        }
+        
+        if (attributes[@"index"]) {
+            _index = [WXConvert NSInteger:attributes[@"index"]];
+        }
+        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
+        if (attributes[@"offsetXAccuracy"]) {
+            _offsetXAccuracy = [WXConvert CGFloat:attributes[@"offsetXAccuracy"]];
+        }
+        _infinite = attributes[@"infinite"] ? [WXConvert BOOL:attributes[@"infinite"]] : YES;
+//#ifndef USE_FLEX
+        if (![WXComponent isUseFlex]) {
+            self.cssNode->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        }
+//#else
+        else
+        {
+              self.flexCssNode->setFlexDirection(WeexCore::kFlexDirectionRow,NO);
+        }
+//#endif
+        
+    }
+    return self;
+}
+
+- (UIView *)loadView
+{
+    return [[WXRecycleSliderView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    
+    _recycleSliderView = (WXRecycleSliderView *)self.view;
+    _recycleSliderView.delegate = self;
+    _recycleSliderView.scrollView.pagingEnabled = YES;
+    _recycleSliderView.exclusiveTouch = YES;
+    _recycleSliderView.scrollView.scrollEnabled = _scrollable;
+    _recycleSliderView.infinite = _infinite;
+    UIAccessibilityTraits traits = UIAccessibilityTraitAdjustable;
+    if (_autoPlay) {
+        traits |= UIAccessibilityTraitUpdatesFrequently;
+        [self _startAutoPlayTimer];
+    } else {
+        [self _stopAutoPlayTimer];
+    }
+     _recycleSliderView.accessibilityTraits = traits;
+}
+
+- (void)layoutDidFinish
+{
+    _recycleSliderView.currentIndex = _index;
+}
+
+- (void)viewDidUnload
+{
+    [_childrenView removeAllObjects];
+}
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    if (subcomponent->_positionType == WXPositionTypeFixed) {
+        [self.weexInstance.rootView addSubview:subcomponent.view];
+        return;
+    }
+    
+    // use _lazyCreateView to forbid component like cell's view creating
+    if(_lazyCreateView) {
+        subcomponent->_lazyCreateView = YES;
+    }
+    
+    if (!subcomponent->_lazyCreateView || (self->_lazyCreateView && [self isViewLoaded])) {
+        UIView *view = subcomponent.view;
+        
+        if(index < 0) {
+            [self.childrenView addObject:view];
+        }
+        else {
+            [self.childrenView insertObject:view atIndex:index];
+        }
+        
+        WXRecycleSliderView *recycleSliderView = (WXRecycleSliderView *)self.view;
+        if ([view isKindOfClass:[WXIndicatorView class]]) {
+            ((WXIndicatorComponent *)subcomponent).delegate = self;
+            [recycleSliderView addSubview:view];
+            [self setIndicatorView:(WXIndicatorView *)view];
+            return;
+        }
+        
+        subcomponent.isViewFrameSyncWithCalculated = NO;
+        
+        if (index == -1) {
+            [recycleSliderView insertItemView:view atIndex:index];
+        } else {
+            NSInteger offset = 0;
+            for (int i = 0; i < [self.childrenView count]; ++i) {
+                if (index == i) break;
+                
+                if ([self.childrenView[i] isKindOfClass:[WXIndicatorView class]]) {
+                    offset++;
+                }
+            }
+            [recycleSliderView insertItemView:view atIndex:index - offset];
+            
+            // check if should apply current contentOffset
+            // in case inserting subviews after layoutDidFinish
+            if (index-offset == _index && _index>0) {
+                recycleSliderView.currentIndex = _index;
+            }
+        }
+        [recycleSliderView layoutSubviews];
+    }
+}
+
+- (void)willRemoveSubview:(WXComponent *)component
+{
+    UIView *view = component.view;
+    
+    if(self.childrenView && [self.childrenView containsObject:view]) {
+        [self.childrenView removeObject:view];
+    }
+    
+    WXRecycleSliderView *recycleSliderView = (WXRecycleSliderView *)_view;
+    [recycleSliderView removeItemView:view];
+    [recycleSliderView setCurrentIndex:0];
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"autoPlay"]) {
+        _autoPlay = [WXConvert BOOL:attributes[@"autoPlay"]];
+        if (_autoPlay) {
+            [self _startAutoPlayTimer];
+        } else {
+            [self _stopAutoPlayTimer];
+        }
+    }
+    
+    if (attributes[@"interval"]) {
+        _interval = [WXConvert NSInteger:attributes[@"interval"]];
+        [self _stopAutoPlayTimer];
+        
+        if (_autoPlay) {
+            [self _startAutoPlayTimer];
+        } 
+    }
+    
+    if (attributes[@"index"]) {
+        _index = [WXConvert NSInteger:attributes[@"index"]];
+        self.currentIndex = _index;
+        self.recycleSliderView.currentIndex = _index;
+    }
+    
+    if (attributes[@"scrollable"]) {
+        _scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
+        ((WXRecycleSliderView *)self.view).scrollView.scrollEnabled = _scrollable;
+    }
+    
+    if (attributes[@"offsetXAccuracy"]) {
+        _offsetXAccuracy = [WXConvert CGFloat:attributes[@"offsetXAccuracy"]];
+    }
+    if (attributes[@"infinite"]) {
+        _infinite = [WXConvert BOOL:attributes[@"infinite"]];
+    }
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"change"]) {
+        _sliderChangeEvent = YES;
+    }
+    if ([eventName isEqualToString:@"scroll"]) {
+        _sliderScrollEvent = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"change"]) {
+        _sliderChangeEvent = NO;
+    }
+    if ([eventName isEqualToString:@"scroll"]) {
+        _sliderScrollEvent = NO;
+    }
+}
+
+#pragma mark WXIndicatorComponentDelegate Methods
+
+-(void)setIndicatorView:(WXIndicatorView *)indicatorView
+{
+    NSAssert(_recycleSliderView, @"");
+    [_recycleSliderView setIndicator:indicatorView];
+}
+
+- (void)resumeAutoPlay:(id)resume
+{
+    if (_autoPlay) {
+        if ([resume boolValue]) {
+            [self _startAutoPlayTimer];
+        } else {
+            [self _stopAutoPlayTimer];
+        }
+    }
+}
+
+#pragma mark Private Methods
+
+- (void)_startAutoPlayTimer
+{
+    if (!self.autoTimer || ![self.autoTimer isValid]) {
+        __weak __typeof__(self) weakSelf = self;
+        self.autoTimer = [NSTimer wx_scheduledTimerWithTimeInterval:_interval/1000.0f block:^() {
+            [weakSelf _autoPlayOnTimer];
+        } repeats:YES];
+        [[NSRunLoop currentRunLoop] addTimer:self.autoTimer forMode:NSRunLoopCommonModes];
+    }
+}
+
+- (void)_stopAutoPlayTimer
+{
+    if (self.autoTimer && [self.autoTimer isValid]) {
+        [self.autoTimer invalidate];
+        self.autoTimer = nil;
+    }
+}
+
+- (void)_autoPlayOnTimer
+{
+    if (!_infinite && (_currentIndex == _recycleSliderView.itemViews.count - 1)) {
+        [self _stopAutoPlayTimer];
+    }else {
+        [self.recycleSliderView nextPage];
+    }
+}
+
+#pragma mark ScrollView Delegate
+
+- (void)recycleSliderView:(WXRecycleSliderView *)recycleSliderView didScroll:(UIScrollView *)scrollView
+{
+    if (_sliderScrollEvent) {
+        CGFloat width = scrollView.frame.size.width;
+        CGFloat XDeviation = 0;
+        if (_infinite) {
+            XDeviation = - (scrollView.contentOffset.x - width);
+        } else {
+            XDeviation = - (scrollView.contentOffset.x - width * _currentIndex);
+        }
+        CGFloat offsetXRatio = (XDeviation / width);
+        if (fabs(offsetXRatio - _lastOffsetXRatio) >= _offsetXAccuracy) {
+            _lastOffsetXRatio = offsetXRatio;
+            [self fireEvent:@"scroll" params:@{@"offsetXRatio":[NSNumber numberWithFloat:offsetXRatio]} domChanges:nil];
+        }
+    }
+}
+
+- (void)recycleSliderView:(WXRecycleSliderView *)recycleSliderView didScrollToItemAtIndex:(NSInteger)index
+{
+    
+    if (_sliderChangeEvent) {
+        [self fireEvent:@"change" params:@{@"index":@(index)} domChanges:@{@"attrs": @{@"index": @(index)}}];
+    }
+    self.currentIndex = index;
+}
+
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
+{
+    [self _stopAutoPlayTimer];
+}
+
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
+{
+    if (_autoPlay) {
+        [self _startAutoPlayTimer];
+    }
+}
+
+@end


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp b/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp
new file mode 100644
index 0000000..11f8dc8
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp
@@ -0,0 +1,247 @@
+#include "WXCoreStyle.h"
+
+namespace WeexCore {
+
+  bool WXCoreMargin::setMargin(const WXCoreMarginEdge &edge, float margin) {
+    bool dirty = false;
+    switch (edge) {
+      case kMarginALL:
+        if (mMarginLeft != margin
+            || mMarginTop != margin
+            || mMarginRight != margin
+            || mMarginBottom != margin) {
+          mMarginLeft = margin;
+          mMarginTop = margin;
+          mMarginRight = margin;
+          mMarginBottom = margin;
+          dirty = true;
+        }
+        break;
+      case kMarginLeft:
+        if (mMarginLeft != margin) {
+          mMarginLeft = margin;
+          dirty = true;
+        }
+        break;
+      case kMarginTop:
+        if (mMarginTop != margin) {
+          mMarginTop = margin;
+          dirty = true;
+        }
+        break;
+      case kMarginRight:
+        if (mMarginRight != margin) {
+          mMarginRight = margin;
+          dirty = true;
+        }
+        break;
+      case kMarginBottom:
+        if (mMarginBottom != margin) {
+          mMarginBottom = margin;
+          dirty = true;
+        }
+        break;
+    }
+    return dirty;
+  }
+
+  float WXCoreMargin::getMargin(const WXCoreMarginEdge &edge)const {
+    float margin = 0;
+    switch (edge) {
+      case kMarginLeft:
+        margin = mMarginLeft;
+        break;
+      case kMarginTop:
+        margin = mMarginTop;
+        break;
+      case kMarginRight:
+        margin = mMarginRight;
+        break;
+      case kMarginBottom:
+        margin = mMarginBottom;
+        break;
+      default:
+        break;
+    }
+    return margin;
+  }
+
+  bool WXCorePadding::setPadding(const WXCorePaddingEdge &edge, float padding) {
+    bool dirty = false;
+    switch (edge) {
+      case kPaddingALL:
+        if (mPaddingLeft != padding
+            || mPaddingTop != padding
+            || mPaddingRight != padding
+            || mPaddingBottom != padding) {
+          mPaddingLeft = padding;
+          mPaddingTop = padding;
+          mPaddingRight = padding;
+          mPaddingBottom = padding;
+          dirty = true;
+        }
+        break;
+      case kPaddingLeft:
+        if (mPaddingLeft != padding) {
+          mPaddingLeft = padding;
+          dirty = true;
+        }
+        break;
+      case kPaddingTop:
+        if (mPaddingTop != padding) {
+          mPaddingTop = padding;
+          dirty = true;
+        }
+        break;
+      case kPaddingRight:
+        if (mPaddingRight != padding) {
+          mPaddingRight = padding;
+          dirty = true;
+        }
+        break;
+      case kPaddingBottom:
+        if (mPaddingBottom != padding) {
+          mPaddingBottom = padding;
+          dirty = true;
+        }
+        break;
+    }
+    return dirty;
+  }
+
+  float WXCorePadding::getPadding(const WXCorePaddingEdge &edge)const {
+    float padding = 0;
+    switch (edge) {
+      case kPaddingLeft:
+        padding = mPaddingLeft;
+        break;
+      case kPaddingTop:
+        padding = mPaddingTop;
+        break;
+      case kPaddingRight:
+        padding = mPaddingRight;
+        break;
+      case kPaddingBottom:
+        padding = mPaddingBottom;
+        break;
+      default:
+        break;
+    }
+    return padding;
+  }
+
+  bool WXCoreBorderWidth::setBorderWidth(const WXCoreBorderWidthEdge &edge, float borderWidth) {
+    bool dirty = false;
+    switch (edge) {
+      case kBorderWidthALL:
+        if (mBorderWidthLeft != borderWidth
+            || mBorderWidthTop != borderWidth
+            || mBorderWidthRight != borderWidth
+            || mBorderWidthBottom != borderWidth) {
+          mBorderWidthLeft = borderWidth;
+          mBorderWidthTop = borderWidth;
+          mBorderWidthRight = borderWidth;
+          mBorderWidthBottom = borderWidth;
+          dirty = true;
+        }
+        break;
+      case kBorderWidthLeft:
+        if (mBorderWidthLeft != borderWidth) {
+          mBorderWidthLeft = borderWidth;
+          dirty = true;
+        }
+        break;
+      case kBorderWidthTop:
+        if (mBorderWidthTop != borderWidth) {
+          mBorderWidthTop = borderWidth;
+          dirty = true;
+        }
+        break;
+      case kBorderWidthRight:
+        if (mBorderWidthRight != borderWidth) {
+          mBorderWidthRight = borderWidth;
+          dirty = true;
+        }
+        break;
+      case kBorderWidthBottom:
+        if (mBorderWidthBottom != borderWidth) {
+          mBorderWidthBottom = borderWidth;
+          dirty = true;
+        }
+        break;
+    }
+    return dirty;
+  }
+
+  float WXCoreBorderWidth::getBorderWidth(const WXCoreBorderWidthEdge &edge)const {
+    float borderWidth = 0;
+    switch (edge) {
+      case kBorderWidthLeft:
+        borderWidth = mBorderWidthLeft;
+        break;
+      case kBorderWidthTop:
+        borderWidth = mBorderWidthTop;
+        break;
+      case kBorderWidthRight:
+        borderWidth = mBorderWidthRight;
+        break;
+      case kBorderWidthBottom:
+        borderWidth = mBorderWidthBottom;
+        break;
+      default:
+        break;
+    }
+    return borderWidth;
+  }
+
+  bool WXCorePosition::setPosition(const WXCorePositionEdge &edge, float position) {
+    bool dirty = false;
+    switch (edge) {
+      case kPositionEdgeLeft:
+        if (mLeft != position) {
+          mLeft = position;
+          dirty = true;
+        }
+        break;
+      case kPositionEdgeTop:
+        if (mTop != position) {
+          mTop = position;
+          dirty = true;
+        }
+        break;
+      case kPositionEdgeRight:
+        if (mRight != position) {
+          mRight = position;
+          dirty = true;
+        }
+        break;
+      case kPositionEdgeBottom:
+        if (mBottom != position) {
+          mBottom = position;
+          dirty = true;
+        }
+        break;
+    }
+    return dirty;
+  }
+
+  float WXCorePosition::getPosition(const WXCorePositionEdge &edge) {
+    float position = 0;
+    switch (edge) {
+      case kPositionEdgeLeft:
+        position = mLeft;
+        break;
+      case kPositionEdgeTop:
+        position = mTop;
+        break;
+      case kPositionEdgeRight:
+        position = mRight;
+        break;
+      case kPositionEdgeBottom:
+        position = mBottom;
+        break;
+    }
+    return position;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h b/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h
new file mode 100644
index 0000000..bc7dd06
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h
@@ -0,0 +1,285 @@
+#ifdef __cplusplus
+
+#ifndef WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUMS_H
+#define WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUMS_H
+
+
+#include "WXCoreFlexEnum.h"
+#include <cmath>
+
+namespace WeexCore {
+
+  /**
+   * Margin: margin-left、margin-right、margin-top、margin-bottom
+   */
+  class WXCoreMargin {
+  private:
+    float mMarginTop;
+    float mMarginBottom;
+    float mMarginLeft;
+    float mMarginRight;
+
+  public:
+    WXCoreMargin() : mMarginTop(0),
+                     mMarginBottom(0),
+                     mMarginLeft(0),
+                     mMarginRight(0) {}
+
+    ~WXCoreMargin() {
+      mMarginTop = 0;
+      mMarginBottom = 0;
+      mMarginLeft = 0;
+      mMarginRight = 0;
+    }
+
+    bool setMargin(const WXCoreMarginEdge &edge, float margin);
+
+    float getMargin(const WXCoreMarginEdge &edge)const;
+  };
+
+
+  /**
+   * Padding:padding-left、padding-right、padding-top、padding-bottom
+   */
+  class WXCorePadding {
+  private:
+    float mPaddingTop;
+    float mPaddingBottom;
+    float mPaddingLeft;
+    float mPaddingRight;
+
+  public:
+    WXCorePadding() : mPaddingTop(0),
+                      mPaddingBottom(0),
+                      mPaddingLeft(0),
+                      mPaddingRight(0) {}
+
+    ~WXCorePadding() {
+      mPaddingTop = 0;
+      mPaddingBottom = 0;
+      mPaddingLeft = 0;
+      mPaddingRight = 0;
+    }
+
+    bool setPadding(const WXCorePaddingEdge &edge, float padding);
+
+    float getPadding(const WXCorePaddingEdge &edge)const;
+  };
+
+
+  /**
+   * BorderWidth:borderwidth-left、borderwidth-right、borderwidth-top、borderwidth-bottom
+   */
+  class WXCoreBorderWidth {
+  private:
+    float mBorderWidthTop;
+    float mBorderWidthBottom;
+    float mBorderWidthLeft;
+    float mBorderWidthRight;
+
+  public:
+    WXCoreBorderWidth() : mBorderWidthTop(0),
+                          mBorderWidthBottom(0),
+                          mBorderWidthLeft(0),
+                          mBorderWidthRight(0) {}
+
+    ~WXCoreBorderWidth() {
+      mBorderWidthTop = 0;
+      mBorderWidthBottom = 0;
+      mBorderWidthLeft = 0;
+      mBorderWidthRight = 0;
+    }
+
+    bool setBorderWidth(const WXCoreBorderWidthEdge &edge, float borderWidth);
+
+    float getBorderWidth(const WXCoreBorderWidthEdge &edge)const;
+  };
+
+
+  /**
+   * position:left、right、top、bottom
+   */
+  class WXCorePosition {
+  private:
+    float mTop;
+    float mBottom;
+    float mLeft;
+    float mRight;
+
+  public:
+    WXCorePosition() : mTop(NAN),
+                       mBottom(NAN),
+                       mLeft(NAN),
+                       mRight(NAN) {}
+
+    ~WXCorePosition() {
+      reset();
+    }
+
+    inline bool isNAN() {
+      return isnan(mTop) || isnan(mBottom) || isnan(mLeft) || isnan(mRight);
+    }
+
+    inline void reset() {
+      mTop = 0;
+      mBottom = 0;
+      mLeft = 0;
+      mRight = 0;
+    }
+
+    bool setPosition(const WXCorePositionEdge &edge, float position);
+
+    float getPosition(const WXCorePositionEdge &edge);
+  };
+
+  enum DimensionLevel{
+    CSS_STYLE = 1,
+    INSTANCE_STYLE = 2,
+    FALLBACK_STYLE = 3
+  };
+
+  /**
+   * css-style
+   */
+  class WXCoreCSSStyle {
+  public:
+    /**
+     * The direction children items are placed inside the Flexbox layout, it determines the
+     * direction of the main axis (and the cross axis, perpendicular to the main axis).
+     * The default value is {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row}.
+     */
+    WXCoreFlexDirection mFlexDirection;
+
+    /**
+     * This attribute controls whether the flex container is single-line or multi-line, and the
+     * direction of the cross axis.
+     * <ul>
+     * <li>{@link WXCoreFlexWrap}: The flex container is single-line.</li>
+     * <li>{@link WXCoreFlexWrap}: The flex container is multi-line.</li>
+     * <li>{@link WXCoreFlexWrap}: The flex container is multi-line. The direction of the
+     * cross axis is opposed to the direction as the {@link WXCoreFlexWrap}</li>
+     * </ul>
+     * The default value is {@link WXCoreFlexWrap #WXCore_Wrap_NoWrap}.
+     */
+    WXCoreFlexWrap mFlexWrap;
+
+    /**
+     * This attribute controls the alignment along the main axis.
+     * The default value is {@link WXCoreJustifyContent #WXCore_Justify_Flex_Start}.
+     */
+    WXCoreJustifyContent mJustifyContent;
+
+    /**
+     * This attribute controls the alignment along the cross axis.
+     * The default value is {@link WXCoreAlignItems #WXCore_AlignItems_Stretch}.
+     */
+    WXCoreAlignItems mAlignItems;
+
+    /**
+     * This attribute controls the alignment along the cross axis.
+     * The default value is {@link WXCoreAlignSelf #WXCore_AlignSelf_Auto}.
+     */
+    WXCoreAlignSelf mAlignSelf;
+
+    WXCorePositionType mPositionType;
+
+    float mFlexGrow;
+
+    float mMinWidth;
+
+    float mMinHeight;
+
+    float mMaxWidth;
+
+    float mMaxHeight;
+
+    float mStyleWidth;
+
+    float mStyleHeight;
+
+    DimensionLevel mStyleWidthLevel;
+
+    DimensionLevel mStyleHeightLevel;
+
+    WXCoreMargin mMargin;
+
+    WXCorePadding mPadding;
+
+    WXCoreBorderWidth mBorderWidth;
+
+    WXCorePosition mStylePosition;
+
+    constexpr static float kFlexGrowDefault  = 0;
+
+    constexpr static WXCoreFlexDirection kFlexDirectionDefault= kFlexDirectionColumn;
+
+    constexpr static WXCoreFlexWrap kFlexWrapDefault = kNoWrap;
+
+    constexpr static WXCoreJustifyContent kFlexJustifyContentDefault = kJustifyFlexStart;
+
+    constexpr static WXCoreAlignItems kFlexAlignItemsDefault = kAlignItemsStretch;
+
+    constexpr static WXCoreAlignSelf kFlexAlignSelfDefault = kAlignSelfAuto;
+
+    constexpr static WXCorePositionType kWXCorePositionTypeDefault = kRelative;
+
+    WXCoreCSSStyle() : mFlexDirection(kFlexDirectionDefault),
+                       mFlexWrap(kFlexWrapDefault),
+                       mJustifyContent(kFlexJustifyContentDefault),
+                       mAlignItems(kFlexAlignItemsDefault),
+                       mAlignSelf(kFlexAlignSelfDefault),
+                       mFlexGrow(kFlexGrowDefault),
+                       mPositionType(kWXCorePositionTypeDefault),
+                       mStyleWidth(NAN), mStyleHeight(NAN),
+                       mStyleHeightLevel(FALLBACK_STYLE), mStyleWidthLevel(FALLBACK_STYLE),
+                       mMaxWidth(NAN), mMaxHeight(NAN),
+                       mMinWidth(NAN), mMinHeight(NAN) {
+
+    }
+
+    ~WXCoreCSSStyle() {
+      mFlexDirection = kFlexDirectionDefault;
+      mFlexWrap = kFlexWrapDefault;
+      mJustifyContent = kFlexJustifyContentDefault;
+      mAlignItems = kFlexAlignItemsDefault;
+      mAlignSelf = kFlexAlignSelfDefault;
+      mFlexGrow = kFlexGrowDefault;
+      mStyleWidth = NAN;
+      mStyleHeight = NAN;
+      mStyleWidthLevel = FALLBACK_STYLE;
+      mStyleHeightLevel = FALLBACK_STYLE;
+      mMaxWidth = NAN;
+      mMaxHeight = NAN;
+      mMinWidth = NAN;
+      mMinHeight = NAN;
+    }
+
+    inline float sumPaddingBorderOfEdge(const WXCoreEdge edge){
+      switch (edge) {
+        case kTop:
+          return mPadding.getPadding(kPaddingTop)
+              + mBorderWidth.getBorderWidth(kBorderWidthTop);
+        case kRight:
+          return mPadding.getPadding(kPaddingRight)
+              + mBorderWidth.getBorderWidth(kBorderWidthRight);
+        case kBottom:
+          return mPadding.getPadding(kPaddingBottom)
+              + mBorderWidth.getBorderWidth(kBorderWidthBottom);
+        case kLeft:
+          return mPadding.getPadding(kPaddingLeft)
+              + mBorderWidth.getBorderWidth(kBorderWidthLeft);
+      }
+    }
+
+    float sumMarginOfDirection(bool horizontal){
+      if(horizontal){
+        return mMargin.getMargin(kMarginLeft) + mMargin.getMargin(kMarginRight);
+      }
+      else{
+        return mMargin.getMargin(kMarginTop) + mMargin.getMargin(kMarginBottom);
+      }
+    }
+  };
+}
+#endif //WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUMS_H
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h b/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h
index 7670085..93f43e9 100644
--- a/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h
@@ -17,6 +17,9 @@
  * under the License.
  */
 
+#if defined __cplusplus
+extern "C" {
+#endif
 
 #define WX_LAYOUT_NAMESPACE wx_
 
@@ -53,5 +56,8 @@
 
 #import "Layout.h"
 
+#if defined __cplusplus
+};
+#endif
 
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.h b/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.h
new file mode 100644
index 0000000..c9b633f
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.h
@@ -0,0 +1,42 @@
+/*
+ * 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 "WXScrollerComponent.h"
+#import "WXComponent+Layout.h"
+
+
+@interface WXScrollerComponent ()
+{
+//#ifndef USE_FLEX
+    css_node_t *_scrollerCSSNode;
+//#else
+    WeexCore::WXCoreLayoutNode *_flexScrollerCSSNode;
+//#endif
+}
+@end
+
+@interface WXScrollerComponent (FlexLayout)
+
+//#ifndef USE_FLEX
+@property (nonatomic, readonly, assign) css_node_t *scrollerCSSNode;
+//#else
+@property (nonatomic, readonly, assign) WeexCore::WXCoreLayoutNode *flexScrollerCSSNode;
+//#endif
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.mm b/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.mm
new file mode 100644
index 0000000..6eb8c9d
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.mm
@@ -0,0 +1,53 @@
+/*
+ * 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 "WXScrollerComponent+Layout.h"
+#import "WXLog.h"
+
+@implementation WXScrollerComponent (FlexLayout)
+
+//#ifndef USE_FLEX
+- (css_node_t *)scrollerCSSNode
+{
+    return _scrollerCSSNode;
+}
+//#else
+- (WeexCore::WXCoreLayoutNode *)flexScrollerCSSNode{
+    return _flexScrollerCSSNode;
+}
+
+- (void)_insertChildCssNode:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    self.flexScrollerCSSNode->addChildAt(subcomponent.flexCssNode, (uint32_t) index);
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> ref:%@,subNodeIndex:%ld,childCount:%ld",self.ref,(long)index,_flexScrollerCSSNode->getChildCount());
+#endif
+   
+//    WXLogInfo(@"FlexLayout -- P:%@ -> C:%@",self,subcomponent);
+}
+- (void)_rmChildCssNode:(WXComponent *)subcomponent
+{
+    self.flexScrollerCSSNode->removeChild(subcomponent->_flexCssNode);
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> ref:%@ ,scrollerCSSNode->removeChild ,childRef:%@",self.ref,subcomponent.ref);
+#endif
+}
+
+//#endif
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
deleted file mode 100644
index 175aeb7..0000000
--- a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
+++ /dev/null
@@ -1,958 +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 "WXComponentManager.h"
-#import "WXComponent.h"
-#import "WXComponent_internal.h"
-#import "WXComponent+DataBinding.h"
-#import "WXComponentFactory.h"
-#import "WXDefine.h"
-#import "NSArray+Weex.h"
-#import "WXSDKInstance.h"
-#import "WXAssert.h"
-#import "WXUtility.h"
-#import "WXMonitor.h"
-#import "WXScrollerProtocol.h"
-#import "WXSDKManager.h"
-#import "WXSDKError.h"
-#import "WXInvocationConfig.h"
-#import "WXHandlerFactory.h"
-#import "WXValidateProtocol.h"
-#import "WXPrerenderManager.h"
-#import "WXTracingManager.h"
-#import "WXLayoutDefine.h"
-#import "WXSDKInstance_performance.h"
-#import "WXRootView.h"
-
-static NSThread *WXComponentThread;
-
-#define WXAssertComponentExist(component)  WXAssert(component, @"component not exists")
-
-@implementation WXComponentManager
-{
-    __weak WXSDKInstance *_weexInstance;
-    BOOL _isValid;
-    
-    BOOL _stopRunning;
-    NSUInteger _noTaskTickCount;
-    
-    // access only on component thread
-    NSMapTable<NSString *, WXComponent *> *_indexDict;
-    NSMutableArray<dispatch_block_t> *_uiTaskQueue;
-    NSMutableDictionary *_uiPrerenderTaskQueue;
-
-    WXComponent *_rootComponent;
-    NSMutableArray *_fixedComponents;
-    
-    css_node_t *_rootCSSNode;
-    CADisplayLink *_displayLink;
-}
-
-+ (instancetype)sharedManager
-{
-    static id _sharedInstance = nil;
-    static dispatch_once_t oncePredicate;
-    dispatch_once(&oncePredicate, ^{
-        _sharedInstance = [[self alloc] init];
-    });
-    return _sharedInstance;
-}
-
-- (instancetype)initWithWeexInstance:(id)weexInstance
-{
-    if (self = [self init]) {
-        _weexInstance = weexInstance;
-        
-        _indexDict = [NSMapTable strongToWeakObjectsMapTable];
-        _fixedComponents = [NSMutableArray wx_mutableArrayUsingWeakReferences];
-        _uiTaskQueue = [NSMutableArray array];
-        _isValid = YES;
-        [self _startDisplayLink];
-    }
-    
-    return self;
-}
-
-- (void)dealloc
-{
-    free_css_node(_rootCSSNode);
-    [NSMutableArray wx_releaseArray:_fixedComponents];
-}
-
-#pragma mark Thread Management
-
-+ (NSThread *)componentThread
-{
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        WXComponentThread = [[NSThread alloc] initWithTarget:[self sharedManager] selector:@selector(_runLoopThread) object:nil];
-        [WXComponentThread setName:WX_COMPONENT_THREAD_NAME];
-        if(WX_SYS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
-            [WXComponentThread setQualityOfService:[[NSThread mainThread] qualityOfService]];
-        } else {
-            [WXComponentThread setThreadPriority:[[NSThread mainThread] threadPriority]];
-        }
-        
-        [WXComponentThread start];
-    });
-    
-    return WXComponentThread;
-}
-
-- (void)_runLoopThread
-{
-    [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
-    
-    while (!_stopRunning) {
-        @autoreleasepool {
-            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
-        }
-    }
-}
-
-+ (void)_performBlockOnComponentThread:(void (^)(void))block
-{
-    if([NSThread currentThread] == [self componentThread]){
-        block();
-    } else {
-        [self performSelector:@selector(_performBlockOnComponentThread:)
-                     onThread:WXComponentThread
-                   withObject:[block copy]
-                waitUntilDone:NO];
-    }
-}
-
-+ (void)_performBlockSyncOnComponentThread:(void (^)(void))block
-{
-    if([NSThread currentThread] == [self componentThread]){
-        block();
-    } else {
-        [self performSelector:@selector(_performBlockOnComponentThread:)
-                     onThread:WXComponentThread
-                   withObject:[block copy]
-                waitUntilDone:YES];
-    }
-}
-
-- (void)startComponentTasks
-{
-    [self _awakeDisplayLink];
-}
-
-- (void)rootViewFrameDidChange:(CGRect)frame
-{
-    WXAssertComponentThread();
-    
-    if (_rootCSSNode) {
-        [self _applyRootFrame:frame toRootCSSNode:_rootCSSNode];
-        if (!_rootComponent.styles[@"width"]) {
-            _rootComponent.cssNode->style.dimensions[CSS_WIDTH] = frame.size.width ?: CSS_UNDEFINED;
-        }
-        if (!_rootComponent.styles[@"height"]) {
-            _rootComponent.cssNode->style.dimensions[CSS_HEIGHT] = frame.size.height ?: CSS_UNDEFINED;
-        }
-        [_rootComponent setNeedsLayout];
-        [self startComponentTasks];
-    }
-}
-
-- (void)_applyRootFrame:(CGRect)rootFrame toRootCSSNode:(css_node_t *)rootCSSNode
-{
-    _rootCSSNode->style.position[CSS_LEFT] = self.weexInstance.frame.origin.x;
-    _rootCSSNode->style.position[CSS_TOP] = self.weexInstance.frame.origin.y;
-    
-    // if no instance width/height, use layout width/height, as Android's wrap_content
-    _rootCSSNode->style.dimensions[CSS_WIDTH] = self.weexInstance.frame.size.width ?: CSS_UNDEFINED;
-    _rootCSSNode->style.dimensions[CSS_HEIGHT] =  self.weexInstance.frame.size.height ?: CSS_UNDEFINED;
-}
-
-- (void)_addUITask:(void (^)(void))block
-{
-    if(!_uiPrerenderTaskQueue){
-        _uiPrerenderTaskQueue = [NSMutableDictionary new];
-    }
-    if(self.weexInstance.needPrerender){
-        NSMutableArray<dispatch_block_t> *tasks  = [_uiPrerenderTaskQueue objectForKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
-        if(!tasks){
-            tasks = [NSMutableArray new];
-        }
-        [tasks addObject:block];
-        [_uiPrerenderTaskQueue setObject:tasks forKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
-    }else{
-        [_uiTaskQueue addObject:block];
-    }
-}
-
-- (void)excutePrerenderUITask:(NSString *)url
-{
-    NSMutableArray *tasks  = [_uiPrerenderTaskQueue objectForKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
-    for (id block in tasks) {
-        [_uiTaskQueue addObject:block];
-    }
-    tasks = [NSMutableArray new];
-    [_uiPrerenderTaskQueue setObject:tasks forKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
-}
-
-#pragma mark Component Tree Building
-
-- (void)createRoot:(NSDictionary *)data
-{
-    WXAssertComponentThread();
-    WXAssertParam(data);
-    
-    _rootComponent = [self _buildComponentForData:data supercomponent:nil];
-    
-    [self _initRootCSSNode];
-    
-    NSArray *subcomponentsData = [data valueForKey:@"children"];
-    if (subcomponentsData) {
-        BOOL appendTree = [_rootComponent.attributes[@"append"] isEqualToString:@"tree"];
-        for(NSDictionary *subcomponentData in subcomponentsData){
-            [self _recursivelyAddComponent:subcomponentData toSupercomponent:_rootComponent atIndex:-1 appendingInTree:appendTree];
-        }
-    }
-    
-    __weak typeof(self) weakSelf = self;
-    WX_MONITOR_INSTANCE_PERF_END(WXFirstScreenJSFExecuteTime, self.weexInstance);
-    [self _addUITask:^{
-        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:data[@"ref"] className:nil name:data[@"type"] phase:WXTracingBegin functionName:@"createBody" options:@{@"threadName":WXTUIThread}];
-        __strong typeof(self) strongSelf = weakSelf;
-        strongSelf.weexInstance.rootView.wx_component = strongSelf->_rootComponent;
-        [strongSelf.weexInstance.rootView addSubview:strongSelf->_rootComponent.view];
-        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:data[@"ref"] className:nil name:data[@"type"] phase:WXTracingEnd functionName:@"createBody" options:@{@"threadName":WXTUIThread}];
-    }];
-    
-    
-}
-
-static bool rootNodeIsDirty(void *context)
-{
-    WXComponentManager *manager = (__bridge WXComponentManager *)(context);
-    return [manager->_rootComponent needsLayout];
-}
-
-static css_node_t * rootNodeGetChild(void *context, int i)
-{
-    WXComponentManager *manager = (__bridge WXComponentManager *)(context);
-    if (i == 0) {
-        return manager->_rootComponent.cssNode;
-    } else if(manager->_fixedComponents.count >= i) {
-        return ((WXComponent *)((manager->_fixedComponents)[i-1])).cssNode;
-    }
-    
-    return NULL;
-}
-
-- (void)addComponent:(NSDictionary *)componentData toSupercomponent:(NSString *)superRef atIndex:(NSInteger)index appendingInTree:(BOOL)appendingInTree
-{
-    WXAssertComponentThread();
-    WXAssertParam(componentData);
-    WXAssertParam(superRef);
-    
-    WXComponent *supercomponent = [_indexDict objectForKey:superRef];
-    WXAssertComponentExist(supercomponent);
-    
-    [self _recursivelyAddComponent:componentData toSupercomponent:supercomponent atIndex:index appendingInTree:appendingInTree];
-}
-
-- (void)_recursivelyAddComponent:(NSDictionary *)componentData toSupercomponent:(WXComponent *)supercomponent atIndex:(NSInteger)index appendingInTree:(BOOL)appendingInTree
-{
-    WXComponent *component = [self _buildComponentForData:componentData supercomponent:supercomponent];
-    if (!supercomponent.subcomponents) {
-        index = 0;
-    } else {
-        index = (index == -1 ? supercomponent->_subcomponents.count : index);
-    }
-    
-    [supercomponent _insertSubcomponent:component atIndex:index];
-    // use _lazyCreateView to forbid component like cell's view creating
-    if(supercomponent && component && supercomponent->_lazyCreateView) {
-        component->_lazyCreateView = YES;
-    }
-    
-    [self recordMaximumVirtualDom:component];
-    
-    if (!component->_isTemplate) {
-        __weak typeof(self) weakSelf = self;
-        BOOL isFSCreateFinish = [self weexInstance].isJSCreateFinish;
-        [self _addUITask:^{
-            [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:componentData[@"ref"] className:nil name:componentData[@"type"] phase:WXTracingBegin functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
-            [supercomponent insertSubview:component atIndex:index];
-            [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:componentData[@"ref"] className:nil name:componentData[@"type"] phase:WXTracingEnd functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
-            [weakSelf onElementChange:isFSCreateFinish];
-        }];
-    }
-    
-    NSArray *subcomponentsData = [componentData valueForKey:@"children"];
-    
-    BOOL appendTree = !appendingInTree && [component.attributes[@"append"] isEqualToString:@"tree"];
-    // if ancestor is appending tree, child should not be laid out again even it is appending tree.
-    for(NSDictionary *subcomponentData in subcomponentsData){
-        [self _recursivelyAddComponent:subcomponentData toSupercomponent:component atIndex:-1 appendingInTree:appendTree || appendingInTree];
-    }
-    
-    [component _didInserted];
-    
-    if (appendTree) {
-        // If appending tree,force layout in case of too much tasks piling up in syncQueue
-        [self _layoutAndSyncUI];
-    }
-}
-
-- (void)moveComponent:(NSString *)ref toSuper:(NSString *)superRef atIndex:(NSInteger)index
-{
-    WXAssertComponentThread();
-    WXAssertParam(ref);
-    WXAssertParam(superRef);
-    
-    WXComponent *component = [_indexDict objectForKey:ref];
-    WXComponent *newSupercomponent = [_indexDict objectForKey:superRef];
-    WXAssertComponentExist(component);
-    WXAssertComponentExist(newSupercomponent);
-    
-    if (component.supercomponent == newSupercomponent && [newSupercomponent.subcomponents indexOfObject:component] < index) {
-        // if the supercomponent moved to is the same as original supercomponent,
-        // unify it into the index after removing.
-        index--;
-    }
-    
-    [component _moveToSupercomponent:newSupercomponent atIndex:index];
-    __weak typeof(self) weakSelf = self;
-    [self _addUITask:^{
-        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
-        [component moveToSuperview:newSupercomponent atIndex:index];
-        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
-    }];
-}
-
-- (void)removeComponent:(NSString *)ref
-{
-    WXAssertComponentThread();
-    WXAssertParam(ref);
-    
-    WXComponent *component = [_indexDict objectForKey:ref];
-    WXAssertComponentExist(component);
-    
-    [component _removeFromSupercomponent];
-    
-    [_indexDict removeObjectForKey:ref];
-    
-    __weak typeof(self) weakSelf = self;
-    BOOL isFSCreateFinish = [self weexInstance].isJSCreateFinish;
-    [self _addUITask:^{
-        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"removeElement" options:@{@"threadName":WXTUIThread}];
-        if (component.supercomponent) {
-            [component.supercomponent willRemoveSubview:component];
-        }
-        [component removeFromSuperview];
-        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"removeElement" options:@{@"threadName":WXTUIThread}];
-        [weakSelf onElementChange:isFSCreateFinish];
-    }];
-    
-    [self _checkFixedSubcomponentToRemove:component];
-    
-}
-
-- (void)onElementChange:(BOOL)isFSCreateFinish
-{
-    if (!isFSCreateFinish) {
-        return;
-    }
-    
-    UIView *root = [self weexInstance].rootView;
-    BOOL hasEvent = TRUE;
-    if (root && [root isKindOfClass:[WXRootView class]]) {
-        WXRootView* wxRootView = (WXRootView *)root;
-        hasEvent = [wxRootView isHasEvent];
-    }
-    if (hasEvent) {
-        return;
-    }
-    double current = CACurrentMediaTime()*1000;
-    
-    double diff =  current - [self weexInstance].performance.jsCreateFinishTime;
-    if (diff > 8000) {
-        return;
-    }
-    [self weexInstance].performance.interactionTime = current - self.weexInstance.performance.renderTimeOrigin;
-}
-
-- (void)recordMaximumVirtualDom:(WXComponent*) component
-{
-    WXAssertComponentExist(component);
-    if(!component){
-        return;
-    }
-    int maxDeep =0;
-    while (component) {
-        maxDeep++;
-        component = component.supercomponent;
-    }
-    if(maxDeep > [self weexInstance].performance.maxVdomDeep)
-    {
-        [self weexInstance].performance.maxVdomDeep = maxDeep;
-    }
-   
-}
-
-- (void)_checkFixedSubcomponentToRemove:(WXComponent *)component
-{
-    for (WXComponent *subcomponent in component.subcomponents) {
-        if (subcomponent->_positionType == WXPositionTypeFixed) {
-             [self _addUITask:^{
-                 [subcomponent removeFromSuperview];
-             }];
-        }
-        
-        [self _checkFixedSubcomponentToRemove:subcomponent];
-    }
-}
-
-- (WXComponent *)componentForRef:(NSString *)ref
-{
-    WXAssertComponentThread();
-    
-    return [_indexDict objectForKey:ref];
-}
-
-- (WXComponent *)componentForRoot
-{
-    return _rootComponent;
-}
-
-- (NSUInteger)numberOfComponents
-{
-    WXAssertComponentThread();
-    
-    return _indexDict.count;
-}
-
-- (WXComponent *)_buildComponentForData:(NSDictionary *)data supercomponent:(WXComponent *)supercomponent
-{
-    NSString *ref = data[@"ref"];
-    NSString *type = data[@"type"];
-    NSDictionary *styles = data[@"style"];
-    NSDictionary *attributes = data[@"attr"];
-    NSArray *events = data[@"event"];
-    
-    if (self.weexInstance.needValidate) {
-        id<WXValidateProtocol> validateHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXValidateProtocol)];
-        if (validateHandler) {
-            WXComponentValidateResult* validateResult;
-            if ([validateHandler respondsToSelector:@selector(validateWithWXSDKInstance:component:supercomponent:)]) {
-                validateResult = [validateHandler validateWithWXSDKInstance:self.weexInstance component:type supercomponent:supercomponent];
-            }
-            if (validateResult==nil || !validateResult.isSuccess) {
-                type = validateResult.replacedComponent? validateResult.replacedComponent : @"div";
-                WXLogError(@"%@",[validateResult.error.userInfo objectForKey:@"errorMsg"]);
-            }
-        }
-    }
-    
-    WXComponentConfig *config = [WXComponentFactory configWithComponentName:type];
-    BOOL isTemplate = [config.properties[@"isTemplate"] boolValue] || (supercomponent && supercomponent->_isTemplate);
-    NSDictionary *bindingStyles;
-    NSDictionary *bindingAttibutes;
-    NSDictionary *bindingEvents;
-    NSDictionary *bindingProps;
-    if (isTemplate) {
-        bindingProps = [self _extractBindingProps:&attributes];
-        bindingStyles = [self _extractBindings:&styles];
-        bindingAttibutes = [self _extractBindings:&attributes];
-        bindingEvents = [self _extractBindingEvents:&events];
-    }
-    
-    Class clazz = NSClassFromString(config.clazz);;
-    WXComponent *component = [[clazz alloc] initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:self.weexInstance];
-    if (isTemplate) {
-        component->_isTemplate = YES;
-        [component _storeBindingsWithProps:bindingProps styles:bindingStyles attributes:bindingAttibutes events:bindingEvents];
-    }
-
-    WXAssert(component, @"Component build failed for data:%@", data);
-    
-    [_indexDict setObject:component forKey:component.ref];
-    [component readyToRender];// notify redyToRender event when init
-    return component;
-}
-
-- (void)addComponent:(WXComponent *)component toIndexDictForRef:(NSString *)ref
-{
-    [_indexDict setObject:component forKey:ref];
-}
-
-- (NSDictionary *)_extractBindings:(NSDictionary **)attributesOrStylesPoint
-{
-    NSDictionary *attributesOrStyles = *attributesOrStylesPoint;
-    if (!attributesOrStyles) {
-        return nil;
-    }
-    
-    NSMutableDictionary *newAttributesOrStyles = [attributesOrStyles mutableCopy];
-    NSMutableDictionary *bindingAttributesOrStyles = [NSMutableDictionary dictionary];
-    
-    [attributesOrStyles enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull attributeOrStyleName, id  _Nonnull attributeOrStyle, BOOL * _Nonnull stop) {
-        if ([WXBindingMatchIdentify isEqualToString:attributeOrStyleName] // match
-            ||  [WXBindingRepeatIdentify isEqualToString:attributeOrStyleName] // repeat
-            ||  [WXBindingOnceIdentify isEqualToString:attributeOrStyleName] // once
-            ||([attributeOrStyle isKindOfClass:[NSDictionary class]] && attributeOrStyle[WXBindingIdentify])) {  // {"attributeOrStyleName": {"@binding":"bindingExpression"}
-            bindingAttributesOrStyles[attributeOrStyleName] = attributeOrStyle;
-            [newAttributesOrStyles removeObjectForKey:attributeOrStyleName];
-        } else if ([attributeOrStyle isKindOfClass:[NSArray class]]) {
-            // {"attributeOrStyleName":[..., "string", {"@binding":"bindingExpression"}, "string", {"@binding":"bindingExpression"}, ...]
-            __block BOOL isBinding = NO;
-            [attributeOrStyle enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
-                if ([obj isKindOfClass:[NSDictionary class]] && obj[WXBindingIdentify]) {
-                    isBinding = YES;
-                    *stop = YES;
-                }
-            }];
-            
-            if (isBinding) {
-                bindingAttributesOrStyles[attributeOrStyleName] = attributeOrStyle;
-                [newAttributesOrStyles removeObjectForKey:attributeOrStyleName];
-            }
-        }
-    }];
-    
-    *attributesOrStylesPoint = newAttributesOrStyles;
-    
-    return bindingAttributesOrStyles;
-}
-
-- (NSDictionary *)_extractBindingEvents:(NSArray **)eventsPoint
-{
-    NSArray *events = *eventsPoint;
-    NSMutableArray *newEvents = [events mutableCopy];
-    NSMutableDictionary *bindingEvents = [NSMutableDictionary dictionary];
-    [events enumerateObjectsUsingBlock:^(id  _Nonnull event, NSUInteger idx, BOOL * _Nonnull stop) {
-        if ([event isKindOfClass:[NSDictionary class]] && event[@"type"] && event[@"params"]) {
-            NSString *eventName = event[@"type"];
-            NSString *bindingParams = event[@"params"];
-            bindingEvents[eventName] = bindingParams;
-            newEvents[idx] = eventName;
-        }
-    }];
-    
-    *eventsPoint = newEvents;
-    return bindingEvents;
-}
-
-- (NSDictionary *)_extractBindingProps:(NSDictionary **)attributesPoint
-{
-    NSDictionary *attributes = *attributesPoint;
-    if (attributes[@"@componentProps"]) {
-        NSMutableDictionary *newAttributes = [attributes mutableCopy];
-        [newAttributes removeObjectForKey:@"@componentProps"];
-        *attributesPoint = newAttributes;
-        return attributes[@"@componentProps"];
-    }
-    
-    return nil;
-}
-
-#pragma mark Reset
--(BOOL)isShouldReset:(id )value
-{
-    if([value isKindOfClass:[NSString class]]) {
-        if(!value || [@"" isEqualToString:value]) {
-            return YES;
-        }
-    }
-    return NO;
-}
-
--(void)filterStyles:(NSDictionary *)styles normalStyles:(NSMutableDictionary *)normalStyles resetStyles:(NSMutableArray *)resetStyles
-{
-    for (NSString *key in styles) {
-        id value = [styles objectForKey:key];
-        if([self isShouldReset:value]) {
-            [resetStyles addObject:key];
-        }else{
-            [normalStyles setObject:styles[key] forKey:key];
-        }
-    }
-}
-
-- (void)updateStyles:(NSDictionary *)styles forComponent:(NSString *)ref
-{
-    [self handleStyles:styles forComponent:ref isUpdateStyles:YES];
-}
-
-- (void)updatePseudoClassStyles:(NSDictionary *)styles forComponent:(NSString *)ref
-{
-    [self handleStyles:styles forComponent:ref isUpdateStyles:NO];
-}
-
-- (void)handleStyleOnMainThread:(NSDictionary*)styles forComponent:(WXComponent *)component isUpdateStyles:(BOOL)isUpdateStyles
-{
-    WXAssertParam(styles);
-    WXAssertParam(component);
-    WXAssertMainThread();
-    
-    NSMutableDictionary *normalStyles = [NSMutableDictionary new];
-    NSMutableArray *resetStyles = [NSMutableArray new];
-    [self filterStyles:styles normalStyles:normalStyles resetStyles:resetStyles];
-    [component _updateStylesOnMainThread:normalStyles resetStyles:resetStyles];
-    [component readyToRender];
-    
-    WXPerformBlockOnComponentThread(^{
-        [component _updateStylesOnComponentThread:normalStyles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
-    });
-}
-
-- (void)handleStyles:(NSDictionary *)styles forComponent:(NSString *)ref isUpdateStyles:(BOOL)isUpdateStyles
-{
-    WXAssertParam(styles);
-    WXAssertParam(ref);
-    
-    WXComponent *component = [_indexDict objectForKey:ref];
-    WXAssertComponentExist(component);
-    
-    NSMutableDictionary *normalStyles = [NSMutableDictionary new];
-    NSMutableArray *resetStyles = [NSMutableArray new];
-    [self filterStyles:styles normalStyles:normalStyles resetStyles:resetStyles];
-    [component _updateStylesOnComponentThread:normalStyles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
-    [self _addUITask:^{
-        [component _updateStylesOnMainThread:normalStyles resetStyles:resetStyles];
-        [component readyToRender];
-    }];
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes forComponent:(NSString *)ref
-{
-    WXAssertParam(attributes);
-    WXAssertParam(ref);
-    
-    WXComponent *component = [_indexDict objectForKey:ref];
-    WXAssertComponentExist(component);
-    
-    [component _updateAttributesOnComponentThread:attributes];
-    __weak typeof(self) weakSelf = self;
-    [self _addUITask:^{
-        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"updateAttrs" options:@{@"threadName":WXTUIThread}];
-        [component _updateAttributesOnMainThread:attributes];
-        [component readyToRender];
-        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"updateAttrs" options:@{@"threadName":WXTUIThread}];
-    }];
-}
-
-- (void)addEvent:(NSString *)eventName toComponent:(NSString *)ref
-{
-    WXAssertComponentThread();
-    WXAssertParam(eventName);
-    WXAssertParam(ref);
-    
-    WXComponent *component = [_indexDict objectForKey:ref];
-    WXAssertComponentExist(component);
-    
-    [component _addEventOnComponentThread:eventName];
-    
-    [self _addUITask:^{
-        [component _addEventOnMainThread:eventName];
-    }];
-}
-
-- (void)removeEvent:(NSString *)eventName fromComponent:(NSString *)ref
-{
-    WXAssertComponentThread();
-    WXAssertParam(eventName);
-    WXAssertParam(ref);
-    
-    WXComponent *component = [_indexDict objectForKey:ref];
-    WXAssertComponentExist(component);
-    
-    [component _removeEventOnComponentThread:eventName];
-    
-    [self _addUITask:^{
-        [component _removeEventOnMainThread:eventName];
-    }];
-}
-
-- (void)scrollToComponent:(NSString *)ref options:(NSDictionary *)options
-{
-    WXAssertComponentThread();
-    WXAssertParam(ref);
-    
-    WXComponent *toComponent = [_indexDict objectForKey:ref];
-    WXAssertComponentExist(toComponent);
-
-    id<WXScrollerProtocol> scrollerComponent = toComponent.ancestorScroller;
-    if (!scrollerComponent) {
-        return;
-    }
-
-    CGFloat offset = [[options objectForKey:@"offset"] floatValue];
-    BOOL animated = YES;
-    if ([options objectForKey:@"animated"]) {
-        animated = [[options objectForKey:@"animated"] boolValue];
-    }
-    
-    [self _addUITask:^{
-        [scrollerComponent scrollToComponent:toComponent withOffset:offset animated:animated];
-    }];
-}
-
-#pragma mark Life Cycle
-
-- (void)createFinish
-{
-    WXAssertComponentThread();
-    
-    WXSDKInstance *instance  = self.weexInstance;
-    [self _addUITask:^{
-        UIView *rootView = instance.rootView;
-        
-        //WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, instance);
-        WX_MONITOR_INSTANCE_PERF_END(WXPTAllRender, instance);
-        WX_MONITOR_SUCCESS(WXMTJSBridge);
-        WX_MONITOR_SUCCESS(WXMTNativeRender);
-        
-        if(instance.renderFinish){
-            [WXTracingManager startTracingWithInstanceId:instance.instanceId ref:nil className:nil name:nil phase:WXTracingInstant functionName:WXTRenderFinish options:@{@"threadName":WXTUIThread}];
-            instance.renderFinish(rootView);
-        }
-    }];
-    [instance updatePerDicAfterCreateFinish];
-}
-
-- (void)updateFinish
-{
-    WXAssertComponentThread();
-    
-    WXSDKInstance *instance = self.weexInstance;
-    WXComponent *root = [_indexDict objectForKey:WX_SDK_ROOT_REF];
-    
-    [self _addUITask:^{
-        if(instance.updateFinish){
-            instance.updateFinish(root.view);
-        }
-    }];
-}
-
-- (void)refreshFinish
-{
-    WXAssertComponentThread();
-    
-    WXSDKInstance *instance = self.weexInstance;
-    WXComponent *root = [_indexDict objectForKey:WX_SDK_ROOT_REF];
-    
-    [self _addUITask:^{
-        if(instance.refreshFinish){
-            instance.refreshFinish(root.view);
-        }
-    }];
-}
-
-- (void)unload
-{
-    WXAssertComponentThread();
-    [self invalidate];
-    [self _stopDisplayLink];
-    NSEnumerator *enumerator = [[_indexDict copy] objectEnumerator];
-    dispatch_async(dispatch_get_main_queue(), ^{
-        WXComponent *component;
-        while ((component = [enumerator nextObject])) {
-            [component _unloadViewWithReusing:NO];
-        }
-        _rootComponent = nil;
-    });
-    
-    [_indexDict removeAllObjects];
-    [_uiTaskQueue removeAllObjects];
-}
-
-- (void)invalidate
-{
-    _isValid = NO;
-}
-
-- (BOOL)isValid
-{
-    return _isValid;
-}
-
-#pragma mark Layout Batch
-
-- (void)_startDisplayLink
-{
-    WXAssertComponentThread();
-    
-    if(!_displayLink){
-        _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleDisplayLink)];
-        [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-    }
-}
-
-- (void)_stopDisplayLink
-{
-    WXAssertComponentThread();
-    
-    if(_displayLink){
-        [_displayLink invalidate];
-        _displayLink = nil;
-    }
-}
-
-- (void)_suspendDisplayLink
-{
-    WXAssertComponentThread();
-    
-    if(_displayLink && !_displayLink.paused) {
-        _displayLink.paused = YES;
-    }
-}
-
-- (void)_awakeDisplayLink
-{
-    WXAssertComponentThread();
-    
-    if(_displayLink && _displayLink.paused) {
-        _displayLink.paused = NO;
-    }
-}
-
-- (void)_handleDisplayLink
-{
-    WXAssertComponentThread();
-    
-    [self _layoutAndSyncUI];
-}
-
-- (void)_layoutAndSyncUI
-{
-    [self _layout];
-    if(_uiTaskQueue.count > 0){
-        [self _syncUITasks];
-        _noTaskTickCount = 0;
-    } else {
-        // suspend display link when there's no task for 1 second, in order to save CPU time.
-        _noTaskTickCount ++;
-        if (_noTaskTickCount > 60) {
-            [self _suspendDisplayLink];
-        }
-    }
-}
-
-- (void)_layout
-{
-    BOOL needsLayout = NO;
-
-    NSEnumerator *enumerator = [_indexDict objectEnumerator];
-    WXComponent *component;
-    while ((component = [enumerator nextObject])) {
-        if ([component needsLayout]) {
-            needsLayout = YES;
-            break;
-        }
-    }
-
-    if (!needsLayout) {
-        return;
-    }
-    
-    layoutNode(_rootCSSNode, _rootCSSNode->style.dimensions[CSS_WIDTH], _rootCSSNode->style.dimensions[CSS_HEIGHT], CSS_DIRECTION_INHERIT);
-    
-    if ([_rootComponent needsLayout]) {
-        if ([WXLog logLevel] >= WXLogLevelDebug) {
-            print_css_node(_rootCSSNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
-        }
-    }
-    
-    NSMutableSet<WXComponent *> *dirtyComponents = [NSMutableSet set];
-    [_rootComponent _calculateFrameWithSuperAbsolutePosition:CGPointZero gatherDirtyComponents:dirtyComponents];
-    [self _calculateRootFrame];
-  
-    for (WXComponent *dirtyComponent in dirtyComponents) {
-        [self _addUITask:^{
-            [dirtyComponent _layoutDidFinish];
-        }];
-    }
-}
-
-- (void)_syncUITasks
-{
-    NSArray<dispatch_block_t> *blocks = _uiTaskQueue;
-    _uiTaskQueue = [NSMutableArray array];
-    dispatch_async(dispatch_get_main_queue(), ^{
-        for(dispatch_block_t block in blocks) {
-            block();
-        }
-    });
-}
-
-- (void)_initRootCSSNode
-{
-    _rootCSSNode = new_css_node();
-    
-    [self _applyRootFrame:self.weexInstance.frame toRootCSSNode:_rootCSSNode];
-    
-    _rootCSSNode->style.flex_wrap = CSS_NOWRAP;
-    _rootCSSNode->is_dirty = rootNodeIsDirty;
-    _rootCSSNode->get_child = rootNodeGetChild;
-    _rootCSSNode->context = (__bridge void *)(self);
-    _rootCSSNode->children_count = 1;
-}
-
-- (void)_calculateRootFrame
-{
-    if (!_rootCSSNode->layout.should_update) {
-        return;
-    }
-    _rootCSSNode->layout.should_update = false;
-    
-    CGRect frame = CGRectMake(WXRoundPixelValue(_rootCSSNode->layout.position[CSS_LEFT]),
-                              WXRoundPixelValue(_rootCSSNode->layout.position[CSS_TOP]),
-                              WXRoundPixelValue(_rootCSSNode->layout.dimensions[CSS_WIDTH]),
-                              WXRoundPixelValue(_rootCSSNode->layout.dimensions[CSS_HEIGHT]));
-    WXPerformBlockOnMainThread(^{
-        if(!self.weexInstance.isRootViewFrozen) {
-            self.weexInstance.rootView.frame = frame;
-        }
-    });
-    
-    resetNodeLayout(_rootCSSNode);
-}
-
-
-#pragma mark Fixed 
-
-- (void)addFixedComponent:(WXComponent *)fixComponent
-{
-    [_fixedComponents addObject:fixComponent];
-    _rootCSSNode->children_count = (int)[_fixedComponents count] + 1;
-}
-
-- (void)removeFixedComponent:(WXComponent *)fixComponent
-{
-    [_fixedComponents removeObject:fixComponent];
-    _rootCSSNode->children_count = (int)[_fixedComponents count] + 1;
-}
-
-@end
-
-void WXPerformBlockOnComponentThread(void (^block)(void))
-{
-    [WXComponentManager _performBlockOnComponentThread:block];
-}
-
-void WXPerformBlockSyncOnComponentThread(void (^block)(void))
-{
-    [WXComponentManager _performBlockSyncOnComponentThread:block];
-}


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

Posted by ac...@apache.org.
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 .
  *


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
index b76ac90..e50e15a 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -136,6 +136,9 @@ _Pragma("clang diagnostic pop") \
         }
         [WXTracingManager startTracingWithInstanceId:instanceId ref:elementData[@"ref"] className:nil name:WXTJSCall phase:WXTracingEnd functionName:@"addElement" options:nil];
         WXPerformBlockOnComponentThread(^{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action: addElement : %@",elementData[@"type"]);
+#endif
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -159,6 +162,9 @@ _Pragma("clang diagnostic pop") \
         }
         [WXTracingManager startTracingWithInstanceId:instanceId ref:bodyData[@"ref"] className:nil name:WXTJSCall phase:WXTracingEnd functionName:@"createBody" options:@{@"threadName":WXTJSBridgeThread}];
         WXPerformBlockOnComponentThread(^{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action: createBody %@ ref:%@",bodyData[@"type"],bodyData[@"ref"]);
+#endif
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -183,6 +189,9 @@ _Pragma("clang diagnostic pop") \
         }
         [WXTracingManager startTracingWithInstanceId:instanceId ref:ref className:nil name:WXTJSCall phase:WXTracingEnd functionName:@"removeElement" options:nil];
         WXPerformBlockOnComponentThread(^{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action: removeElement ref:%@",ref);
+#endif
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -206,6 +215,9 @@ _Pragma("clang diagnostic pop") \
         }
         [WXTracingManager startTracingWithInstanceId:instanceId ref:ref className:nil name:WXTJSCall phase:WXTracingEnd functionName:@"moveElement" options:nil];
         WXPerformBlockOnComponentThread(^{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action: moveElement ,ref:%@ to ref:%@",ref,parentRef);
+#endif
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -228,6 +240,9 @@ _Pragma("clang diagnostic pop") \
         
         [WXTracingManager startTracingWithInstanceId:instanceId ref:ref className:nil name:WXTJSCall phase:WXTracingEnd functionName:@"updateAttrs" options:@{@"threadName":WXTJSBridgeThread}];
         WXPerformBlockOnComponentThread(^{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action: updateAttrs ref:%@,attr:%@",ref,attrsData);
+#endif
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -251,6 +266,10 @@ _Pragma("clang diagnostic pop") \
         }
         [WXTracingManager startTracingWithInstanceId:instanceId ref:ref className:nil name:WXTJSCall phase:WXTracingEnd functionName:@"updateStyles" options:@{@"threadName":WXTJSBridgeThread}];
         WXPerformBlockOnComponentThread(^{
+            
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action: updateStyles ref:%@,styles:%@",ref,stylesData);
+#endif
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -273,6 +292,10 @@ _Pragma("clang diagnostic pop") \
         }
         
         WXPerformBlockOnComponentThread(^{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action: addEvent ref:%@",ref);
+#endif
+            
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -295,6 +318,9 @@ _Pragma("clang diagnostic pop") \
         }
         
         WXPerformBlockOnComponentThread(^{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action :removeEvent ref:%@",ref);
+#endif
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -317,6 +343,10 @@ _Pragma("clang diagnostic pop") \
         }
         [WXTracingManager startTracingWithInstanceId:instanceId ref:nil className:nil name:WXTJSCall phase:WXTracingEnd functionName:@"createFinish" options:@{@"threadName":WXTJSBridgeThread}];
         WXPerformBlockOnComponentThread(^{
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> action: createFinish :%@",instanceId);
+#endif
+            
             WXComponentManager *manager = instance.componentManager;
             if (!manager.isValid) {
                 return;
@@ -339,6 +369,9 @@ _Pragma("clang diagnostic pop") \
             WXLogInfo(@"instance not found for callNativeModule:%@.%@, maybe already destroyed", moduleName, methodName);
             return nil;
         }
+#ifdef DEBUG
+        WXLogDebug(@"flexLayout -> action: callNativeModule : %@ . %@",moduleName,methodName);
+#endif
         NSMutableDictionary * newOptions = [options mutableCopy];
         NSMutableArray * newArguments = [arguments mutableCopy];
         
@@ -367,6 +400,11 @@ _Pragma("clang diagnostic pop") \
     }];
     
     [_jsBridge registerCallNativeComponent:^void(NSString *instanceId, NSString *componentRef, NSString *methodName, NSArray *args, NSDictionary *options) {
+       
+#ifdef DEBUG
+        WXLogDebug(@"flexLayout -> action: callNativeComponent ref:%@",componentRef);
+#endif
+        
         WXSDKInstance *instance = [WXSDKManager instanceForID:instanceId];
         WXComponentMethod *method = [[WXComponentMethod alloc] initWithComponentRef:componentRef methodName:methodName arguments:args instance:instance];
         [method invoke];

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m
deleted file mode 100644
index a6adec0..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m
+++ /dev/null
@@ -1,94 +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 "WXCellSlotComponent.h"
-#import "WXComponent_internal.h"
-#import "WXComponentManager.h"
-#import "WXSDKInstance_private.h"
-#import "WXConvert.h"
-#import "WXAssert.h"
-#import "WXScrollerComponent.h"
-
-@implementation WXCellSlotComponent
-
-- (instancetype)initWithRef:(NSString *)ref
-                       type:(NSString *)type
-                     styles:(NSDictionary *)styles
-                 attributes:(NSDictionary *)attributes
-                     events:(NSArray *)events
-               weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    if (self) {
-        // TODO: isRecycle / insertAnimation / deleteAnimation / keepScrollPosition
-        if (attributes[@"default"]) {
-            _templateCaseType = @"default";
-        }
-        _templateCaseType = attributes[@"case"] ? [WXConvert NSString:attributes[@"case"]] : WXDefaultRecycleTemplateType;
-        _lazyCreateView = YES;
-        _isNeedJoinLayoutSystem = NO;
-    }
-    
-    return self;
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    
-}
-
-- (void)updateCellData:(NSDictionary *)data
-{
-    WXAssertComponentThread();    
-    
-    [self updateBindingData:data];
-    [self triggerLayout];
-}
-
-- (void)_didInserted
-{
-    [self triggerLayout];
-}
-
-- (void)triggerLayout
-{
-    WXAssertComponentThread();
-    
-    //TODO: _isUseContainerWidth?
-    if (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH])) {
-        self.cssNode->style.dimensions[CSS_WIDTH] = ((WXScrollerComponent *)(self.supercomponent)).scrollerCSSNode->style.dimensions[CSS_WIDTH];
-    }
-    
-    if ([self needsLayout]) {
-        layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
-        if ([WXLog logLevel] >= WXLogLevelDebug) {
-            print_css_node(self.cssNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
-        }
-    }
-    
-    NSMutableSet<WXComponent *> *dirtyComponents = [NSMutableSet set];
-    [self _calculateFrameWithSuperAbsolutePosition:CGPointZero gatherDirtyComponents:dirtyComponents];
-    for (WXComponent *dirtyComponent in dirtyComponents) {
-        [self.weexInstance.componentManager _addUITask:^{
-            [dirtyComponent _layoutDidFinish];
-        }];
-    }
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.mm b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.mm
new file mode 100644
index 0000000..b1b757a
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.mm
@@ -0,0 +1,117 @@
+/*
+ * 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 "WXCellSlotComponent.h"
+#import "WXComponent_internal.h"
+#import "WXComponentManager.h"
+#import "WXSDKInstance_private.h"
+#import "WXConvert.h"
+#import "WXAssert.h"
+#import "WXScrollerComponent+Layout.h"
+
+@implementation WXCellSlotComponent
+
+- (instancetype)initWithRef:(NSString *)ref
+                       type:(NSString *)type
+                     styles:(NSDictionary *)styles
+                 attributes:(NSDictionary *)attributes
+                     events:(NSArray *)events
+               weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        // TODO: isRecycle / insertAnimation / deleteAnimation / keepScrollPosition
+        if (attributes[@"default"]) {
+            _templateCaseType = @"default";
+        }
+        _templateCaseType = attributes[@"case"] ? [WXConvert NSString:attributes[@"case"]] :const_cast<NSString *>(WXDefaultRecycleTemplateType) ;
+        _lazyCreateView = YES;
+        _isNeedJoinLayoutSystem = NO;
+    }
+    
+    return self;
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    
+}
+
+- (void)updateCellData:(NSDictionary *)data
+{
+    WXAssertComponentThread();    
+    
+    [self updateBindingData:data];
+    [self triggerLayout];
+}
+
+- (void)_didInserted
+{
+    [self triggerLayout];
+}
+
+- (void)triggerLayout
+{
+    WXAssertComponentThread();
+    
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        //TODO: _isUseContainerWidth?
+        if (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH])) {
+            self.cssNode->style.dimensions[CSS_WIDTH] = ((WXScrollerComponent *)(self.supercomponent)).scrollerCSSNode->style.dimensions[CSS_WIDTH];
+        }
+        
+        if ([self needsLayout]) {
+            layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
+            if ([WXLog logLevel] >= WXLogLevelDebug) {
+                print_css_node(self.cssNode, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN));
+            }
+        }
+    }
+
+//#else
+    else
+    {
+        if (flexIsUndefined(self.flexCssNode->getStyleWidth())) {
+            self.flexCssNode->setStyleWidth(((WXScrollerComponent *)(self.supercomponent)).flexScrollerCSSNode->getStyleWidth(),NO);
+        }
+        
+        if ([self needsLayout]) {
+            std::pair<float, float> renderPageSize;
+            renderPageSize.first = self.weexInstance.frame.size.width;
+            renderPageSize.second = self.weexInstance.frame.size.height;
+            self.flexCssNode->calculateLayout(renderPageSize);
+            if ([WXLog logLevel] >= WXLogLevelDebug) {
+                
+            }
+        }
+    }
+//#endif
+    
+    NSMutableSet<WXComponent *> *dirtyComponents = [NSMutableSet set];
+    [self _calculateFrameWithSuperAbsolutePosition:CGPointZero gatherDirtyComponents:dirtyComponents];
+    for (WXComponent *dirtyComponent in dirtyComponents) {
+        [self.weexInstance.componentManager _addUITask:^{
+            [dirtyComponent _layoutDidFinish];
+        }];
+    }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m
deleted file mode 100644
index 8f71797..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m
+++ /dev/null
@@ -1,618 +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 "WXLog.h"
-#import "WXUtility.h"
-#import "WXComponent_internal.h"
-#import "WXComponentManager.h"
-#import "WXSDKInstance_private.h"
-
-#import "WXCellSlotComponent.h"
-#import "WXRecycleListLayout.h"
-#import "WXRecycleListComponent.h"
-#import "WXRecycleListDataManager.h"
-#import "WXRecycleListTemplateManager.h"
-#import "WXRecycleListUpdateManager.h"
-#import "WXBridgeManager.h"
-#import "WXSDKManager.h"
-#import "WXComponent+DataBinding.h"
-
-@interface WXRecycleListComponentView:UICollectionView
-@end
-
-@implementation WXRecycleListComponentView
-- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
-{
-    if ([(id <WXScrollerProtocol>) self.wx_component respondsToSelector:@selector(requestGestureShouldStopPropagation:shouldReceiveTouch:)]) {
-        return [(id <WXScrollerProtocol>) self.wx_component requestGestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
-    }
-    else{
-        return YES;
-    }
-}
-
-@end
-
-@interface WXRecycleListComponent () <WXRecycleListLayoutDelegate, WXRecycleListUpdateDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>
-
-@end
-
-@implementation WXRecycleListComponent
-{
-    NSString *_templateSwitchKey;
-    NSString *_aliasKey;
-    NSString *_indexKey;
-    __weak UICollectionView *_collectionView;
-    
-    NSMutableDictionary *_sizeCache;
-    NSMutableDictionary *_stickyCache;
-    
-    NSUInteger _previousLoadMoreCellNumber;
-}
-
-WX_EXPORT_METHOD(@selector(appendData:))
-WX_EXPORT_METHOD(@selector(appendRange:))
-WX_EXPORT_METHOD(@selector(insertData:data:))
-WX_EXPORT_METHOD(@selector(updateData:data:))
-WX_EXPORT_METHOD(@selector(removeData:count:))
-WX_EXPORT_METHOD(@selector(moveData:toIndex:))
-WX_EXPORT_METHOD(@selector(scrollTo:options:))
-WX_EXPORT_METHOD(@selector(insertRange:range:))
-WX_EXPORT_METHOD(@selector(setListData:))
-
-- (instancetype)initWithRef:(NSString *)ref
-                       type:(NSString *)type
-                     styles:(NSDictionary *)styles
-                 attributes:(NSDictionary *)attributes
-                     events:(NSArray *)events
-               weexInstance:(WXSDKInstance *)weexInstance
-{
-    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
-        _dataManager = attributes[@"listData"]? [[WXRecycleListDataManager alloc] initWithData:attributes[@"listData"]] : [WXRecycleListDataManager new];
-        _templateManager = [WXRecycleListTemplateManager new];
-        _updateManager = [WXRecycleListUpdateManager new];
-        _updateManager.delegate = self;
-        _templateSwitchKey = [WXConvert NSString:attributes[@"switch"]];
-        _aliasKey = [WXConvert NSString:attributes[@"alias"]];
-        _indexKey = [WXConvert NSString:attributes[@"index"]];
-        _sizeCache = [NSMutableDictionary dictionary];
-        _stickyCache = [NSMutableDictionary dictionary];
-    }
-    
-    return self;
-}
-
-#pragma mark - WXComponent Methods
-
-- (UIView *)loadView
-{
-    WXRecycleListLayout *layout = [self recycleListLayout];
-    return [[WXRecycleListComponentView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
-}
-
-- (void)viewDidLoad
-{
-    [super viewDidLoad];
-    
-    _collectionView = (UICollectionView *)self.view;
-    _collectionView.allowsSelection = NO;
-    _collectionView.allowsMultipleSelection = NO;
-    _collectionView.dataSource = self;
-    _collectionView.delegate = self;
-    
-    _templateManager.collectionView = _collectionView;
-    _updateManager.collectionView = _collectionView;
-}
-
-- (void)viewWillUnload
-{
-    [super viewWillUnload];
-    
-    _collectionView.dataSource = nil;
-    _collectionView.delegate = nil;
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    [super updateAttributes:attributes];
-    
-    if (attributes[@"listData"]) {
-        NSArray *listData = attributes[@"listData"];
-        [self _updateListData:listData withCompletion:nil animation:NO];
-    }
-    if (attributes[@"switch"]) {
-        _templateSwitchKey = [WXConvert NSString:attributes[@"switch"]];
-    }
-    if (attributes[@"alias"]) {
-        _aliasKey = [WXConvert NSString:attributes[@"alias"]];
-    }
-    if (attributes[@"index"]) {
-        _indexKey = [WXConvert NSString:attributes[@"index"]];
-    }
-    if (attributes[@"scrollDirection"]) {
-        WXScrollDirection newScrollDirection = attributes[@"scrollDirection"] ? [WXConvert WXScrollDirection:attributes[@"scrollDirection"]] : WXScrollDirectionVertical;
-        [self _updateScrollDirection:newScrollDirection];
-    }
-}
-
-- (CGPoint)absolutePositionForComponent:(WXComponent *)component
-{
-    CGPoint position = CGPointZero;
-    UIView *view = component->_view;
-    while (view) {
-        if ([view isKindOfClass:[UICollectionViewCell class]]) {
-            NSIndexPath *indexPath = [_collectionView indexPathForCell:(UICollectionViewCell *)view];
-            if (!indexPath) {
-                return CGPointMake(NAN, NAN);
-            }
-            UICollectionViewLayoutAttributes *attributes = [_collectionView layoutAttributesForItemAtIndexPath:indexPath];
-            CGPoint cellOrigin = attributes.frame.origin;
-            position = CGPointMake(position.x + cellOrigin.x,
-                                   position.y + cellOrigin.y);
-            break;
-        }
-        position = CGPointMake(position.x + view.frame.origin.x,
-                               position.y + view.frame.origin.y);
-        view = view.superview;
-    }
-    
-    return position;
-}
-
-- (void)setContentSize:(CGSize)contentSize
-{
-    // Do Nothing
-}
-
-- (void)adjustSticky
-{
-    // Do Nothing, sticky is adjusted by layout
-}
-
-#pragma mark - Load More Event
-
-- (void)loadMore
-{
-    [super loadMore];
-    
-    _previousLoadMoreCellNumber = [_collectionView numberOfItemsInSection:0];
-}
-
-- (BOOL)isNeedLoadMore
-{
-    BOOL superNeedLoadMore = [super isNeedLoadMore];
-    return superNeedLoadMore && _previousLoadMoreCellNumber != [_collectionView numberOfItemsInSection:0];
-}
-
-- (void)resetLoadmore
-{
-    [super resetLoadmore];
-    _previousLoadMoreCellNumber = 0;
-}
-
-#pragma mark - Exported Component Methods
-
-- (void)appendData:(id)appendingData
-{
-    if (!appendingData){
-        return;
-    }
-    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
-    [newListData addObject:appendingData];
-}
-
-- (void)appendRange:(NSArray*)data
-{
-    if (![data isKindOfClass:[NSArray class]]) {
-        WXLogError(@"wrong format of appending data:%@", data);
-        return;
-    }
-    
-    NSArray *oldData = [_dataManager data];
-    [_updateManager updateWithAppendingData:data oldData:oldData completion:nil animation:NO];
-}
-
-- (void)setListData:(NSArray*)data
-{
-    if ([data count]) {
-        [_dataManager updateData:data];
-    }
-}
-- (void)insertData:(NSUInteger)index data:(id)data
-{
-    // TODO: bring the update logic to UpdateManager
-    // TODO: update cell because index has changed
-    NSMutableArray *newListData = [[_dataManager data] mutableCopy];
-    if (index <= newListData.count) {
-        [newListData insertObject:data atIndex:index];
-        [_dataManager updateData:newListData];
-        
-        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
-        
-        [UIView performWithoutAnimation:^{
-            [self->_collectionView insertItemsAtIndexPaths:@[indexPath]];
-        }];
-    }
-}
-
-- (void)updateComponentData:(NSString*)componentDataId componentData:(NSDictionary*)componentData callback:(NSString*)callbackId
-{
-    NSMutableDictionary * virtualComponentData = [[_dataManager virtualComponentDataWithId:componentDataId] mutableCopy];
-    NSIndexPath * indexPath = virtualComponentData[@"indexPath"];
-    if (!indexPath) {
-        return;
-    }
-    virtualComponentData = virtualComponentData?:[NSMutableDictionary new];
-    [virtualComponentData addEntriesFromDictionary:componentData];
-    [_dataManager updateVirtualComponentData:componentDataId data:[virtualComponentData copy]];
-    virtualComponentData[@"@phase"] = @"update";
-    virtualComponentData[@"callbackId"] = callbackId;
-    [self _updateDataForCellSlotAtIndexPath:indexPath data:virtualComponentData];
-}
-
-- (void)_updateDataForCellSlotAtIndexPath:(NSIndexPath*)indexPath data:(NSDictionary*)data
-{
-    if(!indexPath || !data) {
-        return;
-    }
-    WXPerformBlockOnMainThread(^{
-        UICollectionViewCell * cellView = [self->_collectionView cellForItemAtIndexPath:indexPath];
-        WXCellSlotComponent * cellSlotComponent = (WXCellSlotComponent*)cellView.wx_component;
-        if (cellSlotComponent) {
-            [self _updateBindingData:data forCell:cellSlotComponent atIndexPath:indexPath];
-        }
-        // callback when update virtual component data success.
-        NSString * callbackId = data[@"callbackId"];
-        if (callbackId) {
-            [[WXSDKManager bridgeMgr] callBack:self.weexInstance.instanceId funcId:callbackId params:@{@"result":@"success"}];
-        }
-    });
-}
-
-- (void)updateData:(NSUInteger)index data:(id)data
-{
-    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
-    if (!data && index > [newListData count]) {
-        return;
-    }
-    NSIndexPath * indexPath = [NSIndexPath indexPathForRow:index inSection:0];
-    NSDictionary * virtualComponentData = [_dataManager virtualComponentDataWithIndexPath:indexPath];
-    if ([virtualComponentData[WXBindingOnceIdentify] boolValue]) {
-        return;
-    }
-    
-    // TODO: bring the update logic to UpdateManager
-    newListData[index] = data;
-    [_dataManager updateData:newListData];
-    NSString* virtualComponentId = [_dataManager virtualComponentIdWithIndexPath:indexPath];
-    [_dataManager updateVirtualComponentData:virtualComponentId data:data];
-    NSMutableDictionary * newData = nil;
-    if (![data isKindOfClass:[NSDictionary class]]) {
-         newData = [NSMutableDictionary new];
-        [newData setObject:@"data" forKey:data];
-        data = newData;
-    }
-    newData = [data mutableCopy];
-    newData[@"@phase"] = @"update";
-    [self _updateDataForCellSlotAtIndexPath:indexPath data:[newData copy]];
-}
-
-- (void)insertRange:(NSInteger)index range:(NSArray*)data
-{
-    if (![data count]) {
-        WXLogDebug(@"ignore invalid insertRange");
-        return;
-    }
-    
-    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
-    NSRange range = NSMakeRange(index,[data count]);
-    NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
-    [newListData insertObjects:data atIndexes:indexSet];
-    [_dataManager updateData:newListData];
-    [_collectionView reloadData];
-}
-
-- (void)removeData:(NSInteger)index count:(NSInteger)count
-{
-    // TODO: bring the update logic to UpdateManager
-    
-    NSMutableArray *newListData = [[_dataManager data] mutableCopy];
-    if (index > [newListData count] || index + count - 1 > [newListData count]) {
-        
-        return;
-    }
-    NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, count)];
-    [newListData removeObjectsAtIndexes:indexSet];
-    __block NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray new];
-    [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
-        NSIndexPath* indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
-        [indexPaths addObject:indexPath];
-    }];
-    
-    [_dataManager updateData:newListData];
-    [_dataManager deleteVirtualComponentAtIndexPaths:indexPaths];
-    [UIView performWithoutAnimation:^{
-        [self->_collectionView deleteItemsAtIndexPaths:indexPaths];
-        [self->_collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
-    }];
-}
-
-- (void)moveData:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex
-{
-    // TODO: bring the update logic to UpdateManager
-    NSMutableArray *newListData = [[_dataManager data] mutableCopy];
-    id data = newListData[fromIndex];
-    [newListData removeObjectAtIndex:fromIndex];
-    [newListData insertObject:data atIndex:toIndex];
-    [_dataManager updateData:newListData];
-    
-    NSIndexPath *fromIndexPath = [NSIndexPath indexPathForItem:fromIndex inSection:0];
-    NSIndexPath *toIndexPath = [NSIndexPath indexPathForItem:toIndex inSection:0];
-    [UIView performWithoutAnimation:^{
-        [self->_collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
-    }];
-}
-
-- (void)scrollTo:(NSUInteger)index options:(NSDictionary *)options
-{
-    NSIndexPath *toIndexPath = [NSIndexPath indexPathForItem:index inSection:0];
-    BOOL animated = options[@"animated"] ? [WXConvert BOOL:options[@"animated"]] : NO;
-    [_collectionView scrollToItemAtIndexPath:toIndexPath atScrollPosition:UICollectionViewScrollPositionTop animated:animated];
-}
-
-#pragma mark - WXComponent Internal Methods
-
-- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-   [super _insertSubcomponent:subcomponent atIndex:index];
-    
-    if ([subcomponent isKindOfClass:[WXCellSlotComponent class]]) {
-        WXCellSlotComponent *cell = (WXCellSlotComponent*)subcomponent;
-        [self.weexInstance.componentManager _addUITask:^{
-            [_templateManager addTemplate:cell];
-        }];
-        
-        //TODO: update collection view if adding template
-    }
-}
-
-#pragma mark - Private
-
-- (void)_updateBindingData:(id)data forCell:(WXCellSlotComponent *)cellComponent atIndexPath:(NSIndexPath *)indexPath
-{
-    id originalData = data;
-    if (![originalData isKindOfClass:[NSDictionary class]]) {
-        if (_aliasKey) {
-            NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
-            [dictionary setObject:data forKey:_aliasKey];
-            data = dictionary;
-        } else {
-            return;
-        }
-    }
-    
-    if (!data[@"indexPath"] || !data[@"recycleListComponentRef"]) {
-        NSMutableDictionary * dataNew = [data mutableCopy];
-        dataNew[@"recycleListComponentRef"] = self.ref;
-        dataNew[@"indexPath"] = indexPath;
-        data = dataNew;
-    }
-    
-    if ([originalData isKindOfClass:[NSDictionary class]] && _aliasKey &&!data[@"phase"]) {
-        data = @{_aliasKey:data,@"aliasKey":_aliasKey};
-    }
-    
-    if (_indexKey) {
-        NSMutableDictionary *dataNew = [data mutableCopy];
-        dataNew[_indexKey] = @(indexPath.item);
-        data = dataNew;
-    }
-    
-#ifdef DEBUG
-    NSDate *startTime = [NSDate date];
-#endif
-    
-    WXPerformBlockSyncOnComponentThread(^{
-        [cellComponent updateCellData:[data copy]];
-    });
-#ifdef DEBUG
-    double duration = -[startTime timeIntervalSinceNow] * 1000;
-    WXLogDebug(@"cell:%li update data time:%f", (long)indexPath.item, duration);
-#endif
-    
-    NSValue *cachedSize = _sizeCache[indexPath];
-    if (!cachedSize || !CGSizeEqualToSize([cachedSize CGSizeValue] , cellComponent.calculatedFrame.size)) {
-        _sizeCache[indexPath] = [NSValue valueWithCGSize:cellComponent.calculatedFrame.size];
-        [_collectionView.collectionViewLayout invalidateLayout];
-    }
-    NSNumber *cachedSticky = _stickyCache[indexPath];
-    BOOL isSticky = cellComponent->_positionType == WXPositionTypeSticky;
-    if (!cachedSticky || [cachedSticky boolValue] != isSticky) {
-        _stickyCache[indexPath] = @(isSticky);
-    }
-}
-
-- (void)_updateListData:(NSArray *)newData
-        withCompletion:(WXRecycleListUpdateCompletion)completion
-             animation:(BOOL)animation
-{
-    if (![newData isKindOfClass:[NSArray class]]) {
-        WXLogError(@"wrong format of list data:%@", newData);
-        completion(NO);
-        return;
-    }
-    
-    NSArray *oldData = [_dataManager data];
-    [_updateManager updateWithNewData:newData oldData:oldData completion:completion animation:animation];
-}
-
-- (void)_updateScrollDirection:(WXScrollDirection)newScrollDirection
-{   
-    WXRecycleListLayout *layout = [self recycleListLayout];
-    _collectionView.collectionViewLayout = layout;
-}
-
-- (WXRecycleListLayout *)recycleListLayout
-{
-    WXRecycleListLayout *layout = [WXRecycleListLayout new];
-    layout.delegate = self;
-    // to show cells that original width / height is zero, otherwise cellForItemAtIndexPath will not be called
-    layout.minimumLineSpacing = 0.01;
-    layout.minimumInteritemSpacing = 0.01;
-    if (WXScrollDirectionHorizontal == self.scrollDirection) {
-        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
-    }
-    return layout;
-}
-
-#pragma mark - UICollectionViewDataSource
-
-- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
-{
-    return 1;
-}
-
-- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
-{
-    return [_dataManager numberOfItems];
-}
-
-- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    // 1. get the data relating to the cell
-    id data = [_dataManager dataAtIndex:indexPath.row];
-    
-    // 2. get the template type specified by data
-    NSString * templateType = [self templateType:indexPath];
-    _templateManager.collectionView = collectionView;
-    if (!templateType) {
-        WXLogError(@"Each data should have a value for %@ to indicate template type", _templateSwitchKey);
-        return nil;
-    }
-    
-    // 3. dequeue a cell component by template type
-    UICollectionViewCell *cellView = [_collectionView dequeueReusableCellWithReuseIdentifier:templateType forIndexPath:indexPath];
-    WXCellSlotComponent *cellComponent = (WXCellSlotComponent *)cellView.wx_component;
-    if (!cellComponent) {
-        cellComponent = [_templateManager dequeueCellSlotWithType:templateType forIndexPath:indexPath];
-        cellView.wx_component = cellComponent;
-        WXPerformBlockOnComponentThread(^{
-            //TODO: How can we avoid this?
-            [super _insertSubcomponent:cellComponent atIndex:self.subcomponents.count];
-        });
-    }
-    
-    // 4. binding the data to the cell component
-    [self _updateBindingData:data forCell:cellComponent atIndexPath:indexPath];
-
-    // 5. Add cell component's view to content view.
-    UIView *contentView = cellComponent.view;
-    if (contentView.superview == cellView.contentView) {
-        return cellView;
-    }
-    
-    for (UIView *view in cellView.contentView.subviews) {
-        [view removeFromSuperview];
-    }
-    [cellView.contentView addSubview:contentView];
-    [cellView setAccessibilityIdentifier:contentView.accessibilityIdentifier];
-    
-    WXLogDebug(@"Return cell view:%@, indexPath:%@", cellView, indexPath);
-    
-    [self handleAppear];
-    
-    return cellView;
-}
-
-- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
-{
-    return nil;
-}
-
-#pragma mark - UICollectionViewDelegate
-
-- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    WXLogDebug(@"will display cell:%@, at index path:%@", cell, indexPath);
-}
-
-- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    WXLogDebug(@"Did end displaying cell:%@, at index path:%@", cell, indexPath);
-}
-
-#pragma mark - UICollectionViewDelegateFlowLayout
-
-- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    NSValue *size = _sizeCache[indexPath];
-    if (size) {
-        return [size CGSizeValue];
-    } else {
-
-        WXCellSlotComponent *cell = [_templateManager templateWithType:[self templateType:indexPath]];
-        CGSize size = cell.calculatedFrame.size;
-        _sizeCache[indexPath] = [NSValue valueWithCGSize:size];
-        return CGSizeMake(_collectionView.frame.size.width, size.height);
-    }
-}
-
-#pragma mark - WXRecycleListLayoutDelegate
-
-- (BOOL)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout isNeedStickyForIndexPath:(NSIndexPath *)indexPath
-{
-    NSNumber *cachedSticky = _stickyCache[indexPath];
-    if (cachedSticky) {
-        return [cachedSticky boolValue];
-    } else {
-        return NO;
-    }
-}
-
-#pragma mark - WXRecycleListUpdateDelegate
-
-- (void)updateManager:(WXRecycleListUpdateManager *)manager willUpdateData:(id)newData
-{
-    [_dataManager updateData:newData];
-}
-
-- (void)updateManager:(WXRecycleListUpdateManager *)manager didUpdateData:(id)newData withSuccess:(BOOL)finished
-{
-    
-}
-
-- (NSString*)templateType:(NSIndexPath*)indexPath
-{
-    NSDictionary *data = [_dataManager dataAtIndex:indexPath.row];
-    // default is first template.
-    NSString *templateType = [_templateManager topTemplate].templateCaseType;
-    if (!data || ![data isKindOfClass:[NSDictionary class]]) {
-        return templateType;
-    }
-    
-    if (_templateSwitchKey &&data[_templateSwitchKey]){
-        templateType = data[_templateSwitchKey];
-    } else if (data[WXDefaultRecycleTemplateType]){
-        // read the default type.
-        templateType = data[WXDefaultRecycleTemplateType];
-    }
-    return templateType;
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.mm b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.mm
new file mode 100644
index 0000000..551acd9
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.mm
@@ -0,0 +1,619 @@
+/*
+ * 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 "WXLog.h"
+#import "WXUtility.h"
+#import "WXComponent_internal.h"
+#import "WXComponentManager.h"
+#import "WXSDKInstance_private.h"
+
+#import "WXCellSlotComponent.h"
+#import "WXRecycleListLayout.h"
+#import "WXRecycleListComponent.h"
+#import "WXRecycleListDataManager.h"
+#import "WXRecycleListTemplateManager.h"
+#import "WXRecycleListUpdateManager.h"
+#import "WXBridgeManager.h"
+#import "WXSDKManager.h"
+#import "WXComponent+DataBinding.h"
+#import "WXComponent+Layout.h"
+
+@interface WXRecycleListComponentView:UICollectionView
+@end
+
+@implementation WXRecycleListComponentView
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
+{
+    if ([(id <WXScrollerProtocol>) self.wx_component respondsToSelector:@selector(requestGestureShouldStopPropagation:shouldReceiveTouch:)]) {
+        return [(id <WXScrollerProtocol>) self.wx_component requestGestureShouldStopPropagation:gestureRecognizer shouldReceiveTouch:touch];
+    }
+    else{
+        return YES;
+    }
+}
+
+@end
+
+@interface WXRecycleListComponent () <WXRecycleListLayoutDelegate, WXRecycleListUpdateDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>
+
+@end
+
+@implementation WXRecycleListComponent
+{
+    NSString *_templateSwitchKey;
+    NSString *_aliasKey;
+    NSString *_indexKey;
+    __weak UICollectionView *_collectionView;
+    
+    NSMutableDictionary *_sizeCache;
+    NSMutableDictionary *_stickyCache;
+    
+    NSUInteger _previousLoadMoreCellNumber;
+}
+
+WX_EXPORT_METHOD(@selector(appendData:))
+WX_EXPORT_METHOD(@selector(appendRange:))
+WX_EXPORT_METHOD(@selector(insertData:data:))
+WX_EXPORT_METHOD(@selector(updateData:data:))
+WX_EXPORT_METHOD(@selector(removeData:count:))
+WX_EXPORT_METHOD(@selector(moveData:toIndex:))
+WX_EXPORT_METHOD(@selector(scrollTo:options:))
+WX_EXPORT_METHOD(@selector(insertRange:range:))
+WX_EXPORT_METHOD(@selector(setListData:))
+
+- (instancetype)initWithRef:(NSString *)ref
+                       type:(NSString *)type
+                     styles:(NSDictionary *)styles
+                 attributes:(NSDictionary *)attributes
+                     events:(NSArray *)events
+               weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        _dataManager = attributes[@"listData"]? [[WXRecycleListDataManager alloc] initWithData:attributes[@"listData"]] : [WXRecycleListDataManager new];
+        _templateManager = [WXRecycleListTemplateManager new];
+        _updateManager = [WXRecycleListUpdateManager new];
+        _updateManager.delegate = self;
+        _templateSwitchKey = [WXConvert NSString:attributes[@"switch"]];
+        _aliasKey = [WXConvert NSString:attributes[@"alias"]];
+        _indexKey = [WXConvert NSString:attributes[@"index"]];
+        _sizeCache = [NSMutableDictionary dictionary];
+        _stickyCache = [NSMutableDictionary dictionary];
+    }
+    
+    return self;
+}
+
+#pragma mark - WXComponent Methods
+
+- (UIView *)loadView
+{
+    WXRecycleListLayout *layout = [self recycleListLayout];
+    return [[WXRecycleListComponentView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    
+    _collectionView = (UICollectionView *)self.view;
+    _collectionView.allowsSelection = NO;
+    _collectionView.allowsMultipleSelection = NO;
+    _collectionView.dataSource = self;
+    _collectionView.delegate = self;
+    
+    _templateManager.collectionView = _collectionView;
+    _updateManager.collectionView = _collectionView;
+}
+
+- (void)viewWillUnload
+{
+    [super viewWillUnload];
+    
+    _collectionView.dataSource = nil;
+    _collectionView.delegate = nil;
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    [super updateAttributes:attributes];
+    
+    if (attributes[@"listData"]) {
+        NSArray *listData = attributes[@"listData"];
+        [self _updateListData:listData withCompletion:nil animation:NO];
+    }
+    if (attributes[@"switch"]) {
+        _templateSwitchKey = [WXConvert NSString:attributes[@"switch"]];
+    }
+    if (attributes[@"alias"]) {
+        _aliasKey = [WXConvert NSString:attributes[@"alias"]];
+    }
+    if (attributes[@"index"]) {
+        _indexKey = [WXConvert NSString:attributes[@"index"]];
+    }
+    if (attributes[@"scrollDirection"]) {
+        WXScrollDirection newScrollDirection = attributes[@"scrollDirection"] ? [WXConvert WXScrollDirection:attributes[@"scrollDirection"]] : WXScrollDirectionVertical;
+        [self _updateScrollDirection:newScrollDirection];
+    }
+}
+
+- (CGPoint)absolutePositionForComponent:(WXComponent *)component
+{
+    CGPoint position = CGPointZero;
+    UIView *view = component->_view;
+    while (view) {
+        if ([view isKindOfClass:[UICollectionViewCell class]]) {
+            NSIndexPath *indexPath = [_collectionView indexPathForCell:(UICollectionViewCell *)view];
+            if (!indexPath) {
+                return CGPointMake(NAN, NAN);
+            }
+            UICollectionViewLayoutAttributes *attributes = [_collectionView layoutAttributesForItemAtIndexPath:indexPath];
+            CGPoint cellOrigin = attributes.frame.origin;
+            position = CGPointMake(position.x + cellOrigin.x,
+                                   position.y + cellOrigin.y);
+            break;
+        }
+        position = CGPointMake(position.x + view.frame.origin.x,
+                               position.y + view.frame.origin.y);
+        view = view.superview;
+    }
+    
+    return position;
+}
+
+- (void)setContentSize:(CGSize)contentSize
+{
+    // Do Nothing
+}
+
+- (void)adjustSticky
+{
+    // Do Nothing, sticky is adjusted by layout
+}
+
+#pragma mark - Load More Event
+
+- (void)loadMore
+{
+    [super loadMore];
+    
+    _previousLoadMoreCellNumber = [_collectionView numberOfItemsInSection:0];
+}
+
+- (BOOL)isNeedLoadMore
+{
+    BOOL superNeedLoadMore = [super isNeedLoadMore];
+    return superNeedLoadMore && _previousLoadMoreCellNumber != [_collectionView numberOfItemsInSection:0];
+}
+
+- (void)resetLoadmore
+{
+    [super resetLoadmore];
+    _previousLoadMoreCellNumber = 0;
+}
+
+#pragma mark - Exported Component Methods
+
+- (void)appendData:(id)appendingData
+{
+    if (!appendingData){
+        return;
+    }
+    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
+    [newListData addObject:appendingData];
+}
+
+- (void)appendRange:(NSArray*)data
+{
+    if (![data isKindOfClass:[NSArray class]]) {
+        WXLogError(@"wrong format of appending data:%@", data);
+        return;
+    }
+    
+    NSArray *oldData = [_dataManager data];
+    [_updateManager updateWithAppendingData:data oldData:oldData completion:nil animation:NO];
+}
+
+- (void)setListData:(NSArray*)data
+{
+    if ([data count]) {
+        [_dataManager updateData:data];
+    }
+}
+- (void)insertData:(NSUInteger)index data:(id)data
+{
+    // TODO: bring the update logic to UpdateManager
+    // TODO: update cell because index has changed
+    NSMutableArray *newListData = [[_dataManager data] mutableCopy];
+    if (index <= newListData.count) {
+        [newListData insertObject:data atIndex:index];
+        [_dataManager updateData:newListData];
+        
+        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
+        
+        [UIView performWithoutAnimation:^{
+            [self->_collectionView insertItemsAtIndexPaths:@[indexPath]];
+        }];
+    }
+}
+
+- (void)updateComponentData:(NSString*)componentDataId componentData:(NSDictionary*)componentData callback:(NSString*)callbackId
+{
+    NSMutableDictionary * virtualComponentData = [[_dataManager virtualComponentDataWithId:componentDataId] mutableCopy];
+    NSIndexPath * indexPath = virtualComponentData[@"indexPath"];
+    if (!indexPath) {
+        return;
+    }
+    virtualComponentData = virtualComponentData?:[NSMutableDictionary new];
+    [virtualComponentData addEntriesFromDictionary:componentData];
+    [_dataManager updateVirtualComponentData:componentDataId data:[virtualComponentData copy]];
+    virtualComponentData[@"@phase"] = @"update";
+    virtualComponentData[@"callbackId"] = callbackId;
+    [self _updateDataForCellSlotAtIndexPath:indexPath data:virtualComponentData];
+}
+
+- (void)_updateDataForCellSlotAtIndexPath:(NSIndexPath*)indexPath data:(NSDictionary*)data
+{
+    if(!indexPath || !data) {
+        return;
+    }
+    WXPerformBlockOnMainThread(^{
+        UICollectionViewCell * cellView = [self->_collectionView cellForItemAtIndexPath:indexPath];
+        WXCellSlotComponent * cellSlotComponent = (WXCellSlotComponent*)cellView.wx_component;
+        if (cellSlotComponent) {
+            [self _updateBindingData:data forCell:cellSlotComponent atIndexPath:indexPath];
+        }
+        // callback when update virtual component data success.
+        NSString * callbackId = data[@"callbackId"];
+        if (callbackId) {
+            [[WXSDKManager bridgeMgr] callBack:self.weexInstance.instanceId funcId:callbackId params:@{@"result":@"success"}];
+        }
+    });
+}
+
+- (void)updateData:(NSUInteger)index data:(id)data
+{
+    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
+    if (!data && index > [newListData count]) {
+        return;
+    }
+    NSIndexPath * indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+    NSDictionary * virtualComponentData = [_dataManager virtualComponentDataWithIndexPath:indexPath];
+    if ([virtualComponentData[WXBindingOnceIdentify] boolValue]) {
+        return;
+    }
+    
+    // TODO: bring the update logic to UpdateManager
+    newListData[index] = data;
+    [_dataManager updateData:newListData];
+    NSString* virtualComponentId = [_dataManager virtualComponentIdWithIndexPath:indexPath];
+    [_dataManager updateVirtualComponentData:virtualComponentId data:data];
+    NSMutableDictionary * newData = nil;
+    if (![data isKindOfClass:[NSDictionary class]]) {
+         newData = [NSMutableDictionary new];
+        [newData setObject:@"data" forKey:data];
+        data = newData;
+    }
+    newData = [data mutableCopy];
+    newData[@"@phase"] = @"update";
+    [self _updateDataForCellSlotAtIndexPath:indexPath data:[newData copy]];
+}
+
+- (void)insertRange:(NSInteger)index range:(NSArray*)data
+{
+    if (![data count]) {
+        WXLogDebug(@"ignore invalid insertRange");
+        return;
+    }
+    
+    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
+    NSRange range = NSMakeRange(index,[data count]);
+    NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
+    [newListData insertObjects:data atIndexes:indexSet];
+    [_dataManager updateData:newListData];
+    [_collectionView reloadData];
+}
+
+- (void)removeData:(NSInteger)index count:(NSInteger)count
+{
+    // TODO: bring the update logic to UpdateManager
+    
+    NSMutableArray *newListData = [[_dataManager data] mutableCopy];
+    if (index > [newListData count] || index + count - 1 > [newListData count]) {
+        
+        return;
+    }
+    NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, count)];
+    [newListData removeObjectsAtIndexes:indexSet];
+    __block NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray new];
+    [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
+        NSIndexPath* indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
+        [indexPaths addObject:indexPath];
+    }];
+    
+    [_dataManager updateData:newListData];
+    [_dataManager deleteVirtualComponentAtIndexPaths:indexPaths];
+    [UIView performWithoutAnimation:^{
+        [self->_collectionView deleteItemsAtIndexPaths:indexPaths];
+        [self->_collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
+    }];
+}
+
+- (void)moveData:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex
+{
+    // TODO: bring the update logic to UpdateManager
+    NSMutableArray *newListData = [[_dataManager data] mutableCopy];
+    id data = newListData[fromIndex];
+    [newListData removeObjectAtIndex:fromIndex];
+    [newListData insertObject:data atIndex:toIndex];
+    [_dataManager updateData:newListData];
+    
+    NSIndexPath *fromIndexPath = [NSIndexPath indexPathForItem:fromIndex inSection:0];
+    NSIndexPath *toIndexPath = [NSIndexPath indexPathForItem:toIndex inSection:0];
+    [UIView performWithoutAnimation:^{
+        [self->_collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
+    }];
+}
+
+- (void)scrollTo:(NSUInteger)index options:(NSDictionary *)options
+{
+    NSIndexPath *toIndexPath = [NSIndexPath indexPathForItem:index inSection:0];
+    BOOL animated = options[@"animated"] ? [WXConvert BOOL:options[@"animated"]] : NO;
+    [_collectionView scrollToItemAtIndexPath:toIndexPath atScrollPosition:UICollectionViewScrollPositionTop animated:animated];
+}
+
+#pragma mark - WXComponent Internal Methods
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+   [super _insertSubcomponent:subcomponent atIndex:index];
+    
+    if ([subcomponent isKindOfClass:[WXCellSlotComponent class]]) {
+        WXCellSlotComponent *cell = (WXCellSlotComponent*)subcomponent;
+        [self.weexInstance.componentManager _addUITask:^{
+            [_templateManager addTemplate:cell];
+        }];
+        
+        //TODO: update collection view if adding template
+    }
+}
+
+#pragma mark - Private
+
+- (void)_updateBindingData:(id)data forCell:(WXCellSlotComponent *)cellComponent atIndexPath:(NSIndexPath *)indexPath
+{
+    id originalData = data;
+    if (![originalData isKindOfClass:[NSDictionary class]]) {
+        if (_aliasKey) {
+            NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
+            [dictionary setObject:data forKey:_aliasKey];
+            data = dictionary;
+        } else {
+            return;
+        }
+    }
+    
+    if (!data[@"indexPath"] || !data[@"recycleListComponentRef"]) {
+        NSMutableDictionary * dataNew = [data mutableCopy];
+        dataNew[@"recycleListComponentRef"] = self.ref;
+        dataNew[@"indexPath"] = indexPath;
+        data = dataNew;
+    }
+    
+    if ([originalData isKindOfClass:[NSDictionary class]] && _aliasKey &&!data[@"phase"]) {
+        data = @{_aliasKey:data,@"aliasKey":_aliasKey};
+    }
+    
+    if (_indexKey) {
+        NSMutableDictionary *dataNew = [data mutableCopy];
+        dataNew[_indexKey] = @(indexPath.item);
+        data = dataNew;
+    }
+    
+#ifdef DEBUG
+    NSDate *startTime = [NSDate date];
+#endif
+    
+    WXPerformBlockSyncOnComponentThread(^{
+        [cellComponent updateCellData:[data copy]];
+    });
+#ifdef DEBUG
+    double duration = -[startTime timeIntervalSinceNow] * 1000;
+    WXLogDebug(@"cell:%li update data time:%f", (long)indexPath.item, duration);
+#endif
+    
+    NSValue *cachedSize = _sizeCache[indexPath];
+    if (!cachedSize || !CGSizeEqualToSize([cachedSize CGSizeValue] , cellComponent.calculatedFrame.size)) {
+        _sizeCache[indexPath] = [NSValue valueWithCGSize:cellComponent.calculatedFrame.size];
+        [_collectionView.collectionViewLayout invalidateLayout];
+    }
+    NSNumber *cachedSticky = _stickyCache[indexPath];
+    BOOL isSticky = cellComponent->_positionType == WXPositionTypeSticky;
+    if (!cachedSticky || [cachedSticky boolValue] != isSticky) {
+        _stickyCache[indexPath] = @(isSticky);
+    }
+}
+
+- (void)_updateListData:(NSArray *)newData
+        withCompletion:(WXRecycleListUpdateCompletion)completion
+             animation:(BOOL)animation
+{
+    if (![newData isKindOfClass:[NSArray class]]) {
+        WXLogError(@"wrong format of list data:%@", newData);
+        completion(NO);
+        return;
+    }
+    
+    NSArray *oldData = [_dataManager data];
+    [_updateManager updateWithNewData:newData oldData:oldData completion:completion animation:animation];
+}
+
+- (void)_updateScrollDirection:(WXScrollDirection)newScrollDirection
+{   
+    WXRecycleListLayout *layout = [self recycleListLayout];
+    _collectionView.collectionViewLayout = layout;
+}
+
+- (WXRecycleListLayout *)recycleListLayout
+{
+    WXRecycleListLayout *layout = [WXRecycleListLayout new];
+    layout.delegate = self;
+    // to show cells that original width / height is zero, otherwise cellForItemAtIndexPath will not be called
+    layout.minimumLineSpacing = 0.01;
+    layout.minimumInteritemSpacing = 0.01;
+    if (WXScrollDirectionHorizontal == self.scrollDirection) {
+        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
+    }
+    return layout;
+}
+
+#pragma mark - UICollectionViewDataSource
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
+{
+    return 1;
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
+{
+    return [_dataManager numberOfItems];
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    // 1. get the data relating to the cell
+    id data = [_dataManager dataAtIndex:indexPath.row];
+    
+    // 2. get the template type specified by data
+    NSString * templateType = [self templateType:indexPath];
+    _templateManager.collectionView = collectionView;
+    if (!templateType) {
+        WXLogError(@"Each data should have a value for %@ to indicate template type", _templateSwitchKey);
+        return nil;
+    }
+    
+    // 3. dequeue a cell component by template type
+    UICollectionViewCell *cellView = [_collectionView dequeueReusableCellWithReuseIdentifier:templateType forIndexPath:indexPath];
+    WXCellSlotComponent *cellComponent = (WXCellSlotComponent *)cellView.wx_component;
+    if (!cellComponent) {
+        cellComponent = [_templateManager dequeueCellSlotWithType:templateType forIndexPath:indexPath];
+        cellView.wx_component = cellComponent;
+        WXPerformBlockOnComponentThread(^{
+            //TODO: How can we avoid this?
+            [super _insertSubcomponent:cellComponent atIndex:self.subcomponents.count];
+        });
+    }
+    
+    // 4. binding the data to the cell component
+    [self _updateBindingData:data forCell:cellComponent atIndexPath:indexPath];
+
+    // 5. Add cell component's view to content view.
+    UIView *contentView = cellComponent.view;
+    if (contentView.superview == cellView.contentView) {
+        return cellView;
+    }
+    
+    for (UIView *view in cellView.contentView.subviews) {
+        [view removeFromSuperview];
+    }
+    [cellView.contentView addSubview:contentView];
+    [cellView setAccessibilityIdentifier:contentView.accessibilityIdentifier];
+    
+    WXLogDebug(@"Return cell view:%@, indexPath:%@", cellView, indexPath);
+    
+    [self handleAppear];
+    
+    return cellView;
+}
+
+- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
+{
+    return nil;
+}
+
+#pragma mark - UICollectionViewDelegate
+
+- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"will display cell:%@, at index path:%@", cell, indexPath);
+}
+
+- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"Did end displaying cell:%@, at index path:%@", cell, indexPath);
+}
+
+#pragma mark - UICollectionViewDelegateFlowLayout
+
+- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    NSValue *size = _sizeCache[indexPath];
+    if (size) {
+        return [size CGSizeValue];
+    } else {
+
+        WXCellSlotComponent *cell = [_templateManager templateWithType:[self templateType:indexPath]];
+        CGSize size = cell.calculatedFrame.size;
+        _sizeCache[indexPath] = [NSValue valueWithCGSize:size];
+        return CGSizeMake(_collectionView.frame.size.width, size.height);
+    }
+}
+
+#pragma mark - WXRecycleListLayoutDelegate
+
+- (BOOL)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout isNeedStickyForIndexPath:(NSIndexPath *)indexPath
+{
+    NSNumber *cachedSticky = _stickyCache[indexPath];
+    if (cachedSticky) {
+        return [cachedSticky boolValue];
+    } else {
+        return NO;
+    }
+}
+
+#pragma mark - WXRecycleListUpdateDelegate
+
+- (void)updateManager:(WXRecycleListUpdateManager *)manager willUpdateData:(id)newData
+{
+    [_dataManager updateData:newData];
+}
+
+- (void)updateManager:(WXRecycleListUpdateManager *)manager didUpdateData:(id)newData withSuccess:(BOOL)finished
+{
+    
+}
+
+- (NSString*)templateType:(NSIndexPath*)indexPath
+{
+    NSDictionary *data = [_dataManager dataAtIndex:indexPath.row];
+    // default is first template.
+    NSString *templateType = [_templateManager topTemplate].templateCaseType;
+    if (!data || ![data isKindOfClass:[NSDictionary class]]) {
+        return templateType;
+    }
+    
+    if (_templateSwitchKey &&data[_templateSwitchKey]){
+        templateType = data[_templateSwitchKey];
+    } else if (data[WXDefaultRecycleTemplateType]){
+        // read the default type.
+        templateType = data[WXDefaultRecycleTemplateType];
+    }
+    return templateType;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
deleted file mode 100644
index 7ca1de6..0000000
--- a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
+++ /dev/null
@@ -1,738 +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 "WXRecyclerComponent.h"
-#import "WXComponent_internal.h"
-#import "WXSDKInstance_private.h"
-#import "WXRecyclerDataController.h"
-#import "WXRecyclerUpdateController.h"
-#import "WXMultiColumnLayout.h"
-#import "WXHeaderComponent.h"
-#import "WXFooterComponent.h"
-#import "WXCellComponent.h"
-#import "WXAssert.h"
-#import "WXConvert.h"
-#import "WXUtility.h"
-#import "WXMonitor.h"
-#import "NSObject+WXSwizzle.h"
-#import "WXComponent+Events.h"
-#import "WXRecyclerDragController.h"
-
-static NSString * const kCollectionCellReuseIdentifier = @"WXRecyclerCell";
-static NSString * const kCollectionHeaderReuseIdentifier = @"WXRecyclerHeader";
-static float const kRecyclerNormalColumnGap = 32;
-
-typedef enum : NSUInteger {
-    WXRecyclerLayoutTypeMultiColumn,
-    WXRecyclerLayoutTypeFlex,
-    WXRecyclerLayoutTypeGrid,
-} WXRecyclerLayoutType;
-
-@interface WXCollectionView : UICollectionView
-
-@end
-
-@implementation WXCollectionView
-
-- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index
-{
-    [super insertSubview:view atIndex:index];
-}
-
-- (void)layoutSubviews
-{
-    [super layoutSubviews];
-    [self.wx_component layoutDidFinish];
-}
-
-- (void)setContentOffset:(CGPoint)contentOffset
-{
-    // FIXME: side effect caused by hooking _adjustContentOffsetIfNecessary.
-    // When UICollectionView is pulled down and finger releases,contentOffset will be set from -xxxx to about -0.5(greater than -0.5), then contentOffset will be reset to zero by calling _adjustContentOffsetIfNecessary.
-    // So hooking _adjustContentOffsetIfNecessary will always cause remaining 1px space between list's top and navigator.
-    // Demo: http://dotwe.org/895630945793a9a044e49abe39cbb77f
-    // Have to reset contentOffset to zero manually here.
-    if (fabs(contentOffset.y) < 0.5) {
-        contentOffset.y = 0;
-    }
-    if (isnan(contentOffset.x)) {
-        contentOffset.x = 0;
-    }
-    if(isnan(contentOffset.y)) {
-        contentOffset.y = 0;
-    }
-    
-    [super setContentOffset:contentOffset];
-}
-
-@end
-
-@interface WXCollectionViewCell : UICollectionViewCell
-
-@end
-
-@implementation WXCollectionViewCell
-
-- (void)prepareForReuse
-{
-    [super prepareForReuse];
-    
-    WXCellComponent *cellComponent = (WXCellComponent *)self.wx_component;
-    if (cellComponent.isRecycle && [cellComponent isViewLoaded] && [self.contentView.subviews containsObject:cellComponent.view]) {
-        [cellComponent _unloadViewWithReusing:YES];
-    }
-}
-
-@end
-
-@interface WXRecyclerComponent () <UICollectionViewDataSource, UICollectionViewDelegate, WXMultiColumnLayoutDelegate, WXRecyclerUpdateControllerDelegate, WXCellRenderDelegate, WXHeaderRenderDelegate, WXRecyclerDragControllerDelegate>
-
-@property (nonatomic, strong, readonly) WXRecyclerDataController *dataController;
-@property (nonatomic, strong, readonly) WXRecyclerUpdateController *updateController;
-@property (nonatomic, weak, readonly) UICollectionView *collectionView;
-@property (nonatomic, strong) WXRecyclerDragController *dragController;
-
-@end
-
-@implementation WXRecyclerComponent
-{
-    WXRecyclerLayoutType _layoutType;
-    UICollectionViewLayout *_collectionViewlayout;
-    
-    UIEdgeInsets _padding;
-    NSUInteger _previousLoadMoreCellNumber;
-}
-
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
-        [self _fillPadding];
-        
-        if ([type isEqualToString:@"waterfall"] || (attributes[@"layout"] && [attributes[@"layout"] isEqualToString:@"multi-column"])) {
-            // TODO: abstraction
-            _layoutType = WXRecyclerLayoutTypeMultiColumn;
-            CGFloat scaleFactor = weexInstance.pixelScaleFactor;
-            _collectionViewlayout = [WXMultiColumnLayout new];
-            WXMultiColumnLayout *layout = (WXMultiColumnLayout *)_collectionViewlayout;
-            layout.columnWidth = [WXConvert WXLength:attributes[@"columnWidth"] isFloat:YES scaleFactor:scaleFactor] ? : [WXLength lengthWithFloat:0.0 type:WXLengthTypeAuto];
-            layout.columnCount = [WXConvert WXLength:attributes[@"columnCount"] isFloat:NO scaleFactor:1.0] ? : [WXLength lengthWithInt:1 type:WXLengthTypeFixed];
-            if (attributes[@"leftGap"]) {
-                layout.leftGap = [WXConvert WXPixelType:attributes[@"leftGap"] scaleFactor:scaleFactor];
-            }
-            if (attributes[@"rightGap"]) {
-                layout.rightGap = [WXConvert WXPixelType:attributes[@"rightGap"] scaleFactor:scaleFactor];
-            }
-            layout.columnGap = [self _floatValueForColumnGap:([WXConvert WXLength:attributes[@"columnGap"] isFloat:YES scaleFactor:scaleFactor] ? : [WXLength lengthWithFloat:0.0 type:WXLengthTypeNormal])];
-            
-            layout.delegate = self;
-        } else {
-            _collectionViewlayout = [UICollectionViewLayout new];
-        }
-        
-        _dataController = [WXRecyclerDataController new];
-        _updateController = [WXRecyclerUpdateController new];
-        _updateController.delegate = self;
-        [self fixFlicker];
-        
-        if ([attributes[@"draggable"] boolValue]) {
-            // lazy load
-            _dragController = [WXRecyclerDragController new];
-            _dragController.delegate = self;
-            if([attributes[@"dragTriggerType"]  isEqual: @"pan"]){
-                _dragController.dragTriggerType = WXRecyclerDragTriggerPan;
-            }
-            _dragController.isDragable = YES;
-        }
-    }
-    
-    return self;
-}
-
-- (void)dealloc
-{
-    _collectionView.delegate = nil;
-    _collectionView.dataSource = nil;
-}
-
-#pragma mark - Public Subclass Methods
-
-- (UIView *)loadView
-{
-    return [[WXCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_collectionViewlayout];
-}
-
-- (void)viewDidLoad
-{
-    [super viewDidLoad];
-    
-    _collectionView = (UICollectionView *)self.view;
-    _collectionView.allowsSelection = NO;
-    _collectionView.allowsMultipleSelection = NO;
-    _collectionView.dataSource = self;
-    _collectionView.delegate = self;
-    
-    [_collectionView registerClass:[WXCollectionViewCell class] forCellWithReuseIdentifier:kCollectionCellReuseIdentifier];
-    [_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:kCollectionSupplementaryViewKindHeader withReuseIdentifier:kCollectionHeaderReuseIdentifier];
-    
-    _dragController.dragingCell = [[WXCollectionViewCell alloc] initWithFrame:CGRectMake(0, 0, 100, 100/2.0f)];
-    _dragController.collectionView = _collectionView;
-    
-    [self performUpdatesWithCompletion:^(BOOL finished) {
-        
-    }];
-}
-
-- (void)viewWillUnload
-{
-    [super viewWillUnload];
-    
-    _collectionView.dataSource = nil;
-    _collectionView.delegate = nil;
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
-    [super updateAttributes:attributes];
-    
-    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
-        CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
-        WXMultiColumnLayout *layout = (WXMultiColumnLayout *)_collectionViewlayout;
-        BOOL needUpdateLayout = NO;
-        
-        if ([attributes[@"draggable"] boolValue]) {
-            if (!_dragController) {  // lazy load
-                _dragController = [WXRecyclerDragController new];
-                _dragController.delegate = self;
-            }
-            if([attributes[@"dragTriggerType"]  isEqual: @"pan"]){
-                _dragController.dragTriggerType = WXRecyclerDragTriggerPan;
-            }
-            _dragController.isDragable = YES;
-        } else {
-            _dragController.isDragable = NO;
-        }
-        
-        if (attributes[@"columnWidth"]) {
-            layout.columnWidth = [WXConvert WXLength:attributes[@"columnWidth"] isFloat:YES scaleFactor:scaleFactor];
-            needUpdateLayout = YES;
-        }
-        
-        if (attributes[@"columnCount"]) {
-            layout.columnCount = [WXConvert WXLength:attributes[@"columnCount"] isFloat:NO scaleFactor:1.0];
-            
-            needUpdateLayout = YES;
-        }
-        if (attributes[@"columnGap"]) {
-            layout.columnGap = [self _floatValueForColumnGap:([WXConvert WXLength:attributes[@"columnGap"] isFloat:YES scaleFactor:scaleFactor])];
-            needUpdateLayout = YES;
-        }
-        if (attributes[@"leftGap"]) {
-            layout.leftGap = [WXConvert WXPixelType:attributes[@"leftGap"] scaleFactor:scaleFactor];
-        }
-        if (attributes[@"rightGap"]) {
-            layout.rightGap = [WXConvert WXPixelType:attributes[@"rightGap"] scaleFactor:scaleFactor];
-        }
-        
-        if (needUpdateLayout) {
-            for (WXComponent *component in self.subcomponents) {
-                [component setNeedsLayout];
-            }
-            
-            [self.collectionView reloadData];
-            [self.collectionView.collectionViewLayout invalidateLayout];
-        }
-    }
-    
-}
-
-- (void)setContentSize:(CGSize)contentSize
-{
-    // Do Nothing
-}
-
-- (void)adjustSticky
-{
-    // Do Nothing, sticky is adjusted by layout
-}
-
-#pragma mark - Private Subclass Methods
-
-- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles
-{
-    [super _updateStylesOnComponentThread:styles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
-    
-    [self _fillPadding];
-}
-
-- (void)_handleFirstScreenTime
-{
-    // Do Nothing, firstScreenTime is set by cellDidRendered:
-}
-
-- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset animated:(BOOL)animated
-{
-    CGPoint contentOffset = _collectionView.contentOffset;
-    CGFloat contentOffsetY = 0;
-    
-    CGRect rect;
-    while (component) {
-        if ([component isKindOfClass:[WXCellComponent class]]) {
-            NSIndexPath *toIndexPath = [self.dataController indexPathForCell:(WXCellComponent *)component];
-            UICollectionViewLayoutAttributes *attributes = [_collectionView layoutAttributesForItemAtIndexPath:toIndexPath];
-            rect = attributes.frame;
-            break;
-        }
-        if ([component isKindOfClass:[WXHeaderComponent class]]) {
-            NSUInteger toIndex = [self.dataController indexForHeader:(WXHeaderComponent *)component];
-            UICollectionViewLayoutAttributes *attributes = [_collectionView layoutAttributesForSupplementaryElementOfKind:kCollectionSupplementaryViewKindHeader atIndexPath:[NSIndexPath indexPathWithIndex:toIndex]];
-            rect = attributes.frame;
-            break;
-        }
-        contentOffsetY += component.calculatedFrame.origin.y;
-        component = component.supercomponent;
-    }
-    
-    contentOffsetY += rect.origin.y;
-    contentOffsetY += offset * self.weexInstance.pixelScaleFactor;
-    
-    if (_collectionView.contentSize.height >= _collectionView.frame.size.height && contentOffsetY > _collectionView.contentSize.height - _collectionView.frame.size.height) {
-        contentOffset.y = _collectionView.contentSize.height - _collectionView.frame.size.height;
-    } else {
-        contentOffset.y = contentOffsetY;
-    }
-    
-    [_collectionView setContentOffset:contentOffset animated:animated];
-    
-}
-
-- (void)performUpdatesWithCompletion:(void (^)(BOOL finished))completion
-{
-    WXAssertMainThread();
-    
-    //TODO: support completion
-    
-    if (![self isViewLoaded]) {
-        completion(NO);
-    }
-    
-    NSArray *oldData = [self.dataController.sections copy];
-    NSArray *newData = [self _sectionArrayFromComponents:self.subcomponents];
-    
-    [_updateController performUpdatesWithNewData:newData oldData:oldData view:_collectionView];
-}
-
-- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    if ([subcomponent isKindOfClass:[WXCellComponent class]]) {
-        ((WXCellComponent *)subcomponent).delegate = self;
-    } else if ([subcomponent isKindOfClass:[WXHeaderComponent class]]) {
-        ((WXHeaderComponent *)subcomponent).delegate = self;
-    }
-    
-    [super _insertSubcomponent:subcomponent atIndex:index];
-    
-    if (![subcomponent isKindOfClass:[WXHeaderComponent class]]
-        && ![subcomponent isKindOfClass:[WXCellComponent class]]) {
-        return;
-    }
-    
-    WXPerformBlockOnMainThread(^{
-        [self performUpdatesWithCompletion:^(BOOL finished) {
-            
-        }];
-    });
-}
-
-- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
-    //Here will not insert cell/header/footer's view again
-    if (![subcomponent isKindOfClass:[WXCellComponent class]]
-        && ![subcomponent isKindOfClass:[WXHeaderComponent class]]
-        && ![subcomponent isKindOfClass:[WXFooterComponent class]]) {
-        [super insertSubview:subcomponent atIndex:index];
-    }
-}
-
-#pragma mark - WXRecyclerUpdateControllerDelegate
-
-- (void)updateController:(WXRecyclerUpdateController *)controller willPerformUpdateWithNewData:(NSArray<WXSectionDataController *> *)newData
-{
-    if (newData) {
-        [self.dataController updateData:newData];
-    }
-}
-
-- (void)updateController:(WXRecyclerUpdateController *)controller didPerformUpdateWithFinished:(BOOL)finished
-{
-    
-}
-
-#pragma mark - UICollectionViewDataSource
-
-- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
-{
-    WXLogDebug(@"section number:%li", (long)[self.dataController numberOfSections]);
-    return [self.dataController numberOfSections];
-}
-
-- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
-{
-    NSInteger numberOfItems = [self.dataController numberOfItemsInSection:section];
-    
-    WXLogDebug(@"Number of items is %ld in section:%ld", (long)numberOfItems, (long)section);
-    
-    return numberOfItems;
-}
-
-- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    WXLogDebug(@"Getting cell at indexPath:%@", indexPath);
-    
-    WXCollectionViewCell *cellView = [_collectionView dequeueReusableCellWithReuseIdentifier:kCollectionCellReuseIdentifier forIndexPath:indexPath];
-    
-    UIView *contentView = [self.dataController cellForItemAtIndexPath:indexPath];
-    
-    cellView.wx_component = contentView.wx_component;
-    
-    [self.dragController goThroughAnchor:cellView.wx_component indexPath:indexPath];
-    
-    if (contentView.superview == cellView.contentView) {
-        return cellView;
-    }
-    
-    for (UIView *view in cellView.contentView.subviews) {
-        [view removeFromSuperview];
-    }
-    
-    [cellView.contentView addSubview:contentView];
-    [cellView setAccessibilityIdentifier:contentView.accessibilityIdentifier];
-    
-    return cellView;
-}
-
-- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
-{
-    UICollectionReusableView *reusableView = nil;
-    if ([kind isEqualToString:kCollectionSupplementaryViewKindHeader]) {
-        reusableView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kCollectionHeaderReuseIdentifier forIndexPath:indexPath];
-        UIView *contentView = [self.dataController viewForHeaderAtIndexPath:indexPath];
-        if (contentView.superview != reusableView) {
-            for (UIView *view in reusableView.subviews) {
-                [view removeFromSuperview];
-            }
-            
-            [reusableView addSubview:contentView];
-        }
-    }
-    
-    return reusableView;
-}
-
-#pragma mark - UICollectionViewDelegate
-
-- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    WXLogDebug(@"will display cell:%@, at index path:%@", cell, indexPath);
-}
-
-- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    WXLogDebug(@"Did end displaying cell:%@, at index path:%@", cell, indexPath);
-}
-
-#pragma mark - WXMultiColumnLayoutDelegate
-
-- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView insetForLayout:(UICollectionViewLayout *)collectionViewLayout
-{
-    return _padding;
-}
-
-- (CGFloat)collectionView:(UICollectionView *)collectionView contentWidthForLayout:(UICollectionViewLayout *)collectionViewLayout
-{
-    return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
-}
-
-- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    CGSize itemSize = [self.dataController sizeForItemAtIndexPath:indexPath];
-    return itemSize.height;
-}
-
-- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForHeaderInSection:(NSInteger)section
-{
-    CGSize headerSize = [self.dataController sizeForHeaderAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
-    return headerSize.height;
-}
-
-- (BOOL)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout hasHeaderInSection:(NSInteger)section
-{
-    return [self.dataController hasHeaderInSection:section];
-}
-
-- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout isNeedStickyForHeaderInSection:(NSInteger)section
-{
-    return [self.dataController isStickyForHeaderAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
-}
-
-#pragma mark - WXHeaderRenderDelegate
-
-- (float)headerWidthForLayout:(WXHeaderComponent *)header
-{
-    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
-        return ((WXMultiColumnLayout *)_collectionViewlayout).computedHeaderWidth;
-    }
-    
-    return 0.0;
-}
-
-- (void)headerDidLayout:(WXHeaderComponent *)header
-{
-    WXPerformBlockOnMainThread(^{
-        [self.collectionView.collectionViewLayout invalidateLayout];
-    });
-}
-
-- (void)headerDidRemove:(WXHeaderComponent *)header
-{
-    WXPerformBlockOnMainThread(^{
-        [self performUpdatesWithCompletion:^(BOOL finished) {
-            
-        }];
-    });
-}
-
-#pragma mark - WXCellRenderDelegate
-
-- (float)containerWidthForLayout:(WXCellComponent *)cell
-{
-    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
-        return ((WXMultiColumnLayout *)_collectionViewlayout).computedColumnWidth;
-    }
-    
-    return 0.0;
-}
-
-- (void)cellDidLayout:(WXCellComponent *)cell
-{
-    BOOL previousLayoutComplete = cell.isLayoutComplete;
-    cell.isLayoutComplete = YES;
-    WXPerformBlockOnMainThread(^{
-        if (previousLayoutComplete) {
-            [self.updateController reloadItemsAtIndexPath:[self.dataController indexPathForCell:cell]];
-        } else {
-            [self performUpdatesWithCompletion:^(BOOL finished) {
-            }];
-        }
-    });
-}
-
-- (void)cellDidRendered:(WXCellComponent *)cell
-{
-    if (WX_MONITOR_INSTANCE_PERF_IS_RECORDED(WXPTFirstScreenRender, self.weexInstance) && !self.weexInstance.onRenderProgress) {
-        return;
-    }
-    
-    NSIndexPath *indexPath = [self.dataController indexPathForCell:cell];
-    
-    UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath];
-    CGRect cellRect = attributes.frame;
-    if (cellRect.origin.y + cellRect.size.height >= _collectionView.frame.size.height) {
-        WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, self.weexInstance);
-    }
-    
-    if (self.weexInstance.onRenderProgress) {
-        CGRect renderRect = [_collectionView convertRect:cellRect toView:self.weexInstance.rootView];
-        self.weexInstance.onRenderProgress(renderRect);
-    }
-}
-
-- (void)cellDidRemove:(WXCellComponent *)cell
-{
-    if (cell.isLayoutComplete) {
-        WXPerformBlockOnMainThread(^{
-            [self performUpdatesWithCompletion:^(BOOL finished) {
-            }];
-        });
-    }
-}
-
-- (void)cell:(WXCellComponent *)cell didMoveToIndex:(NSUInteger)index
-{
-    if (cell.isLayoutComplete) {
-        WXPerformBlockOnMainThread(^{
-            [self performUpdatesWithCompletion:^(BOOL finished) {
-            }];
-        });
-    }
-}
-
-#pragma mark - Load More Event
-
-- (void)setLoadmoreretry:(NSUInteger)loadmoreretry
-{
-    if (loadmoreretry != self.loadmoreretry) {
-        _previousLoadMoreCellNumber = 0;
-    }
-    
-    [super setLoadmoreretry:loadmoreretry];
-}
-
-- (void)loadMore
-{
-    [super loadMore];
-    
-    _previousLoadMoreCellNumber = [self totalNumberOfCells];
-}
-
-- (BOOL)isNeedLoadMore
-{
-    BOOL superNeedLoadMore = [super isNeedLoadMore];
-    return superNeedLoadMore && _previousLoadMoreCellNumber != [self totalNumberOfCells];
-}
-
-- (NSUInteger)totalNumberOfCells
-{
-    NSUInteger cellNumber = 0;
-    NSUInteger sectionCount = [_collectionView numberOfSections];
-    for (int section = 0; section < sectionCount; section ++) {
-        cellNumber += [_collectionView numberOfItemsInSection:section];
-    }
-    
-    return cellNumber;
-}
-
-- (void)resetLoadmore{
-    [super resetLoadmore];
-    _previousLoadMoreCellNumber = 0;
-}
-
-#pragma mark - Private
-
-- (float)_floatValueForColumnGap:(WXLength *)gap
-{
-    if (gap.isNormal) {
-        return kRecyclerNormalColumnGap * self.weexInstance.pixelScaleFactor;
-    } else {
-        return gap.floatValue;
-    }
-}
-
-- (void)_fillPadding
-{
-    UIEdgeInsets padding = {
-        WXFloorPixelValue(self.cssNode->style.padding[CSS_TOP] + self.cssNode->style.border[CSS_TOP]),
-        WXFloorPixelValue(self.cssNode->style.padding[CSS_LEFT] + self.cssNode->style.border[CSS_LEFT]),
-        WXFloorPixelValue(self.cssNode->style.padding[CSS_BOTTOM] + self.cssNode->style.border[CSS_BOTTOM]),
-        WXFloorPixelValue(self.cssNode->style.padding[CSS_RIGHT] + self.cssNode->style.border[CSS_RIGHT])
-    };
-    
-    if (!UIEdgeInsetsEqualToEdgeInsets(padding, _padding)) {
-        _padding = padding;
-        [self setNeedsLayout];
-        
-        for (WXComponent *component in self.subcomponents) {
-            [component setNeedsLayout];
-        }
-        
-        if (_collectionView) {
-            WXPerformBlockOnMainThread(^{
-                [_collectionView.collectionViewLayout invalidateLayout];
-            });
-        }
-    }
-}
-
-- (NSArray<WXSectionDataController *> *)_sectionArrayFromComponents:(NSArray<WXComponent *> *)components
-{
-    NSMutableArray<WXSectionDataController *> *sectionArray = [NSMutableArray array];
-    NSMutableArray<WXCellComponent *> *cellArray = [NSMutableArray array];
-    WXSectionDataController *currentSection;
-    
-    for (int i = 0; i < components.count; i++) {
-        if (!currentSection) {
-            currentSection = [WXSectionDataController new];
-        }
-        
-        WXComponent* component = components[i];
-        
-        if ([component isKindOfClass:[WXHeaderComponent class]]) {
-            if (i != 0 && (currentSection.headerComponent || cellArray.count > 0)) {
-                currentSection.cellComponents = [cellArray copy];
-                [sectionArray addObject:currentSection];
-                currentSection = [WXSectionDataController new];
-                [cellArray removeAllObjects];
-            }
-            currentSection.headerComponent = (WXHeaderComponent *)component;
-        } else if ([component isKindOfClass:[WXCellComponent class]]
-                   && ((WXCellComponent *)component).isLayoutComplete) {
-            [cellArray addObject:(WXCellComponent *)component];
-        } else if ([component isKindOfClass:[WXFooterComponent class]]) {
-            currentSection.footerComponent = component;
-        } else {
-            continue;
-        }
-    }
-    
-    if (cellArray.count > 0 || currentSection.headerComponent) {
-        currentSection.cellComponents = [cellArray copy];
-        [sectionArray addObject:currentSection];
-    }
-    
-    return sectionArray;
-}
-
-- (void)fixFlicker
-{
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        // FIXME:(ง •̀_•́)ง┻━┻ Stupid scoll view, always reset content offset to zero by calling _adjustContentOffsetIfNecessary after insert cells.
-        // So if you pull down list while list is rendering, the list will be flickering.
-        // Demo:
-        // Have to hook _adjustContentOffsetIfNecessary here.
-        // Any other more elegant way?
-        NSString *a = @"ntOffsetIfNe";
-        NSString *b = @"adjustConte";
-        
-        NSString *originSelector = [NSString stringWithFormat:@"_%@%@cessary", b, a];
-        [[self class] weex_swizzle:[WXCollectionView class] Method:NSSelectorFromString(originSelector) withMethod:@selector(fixedFlickerSelector)];
-    });
-}
-
-#define mark dragControllerDelegate
-
-- (void)updateDataSource{
-    NSMutableArray *oldComponents = [[NSMutableArray alloc] initWithArray:self.dataController.sections[self.dragController.startIndexPath.section].cellComponents];
-    if(oldComponents.count > 1){
-        WXCellComponent *startComponent = self.dataController.sections[self.dragController.startIndexPath.section].cellComponents[self.dragController.startIndexPath.item];
-        [oldComponents removeObject:startComponent];
-        [oldComponents insertObject:startComponent atIndex:self.dragController.targetIndexPath.item];
-        self.dataController.sections[self.dragController.startIndexPath.section].cellComponents = oldComponents;
-    }
-}
-
-- (void)dragFireEvent:(NSString *)eventName params:(NSDictionary *)params{
-    [self fireEvent:eventName params:params];
-}
-
-- (void)fixedFlickerSelector
-{
-    // DO NOT delete this method.
-}
-
-@end



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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
new file mode 100644
index 0000000..c8c6e3f
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
@@ -0,0 +1,1158 @@
+/*
+ * 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 "WXComponentManager.h"
+#import "WXComponent.h"
+#import "WXComponent_internal.h"
+#import "WXComponent+DataBinding.h"
+#import "WXComponentFactory.h"
+#import "WXDefine.h"
+#import "NSArray+Weex.h"
+#import "WXSDKInstance.h"
+#import "WXAssert.h"
+#import "WXUtility.h"
+#import "WXMonitor.h"
+#import "WXScrollerProtocol.h"
+#import "WXSDKManager.h"
+#import "WXSDKError.h"
+#import "WXInvocationConfig.h"
+#import "WXHandlerFactory.h"
+#import "WXValidateProtocol.h"
+#import "WXPrerenderManager.h"
+#import "WXTracingManager.h"
+#import "WXLayoutDefine.h"
+#import "WXSDKInstance_performance.h"
+#import "WXRootView.h"
+#import "WXComponent+Layout.h"
+
+
+
+static NSThread *WXComponentThread;
+
+#define WXAssertComponentExist(component)  WXAssert(component, @"component not exists")
+
+
+@implementation WXComponentManager
+{
+    __weak WXSDKInstance *_weexInstance;
+    BOOL _isValid;
+    
+    BOOL _stopRunning;
+    NSUInteger _noTaskTickCount;
+    
+    // access only on component thread
+    NSMapTable<NSString *, WXComponent *> *_indexDict;
+    NSMutableArray<dispatch_block_t> *_uiTaskQueue;
+    NSMutableDictionary *_uiPrerenderTaskQueue;
+
+    WXComponent *_rootComponent;
+    NSMutableArray *_fixedComponents;
+//#ifndef USE_FLEX
+    css_node_t *_rootCSSNode;
+//#else
+    WeexCore::WXCoreLayoutNode* _rootFlexCSSNode;
+//#endif
+    CADisplayLink *_displayLink;
+}
+
++ (instancetype)sharedManager
+{
+    static id _sharedInstance = nil;
+    static dispatch_once_t oncePredicate;
+    dispatch_once(&oncePredicate, ^{
+        _sharedInstance = [[self alloc] init];
+    });
+    return _sharedInstance;
+}
+
+- (instancetype)initWithWeexInstance:(id)weexInstance
+{
+    if (self = [self init]) {
+        _weexInstance = weexInstance;
+        
+        _indexDict = [NSMapTable strongToWeakObjectsMapTable];
+        _fixedComponents = [NSMutableArray wx_mutableArrayUsingWeakReferences];
+        _uiTaskQueue = [NSMutableArray array];
+        _isValid = YES;
+        [self _startDisplayLink];
+    }
+    
+    return self;
+}
+
+- (void)dealloc
+{
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+         free_css_node(_rootCSSNode);
+    }
+   
+//#else
+    
+    if(_rootFlexCSSNode){
+        delete _rootFlexCSSNode;
+        
+       // WeexCore::WXCoreLayoutNode::freeNodeTree(_rootFlexCSSNode);
+        _rootFlexCSSNode=nullptr;
+    }
+//#endif
+    [NSMutableArray wx_releaseArray:_fixedComponents];
+}
+
+#pragma mark Thread Management
+
++ (NSThread *)componentThread
+{
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        WXComponentThread = [[NSThread alloc] initWithTarget:[self sharedManager] selector:@selector(_runLoopThread) object:nil];
+        [WXComponentThread setName:WX_COMPONENT_THREAD_NAME];
+        if(WX_SYS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
+            [WXComponentThread setQualityOfService:[[NSThread mainThread] qualityOfService]];
+        } else {
+            [WXComponentThread setThreadPriority:[[NSThread mainThread] threadPriority]];
+        }
+        
+        [WXComponentThread start];
+    });
+    
+    return WXComponentThread;
+}
+
+- (void)_runLoopThread
+{
+    [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
+    
+    while (!_stopRunning) {
+        @autoreleasepool {
+            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+        }
+    }
+}
+
++ (void)_performBlockOnComponentThread:(void (^)(void))block
+{
+    if([NSThread currentThread] == [self componentThread]){
+        block();
+    } else {
+        [self performSelector:@selector(_performBlockOnComponentThread:)
+                     onThread:WXComponentThread
+                   withObject:[block copy]
+                waitUntilDone:NO];
+    }
+}
+
++ (void)_performBlockSyncOnComponentThread:(void (^)(void))block
+{
+    if([NSThread currentThread] == [self componentThread]){
+        block();
+    } else {
+        [self performSelector:@selector(_performBlockOnComponentThread:)
+                     onThread:WXComponentThread
+                   withObject:[block copy]
+                waitUntilDone:YES];
+    }
+}
+
+- (void)startComponentTasks
+{
+    [self _awakeDisplayLink];
+}
+
+- (void)rootViewFrameDidChange:(CGRect)frame
+{
+    WXAssertComponentThread();
+//#ifndef USE_FLEX
+    
+    if (![WXComponent isUseFlex]) {
+        if (_rootCSSNode) {
+            [self _applyRootFrame:frame toRootCSSNode:_rootCSSNode];
+            if (!_rootComponent.styles[@"width"]) {
+                _rootComponent.cssNode->style.dimensions[CSS_WIDTH] = frame.size.width ?: CSS_UNDEFINED;
+            }
+            if (!_rootComponent.styles[@"height"]) {
+                _rootComponent.cssNode->style.dimensions[CSS_HEIGHT] = frame.size.height ?: CSS_UNDEFINED;
+            }
+        }
+    }
+//#else
+    else
+    {
+        if (_rootFlexCSSNode) {
+            [self _applyRootFrame:frame];
+            if (!_rootComponent.styles[@"width"]) {
+                _rootComponent.flexCssNode->setStyleWidth(frame.size.width ?:FlexUndefined,NO);
+            }
+            if (!_rootComponent.styles[@"height"]) {
+                _rootComponent.flexCssNode->setStyleHeight(frame.size.height ?:FlexUndefined);
+            }
+        }
+    }
+//#endif
+    [_rootComponent setNeedsLayout];
+    [self startComponentTasks];
+}
+
+//#ifndef USE_FLEX
+- (void)_applyRootFrame:(CGRect)rootFrame toRootCSSNode:(css_node_t *)rootCSSNode
+{
+    _rootCSSNode->style.position[CSS_LEFT] = self.weexInstance.frame.origin.x;
+    _rootCSSNode->style.position[CSS_TOP] = self.weexInstance.frame.origin.y;
+    // if no instance width/height, use layout width/height, as Android's wrap_content
+    _rootCSSNode->style.dimensions[CSS_WIDTH] = self.weexInstance.frame.size.width ?: CSS_UNDEFINED;
+    _rootCSSNode->style.dimensions[CSS_HEIGHT] =  self.weexInstance.frame.size.height ?: CSS_UNDEFINED;
+}
+//#else
+- (void)_applyRootFrame:(CGRect)rootFrame{
+    _rootFlexCSSNode->setStylePosition(WeexCore::kPositionEdgeLeft, self.weexInstance.frame.origin.x);
+    _rootFlexCSSNode->setStylePosition(WeexCore::kPositionEdgeTop, self.weexInstance.frame.origin.y);
+    _rootFlexCSSNode->setStyleWidth(self.weexInstance.frame.size.width ?: FlexUndefined,NO);
+    _rootFlexCSSNode->setStyleHeight(self.weexInstance.frame.size.height ?: FlexUndefined);
+}
+//#endif
+
+- (void)_addUITask:(void (^)(void))block
+{
+    if(!_uiPrerenderTaskQueue){
+        _uiPrerenderTaskQueue = [NSMutableDictionary new];
+    }
+    if(self.weexInstance.needPrerender){
+        NSMutableArray<dispatch_block_t> *tasks  = [_uiPrerenderTaskQueue objectForKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
+        if(!tasks){
+            tasks = [NSMutableArray new];
+        }
+        [tasks addObject:block];
+        [_uiPrerenderTaskQueue setObject:tasks forKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
+    }else{
+        [_uiTaskQueue addObject:block];
+    }
+}
+
+- (void)excutePrerenderUITask:(NSString *)url
+{
+    NSMutableArray *tasks  = [_uiPrerenderTaskQueue objectForKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
+    for (id block in tasks) {
+        [_uiTaskQueue addObject:block];
+    }
+    tasks = [NSMutableArray new];
+    [_uiPrerenderTaskQueue setObject:tasks forKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
+}
+
+#pragma mark Component Tree Building
+
+- (void)createRoot:(NSDictionary *)data
+{
+    WXAssertComponentThread();
+    WXAssertParam(data);
+    
+    _rootComponent = [self _buildComponentForData:data supercomponent:nil];
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        [self _initRootCSSNode];
+    }
+//#else
+    else
+    {
+        [self _initRootFlexCssNode];
+        _rootFlexCSSNode->addChildAt(_rootComponent.flexCssNode, (uint32_t)[_fixedComponents count]);
+    }
+//#endif
+    
+    NSArray *subcomponentsData = [data valueForKey:@"children"];
+    if (subcomponentsData) {
+        BOOL appendTree = [_rootComponent.attributes[@"append"] isEqualToString:@"tree"];
+        for(NSDictionary *subcomponentData in subcomponentsData){
+            [self _recursivelyAddComponent:subcomponentData toSupercomponent:_rootComponent atIndex:-1 appendingInTree:appendTree];
+        }
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    WX_MONITOR_INSTANCE_PERF_END(WXFirstScreenJSFExecuteTime, self.weexInstance);
+    [self _addUITask:^{
+        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:data[@"ref"] className:nil name:data[@"type"] phase:WXTracingBegin functionName:@"createBody" options:@{@"threadName":WXTUIThread}];
+        __strong typeof(self) strongSelf = weakSelf;
+        strongSelf.weexInstance.rootView.wx_component = strongSelf->_rootComponent;
+        [strongSelf.weexInstance.rootView addSubview:strongSelf->_rootComponent.view];
+        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:data[@"ref"] className:nil name:data[@"type"] phase:WXTracingEnd functionName:@"createBody" options:@{@"threadName":WXTUIThread}];
+    }];
+    
+    
+}
+
+//#ifndef USE_FLEX
+static bool rootNodeIsDirty(void *context)
+{
+    WXComponentManager *manager = (__bridge WXComponentManager *)(context);
+    return [manager->_rootComponent needsLayout];
+}
+
+static css_node_t * rootNodeGetChild(void *context, int i)
+{
+    WXComponentManager *manager = (__bridge WXComponentManager *)(context);
+    if (i == 0) {
+        return manager->_rootComponent.cssNode;
+    } else if(manager->_fixedComponents.count >= i) {
+        return ((WXComponent *)((manager->_fixedComponents)[i-1])).cssNode;
+    }
+    
+    return NULL;
+}
+//#endif
+
+- (void)addComponent:(NSDictionary *)componentData toSupercomponent:(NSString *)superRef atIndex:(NSInteger)index appendingInTree:(BOOL)appendingInTree
+{
+    WXAssertComponentThread();
+    WXAssertParam(componentData);
+    WXAssertParam(superRef);
+    
+    WXComponent *supercomponent = [_indexDict objectForKey:superRef];
+    WXAssertComponentExist(supercomponent);
+    
+    if ([WXComponent isUseFlex] && !supercomponent) {
+        WXLogWarning(@"addComponent,superRef from js never exit ! check JS action, supRef:%@",superRef);
+        return;
+    }
+    
+    [self _recursivelyAddComponent:componentData toSupercomponent:supercomponent atIndex:index appendingInTree:appendingInTree];
+}
+
+- (void)_recursivelyAddComponent:(NSDictionary *)componentData toSupercomponent:(WXComponent *)supercomponent atIndex:(NSInteger)index appendingInTree:(BOOL)appendingInTree
+{
+    WXComponent *component = [self _buildComponentForData:componentData supercomponent:supercomponent];
+    if (!supercomponent.subcomponents) {
+        index = 0;
+    } else {
+        index = (index == -1 ? supercomponent->_subcomponents.count : index);
+    }
+    
+#ifdef DEBUG
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        WXLogDebug(@"flexLayout -> _recursivelyAddComponent : super:(%@,%@):[%f,%f] ,child:(%@,%@):[%f,%f],childClass:%@",
+              supercomponent.type,
+              supercomponent.ref,
+              supercomponent.cssNode->style.dimensions[CSS_WIDTH],
+              supercomponent.cssNode->style.dimensions[CSS_HEIGHT],
+              component.type,
+              component.ref,
+              component.cssNode->style.dimensions[CSS_WIDTH],
+              component.cssNode->style.dimensions[CSS_HEIGHT]
+              ,NSStringFromClass([component class])
+              );
+    }
+//#else
+    else
+    {
+        WXLogDebug(@"flexLayout -> _recursivelyAddComponent : super:(%@,%@):[%f,%f] ,child:(%@,%@):[%f,%f],childClass:%@",
+              supercomponent.type,
+              supercomponent.ref,
+              supercomponent.flexCssNode->getStyleWidth(),
+              supercomponent.flexCssNode->getStyleHeight(),
+              component.type,
+              component.ref,
+              component.flexCssNode->getStyleWidth(),
+              component.flexCssNode->getStyleHeight()
+              ,NSStringFromClass([component class])
+              );
+    }
+//#endif
+#endif //DEBUG
+
+    
+    [supercomponent _insertSubcomponent:component atIndex:index];
+    // use _lazyCreateView to forbid component like cell's view creating
+    if(supercomponent && component && supercomponent->_lazyCreateView) {
+        component->_lazyCreateView = YES;
+    }
+    
+    [self recordMaximumVirtualDom:component];
+    
+    if (!component->_isTemplate) {
+        __weak typeof(self) weakSelf = self;
+        BOOL isFSCreateFinish = [self weexInstance].isJSCreateFinish;
+        [self _addUITask:^{
+            [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:componentData[@"ref"] className:nil name:componentData[@"type"] phase:WXTracingBegin functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
+            [supercomponent insertSubview:component atIndex:index];
+            [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:componentData[@"ref"] className:nil name:componentData[@"type"] phase:WXTracingEnd functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
+            [weakSelf onElementChange:isFSCreateFinish];
+        }];
+    }
+    
+    NSArray *subcomponentsData = [componentData valueForKey:@"children"];
+    
+    BOOL appendTree = !appendingInTree && [component.attributes[@"append"] isEqualToString:@"tree"];
+    // if ancestor is appending tree, child should not be laid out again even it is appending tree.
+    for(NSDictionary *subcomponentData in subcomponentsData){
+        [self _recursivelyAddComponent:subcomponentData toSupercomponent:component atIndex:-1 appendingInTree:appendTree || appendingInTree];
+    }
+    
+    [component _didInserted];
+    
+    if (appendTree) {
+        // If appending tree,force layout in case of too much tasks piling up in syncQueue
+        [self _layoutAndSyncUI];
+    }
+}
+
+- (void)moveComponent:(NSString *)ref toSuper:(NSString *)superRef atIndex:(NSInteger)index
+{
+    WXAssertComponentThread();
+    WXAssertParam(ref);
+    WXAssertParam(superRef);
+    
+    WXComponent *component = [_indexDict objectForKey:ref];
+    WXComponent *newSupercomponent = [_indexDict objectForKey:superRef];
+    WXAssertComponentExist(component);
+    WXAssertComponentExist(newSupercomponent);
+    
+    if (component.supercomponent == newSupercomponent && [newSupercomponent.subcomponents indexOfObject:component] < index) {
+        // if the supercomponent moved to is the same as original supercomponent,
+        // unify it into the index after removing.
+        index--;
+    }
+    
+    [component _moveToSupercomponent:newSupercomponent atIndex:index];
+    __weak typeof(self) weakSelf = self;
+    [self _addUITask:^{
+        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
+        [component moveToSuperview:newSupercomponent atIndex:index];
+        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
+    }];
+}
+
+- (void)removeComponent:(NSString *)ref
+{
+    WXAssertComponentThread();
+    WXAssertParam(ref);
+    
+    WXComponent *component = [_indexDict objectForKey:ref];
+    WXAssertComponentExist(component);
+    
+    if ([WXComponent isUseFlex] && !component) {
+        WXLogWarning(@"removeComponent ref from js never exit ! check JS action, ref :%@",ref);
+        return;
+    }
+    
+    [component _removeFromSupercomponent];
+    
+    [_indexDict removeObjectForKey:ref];
+    
+    __weak typeof(self) weakSelf = self;
+    BOOL isFSCreateFinish = [self weexInstance].isJSCreateFinish;
+    [self _addUITask:^{
+        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"removeElement" options:@{@"threadName":WXTUIThread}];
+        if (component.supercomponent) {
+            [component.supercomponent willRemoveSubview:component];
+        }
+        [component removeFromSuperview];
+        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"removeElement" options:@{@"threadName":WXTUIThread}];
+        [weakSelf onElementChange:isFSCreateFinish];
+    }];
+    
+    [self _checkFixedSubcomponentToRemove:component];
+    
+}
+
+- (void)onElementChange:(BOOL)isFSCreateFinish
+{
+    if (!isFSCreateFinish) {
+        return;
+    }
+    
+    UIView *root = [self weexInstance].rootView;
+    BOOL hasEvent = TRUE;
+    if (root && [root isKindOfClass:[WXRootView class]]) {
+        WXRootView* wxRootView = (WXRootView *)root;
+        hasEvent = [wxRootView isHasEvent];
+    }
+    if (hasEvent) {
+        return;
+    }
+    double current = CACurrentMediaTime()*1000;
+    
+    double diff =  current - [self weexInstance].performance.jsCreateFinishTime;
+    if (diff > 8000) {
+        return;
+    }
+    [self weexInstance].performance.interactionTime = current - self.weexInstance.performance.renderTimeOrigin;
+}
+
+- (void)recordMaximumVirtualDom:(WXComponent*) component
+{
+    WXAssertComponentExist(component);
+    if(!component){
+        return;
+    }
+    int maxDeep =0;
+    while (component) {
+        maxDeep++;
+        component = component.supercomponent;
+    }
+    if(maxDeep > [self weexInstance].performance.maxVdomDeep)
+    {
+        [self weexInstance].performance.maxVdomDeep = maxDeep;
+    }
+   
+}
+
+- (void)_checkFixedSubcomponentToRemove:(WXComponent *)component
+{
+    for (WXComponent *subcomponent in component.subcomponents) {
+        if (subcomponent->_positionType == WXPositionTypeFixed) {
+             [self _addUITask:^{
+                 [subcomponent removeFromSuperview];
+             }];
+        }
+        
+        [self _checkFixedSubcomponentToRemove:subcomponent];
+    }
+}
+
+- (WXComponent *)componentForRef:(NSString *)ref
+{
+    WXAssertComponentThread();
+    
+    return [_indexDict objectForKey:ref];
+}
+
+- (WXComponent *)componentForRoot
+{
+    return _rootComponent;
+}
+
+- (NSUInteger)numberOfComponents
+{
+    WXAssertComponentThread();
+    
+    return _indexDict.count;
+}
+
+- (WXComponent *)_buildComponentForData:(NSDictionary *)data supercomponent:(WXComponent *)supercomponent
+{
+    NSString *ref = data[@"ref"];
+    NSString *type = data[@"type"];
+    NSDictionary *styles = data[@"style"];
+    NSDictionary *attributes = data[@"attr"];
+    NSArray *events = data[@"event"];
+    
+    if (self.weexInstance.needValidate) {
+        id<WXValidateProtocol> validateHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXValidateProtocol)];
+        if (validateHandler) {
+            WXComponentValidateResult* validateResult;
+            if ([validateHandler respondsToSelector:@selector(validateWithWXSDKInstance:component:supercomponent:)]) {
+                validateResult = [validateHandler validateWithWXSDKInstance:self.weexInstance component:type supercomponent:supercomponent];
+            }
+            if (validateResult==nil || !validateResult.isSuccess) {
+                type = validateResult.replacedComponent? validateResult.replacedComponent : @"div";
+                WXLogError(@"%@",[validateResult.error.userInfo objectForKey:@"errorMsg"]);
+            }
+        }
+    }
+    
+    WXComponentConfig *config = [WXComponentFactory configWithComponentName:type];
+    BOOL isTemplate = [config.properties[@"isTemplate"] boolValue] || (supercomponent && supercomponent->_isTemplate);
+    NSDictionary *bindingStyles;
+    NSDictionary *bindingAttibutes;
+    NSDictionary *bindingEvents;
+    NSDictionary *bindingProps;
+    if (isTemplate) {
+        bindingProps = [self _extractBindingProps:&attributes];
+        bindingStyles = [self _extractBindings:&styles];
+        bindingAttibutes = [self _extractBindings:&attributes];
+        bindingEvents = [self _extractBindingEvents:&events];
+    }
+    
+    Class clazz = NSClassFromString(config.clazz);;
+    WXComponent *component = [[clazz alloc] initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:self.weexInstance];
+    if (isTemplate) {
+        component->_isTemplate = YES;
+        [component _storeBindingsWithProps:bindingProps styles:bindingStyles attributes:bindingAttibutes events:bindingEvents];
+    }
+
+    WXAssert(component, @"Component build failed for data:%@", data);
+    
+    [_indexDict setObject:component forKey:component.ref];
+    [component readyToRender];// notify redyToRender event when init
+    return component;
+}
+
+- (void)addComponent:(WXComponent *)component toIndexDictForRef:(NSString *)ref
+{
+    [_indexDict setObject:component forKey:ref];
+}
+
+- (NSDictionary *)_extractBindings:(NSDictionary **)attributesOrStylesPoint
+{
+    NSDictionary *attributesOrStyles = *attributesOrStylesPoint;
+    if (!attributesOrStyles) {
+        return nil;
+    }
+    
+    NSMutableDictionary *newAttributesOrStyles = [attributesOrStyles mutableCopy];
+    NSMutableDictionary *bindingAttributesOrStyles = [NSMutableDictionary dictionary];
+    
+    [attributesOrStyles enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull attributeOrStyleName, id  _Nonnull attributeOrStyle, BOOL * _Nonnull stop) {
+        if ([WXBindingMatchIdentify isEqualToString:attributeOrStyleName] // match
+            ||  [WXBindingRepeatIdentify isEqualToString:attributeOrStyleName] // repeat
+            ||  [WXBindingOnceIdentify isEqualToString:attributeOrStyleName] // once
+            ||([attributeOrStyle isKindOfClass:[NSDictionary class]] && attributeOrStyle[WXBindingIdentify])) {  // {"attributeOrStyleName": {"@binding":"bindingExpression"}
+            bindingAttributesOrStyles[attributeOrStyleName] = attributeOrStyle;
+            [newAttributesOrStyles removeObjectForKey:attributeOrStyleName];
+        } else if ([attributeOrStyle isKindOfClass:[NSArray class]]) {
+            // {"attributeOrStyleName":[..., "string", {"@binding":"bindingExpression"}, "string", {"@binding":"bindingExpression"}, ...]
+            __block BOOL isBinding = NO;
+            [attributeOrStyle enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+                if ([obj isKindOfClass:[NSDictionary class]] && obj[WXBindingIdentify]) {
+                    isBinding = YES;
+                    *stop = YES;
+                }
+            }];
+            
+            if (isBinding) {
+                bindingAttributesOrStyles[attributeOrStyleName] = attributeOrStyle;
+                [newAttributesOrStyles removeObjectForKey:attributeOrStyleName];
+            }
+        }
+    }];
+    
+    *attributesOrStylesPoint = newAttributesOrStyles;
+    
+    return bindingAttributesOrStyles;
+}
+
+- (NSDictionary *)_extractBindingEvents:(NSArray **)eventsPoint
+{
+    NSArray *events = *eventsPoint;
+    NSMutableArray *newEvents = [events mutableCopy];
+    NSMutableDictionary *bindingEvents = [NSMutableDictionary dictionary];
+    [events enumerateObjectsUsingBlock:^(id  _Nonnull event, NSUInteger idx, BOOL * _Nonnull stop) {
+        if ([event isKindOfClass:[NSDictionary class]] && event[@"type"] && event[@"params"]) {
+            NSString *eventName = event[@"type"];
+            NSString *bindingParams = event[@"params"];
+            bindingEvents[eventName] = bindingParams;
+            newEvents[idx] = eventName;
+        }
+    }];
+    
+    *eventsPoint = newEvents;
+    return bindingEvents;
+}
+
+- (NSDictionary *)_extractBindingProps:(NSDictionary **)attributesPoint
+{
+    NSDictionary *attributes = *attributesPoint;
+    if (attributes[@"@componentProps"]) {
+        NSMutableDictionary *newAttributes = [attributes mutableCopy];
+        [newAttributes removeObjectForKey:@"@componentProps"];
+        *attributesPoint = newAttributes;
+        return attributes[@"@componentProps"];
+    }
+    
+    return nil;
+}
+
+#pragma mark Reset
+-(BOOL)isShouldReset:(id )value
+{
+    if([value isKindOfClass:[NSString class]]) {
+        if(!value || [@"" isEqualToString:value]) {
+            return YES;
+        }
+    }
+    return NO;
+}
+
+-(void)filterStyles:(NSDictionary *)styles normalStyles:(NSMutableDictionary *)normalStyles resetStyles:(NSMutableArray *)resetStyles
+{
+    for (NSString *key in styles) {
+        id value = [styles objectForKey:key];
+        if([self isShouldReset:value]) {
+            [resetStyles addObject:key];
+        }else{
+            [normalStyles setObject:styles[key] forKey:key];
+        }
+    }
+}
+
+- (void)updateStyles:(NSDictionary *)styles forComponent:(NSString *)ref
+{
+    [self handleStyles:styles forComponent:ref isUpdateStyles:YES];
+}
+
+- (void)updatePseudoClassStyles:(NSDictionary *)styles forComponent:(NSString *)ref
+{
+    [self handleStyles:styles forComponent:ref isUpdateStyles:NO];
+}
+
+- (void)handleStyleOnMainThread:(NSDictionary*)styles forComponent:(WXComponent *)component isUpdateStyles:(BOOL)isUpdateStyles
+{
+    WXAssertParam(styles);
+    WXAssertParam(component);
+    WXAssertMainThread();
+    
+    NSMutableDictionary *normalStyles = [NSMutableDictionary new];
+    NSMutableArray *resetStyles = [NSMutableArray new];
+    [self filterStyles:styles normalStyles:normalStyles resetStyles:resetStyles];
+    [component _updateStylesOnMainThread:normalStyles resetStyles:resetStyles];
+    [component readyToRender];
+    
+    WXPerformBlockOnComponentThread(^{
+        [component _updateStylesOnComponentThread:normalStyles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
+    });
+}
+
+- (void)handleStyles:(NSDictionary *)styles forComponent:(NSString *)ref isUpdateStyles:(BOOL)isUpdateStyles
+{
+    WXAssertParam(styles);
+    WXAssertParam(ref);
+    
+    WXComponent *component = [_indexDict objectForKey:ref];
+    WXAssertComponentExist(component);
+    
+    NSMutableDictionary *normalStyles = [NSMutableDictionary new];
+    NSMutableArray *resetStyles = [NSMutableArray new];
+    [self filterStyles:styles normalStyles:normalStyles resetStyles:resetStyles];
+    [component _updateStylesOnComponentThread:normalStyles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
+    [self _addUITask:^{
+        [component _updateStylesOnMainThread:normalStyles resetStyles:resetStyles];
+        [component readyToRender];
+    }];
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes forComponent:(NSString *)ref
+{
+    WXAssertParam(attributes);
+    WXAssertParam(ref);
+    
+    WXComponent *component = [_indexDict objectForKey:ref];
+    WXAssertComponentExist(component);
+    
+    [component _updateAttributesOnComponentThread:attributes];
+    __weak typeof(self) weakSelf = self;
+    [self _addUITask:^{
+        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"updateAttrs" options:@{@"threadName":WXTUIThread}];
+        [component _updateAttributesOnMainThread:attributes];
+        [component readyToRender];
+        [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"updateAttrs" options:@{@"threadName":WXTUIThread}];
+    }];
+}
+
+- (void)addEvent:(NSString *)eventName toComponent:(NSString *)ref
+{
+    WXAssertComponentThread();
+    WXAssertParam(eventName);
+    WXAssertParam(ref);
+    
+    WXComponent *component = [_indexDict objectForKey:ref];
+    WXAssertComponentExist(component);
+    
+    [component _addEventOnComponentThread:eventName];
+    
+    [self _addUITask:^{
+        [component _addEventOnMainThread:eventName];
+    }];
+}
+
+- (void)removeEvent:(NSString *)eventName fromComponent:(NSString *)ref
+{
+    WXAssertComponentThread();
+    WXAssertParam(eventName);
+    WXAssertParam(ref);
+    
+    WXComponent *component = [_indexDict objectForKey:ref];
+    WXAssertComponentExist(component);
+    
+    [component _removeEventOnComponentThread:eventName];
+    
+    [self _addUITask:^{
+        [component _removeEventOnMainThread:eventName];
+    }];
+}
+
+- (void)scrollToComponent:(NSString *)ref options:(NSDictionary *)options
+{
+    WXAssertComponentThread();
+    WXAssertParam(ref);
+    
+    WXComponent *toComponent = [_indexDict objectForKey:ref];
+    WXAssertComponentExist(toComponent);
+
+    id<WXScrollerProtocol> scrollerComponent = toComponent.ancestorScroller;
+    if (!scrollerComponent) {
+        return;
+    }
+
+    CGFloat offset = [[options objectForKey:@"offset"] floatValue];
+    BOOL animated = YES;
+    if ([options objectForKey:@"animated"]) {
+        animated = [[options objectForKey:@"animated"] boolValue];
+    }
+    
+    [self _addUITask:^{
+        [scrollerComponent scrollToComponent:toComponent withOffset:offset animated:animated];
+    }];
+}
+
+#pragma mark Life Cycle
+
+- (void)createFinish
+{
+    WXAssertComponentThread();
+    
+    WXSDKInstance *instance  = self.weexInstance;
+    [self _addUITask:^{
+        UIView *rootView = instance.rootView;
+        
+        //WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, instance);
+        WX_MONITOR_INSTANCE_PERF_END(WXPTAllRender, instance);
+        WX_MONITOR_SUCCESS(WXMTJSBridge);
+        WX_MONITOR_SUCCESS(WXMTNativeRender);
+        
+        if(instance.renderFinish){
+            [WXTracingManager startTracingWithInstanceId:instance.instanceId ref:nil className:nil name:nil phase:WXTracingInstant functionName:WXTRenderFinish options:@{@"threadName":WXTUIThread}];
+            instance.renderFinish(rootView);
+        }
+    }];
+    [instance updatePerDicAfterCreateFinish];
+}
+
+- (void)updateFinish
+{
+    WXAssertComponentThread();
+    
+    WXSDKInstance *instance = self.weexInstance;
+    WXComponent *root = [_indexDict objectForKey:WX_SDK_ROOT_REF];
+    
+    [self _addUITask:^{
+        if(instance.updateFinish){
+            instance.updateFinish(root.view);
+        }
+    }];
+}
+
+- (void)refreshFinish
+{
+    WXAssertComponentThread();
+    
+    WXSDKInstance *instance = self.weexInstance;
+    WXComponent *root = [_indexDict objectForKey:WX_SDK_ROOT_REF];
+    
+    [self _addUITask:^{
+        if(instance.refreshFinish){
+            instance.refreshFinish(root.view);
+        }
+    }];
+}
+
+- (void)unload
+{
+    WXAssertComponentThread();
+    [self invalidate];
+    [self _stopDisplayLink];
+    NSEnumerator *enumerator = [[_indexDict copy] objectEnumerator];
+    dispatch_async(dispatch_get_main_queue(), ^{
+        WXComponent *component;
+        while ((component = [enumerator nextObject])) {
+            [component _unloadViewWithReusing:NO];
+        }
+        _rootComponent = nil;
+    });
+    
+    [_indexDict removeAllObjects];
+    [_uiTaskQueue removeAllObjects];
+}
+
+- (void)invalidate
+{
+    _isValid = NO;
+}
+
+- (BOOL)isValid
+{
+    return _isValid;
+}
+
+#pragma mark Layout Batch
+
+- (void)_startDisplayLink
+{
+    WXAssertComponentThread();
+    
+    if(!_displayLink){
+        _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleDisplayLink)];
+        [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+    }
+}
+
+- (void)_stopDisplayLink
+{
+    WXAssertComponentThread();
+    
+    if(_displayLink){
+        [_displayLink invalidate];
+        _displayLink = nil;
+    }
+}
+
+- (void)_suspendDisplayLink
+{
+    WXAssertComponentThread();
+    
+    if(_displayLink && !_displayLink.paused) {
+        _displayLink.paused = YES;
+    }
+}
+
+- (void)_awakeDisplayLink
+{
+    WXAssertComponentThread();
+    
+    if(_displayLink && _displayLink.paused) {
+        _displayLink.paused = NO;
+    }
+}
+
+- (void)_handleDisplayLink
+{
+    WXAssertComponentThread();
+    
+    [self _layoutAndSyncUI];
+}
+
+- (void)_layoutAndSyncUI
+{
+    [self _layout];
+    if(_uiTaskQueue.count > 0){
+        [self _syncUITasks];
+        _noTaskTickCount = 0;
+    } else {
+        // suspend display link when there's no task for 1 second, in order to save CPU time.
+        _noTaskTickCount ++;
+        if (_noTaskTickCount > 60) {
+            [self _suspendDisplayLink];
+        }
+    }
+}
+
+- (void)_layout
+{
+    BOOL needsLayout = NO;
+
+//    NSEnumerator *enumerator = [_indexDict objectEnumerator];
+//    WXComponent *component;
+//    while ((component = [enumerator nextObject])) {
+//        if ([component needsLayout]) {
+//            needsLayout = YES;
+//            break;
+//        }
+//    }
+    
+    needsLayout = [_rootComponent needsLayout];
+
+    if (!needsLayout) {
+        return;
+    }
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> action__ calculateLayout root");
+#endif
+    
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+         layoutNode(_rootCSSNode, _rootCSSNode->style.dimensions[CSS_WIDTH], _rootCSSNode->style.dimensions[CSS_HEIGHT], CSS_DIRECTION_INHERIT);
+    }
+//#else
+    else
+    {
+        std::pair<float, float> renderPageSize;
+        renderPageSize.first = self.weexInstance.frame.size.width;
+        renderPageSize.second = self.weexInstance.frame.size.height;
+        _rootFlexCSSNode->calculateLayout(renderPageSize);
+    }
+//#endif
+    NSMutableSet<WXComponent *> *dirtyComponents = [NSMutableSet set];
+    [_rootComponent _calculateFrameWithSuperAbsolutePosition:CGPointZero gatherDirtyComponents:dirtyComponents];
+    [self _calculateRootFrame];
+  
+    for (WXComponent *dirtyComponent in dirtyComponents) {
+        [self _addUITask:^{
+            [dirtyComponent _layoutDidFinish];
+        }];
+    }
+}
+
+//#ifdef USE_FLEX
+- (void) _printFlexComonentFrame:(WXComponent *)component
+{
+#ifdef DEBUG
+    WXLogDebug(@"node ref:%@, type:%@ , frame:%@",
+          component.ref,
+          component.type,
+          NSStringFromCGRect(component.view.layer.frame)
+          );
+#endif
+    
+  
+    
+    for (WXComponent *childComponent in component.subcomponents) {
+        [self _printFlexComonentFrame:childComponent];
+    }
+
+    
+}
+//#endif
+
+- (void)_syncUITasks
+{
+    NSArray<dispatch_block_t> *blocks = _uiTaskQueue;
+    _uiTaskQueue = [NSMutableArray array];
+    dispatch_async(dispatch_get_main_queue(), ^{
+        for(dispatch_block_t block in blocks) {
+            block();
+        }
+    });
+}
+//#ifndef USE_FLEX
+- (void)_initRootCSSNode
+{
+    _rootCSSNode = new_css_node();
+    
+    [self _applyRootFrame:self.weexInstance.frame toRootCSSNode:_rootCSSNode];
+    
+    _rootCSSNode->style.flex_wrap = CSS_NOWRAP;
+    _rootCSSNode->is_dirty = rootNodeIsDirty;
+    _rootCSSNode->get_child = rootNodeGetChild;
+    _rootCSSNode->context=(__bridge void *)(self);
+    _rootCSSNode->children_count = 1;
+}
+//#else
+- (void)_initRootFlexCssNode
+{
+    _rootFlexCSSNode = new WeexCore::WXCoreLayoutNode();
+    [self _applyRootFrame:self.weexInstance.frame];
+    _rootFlexCSSNode->setFlexWrap(WeexCore::kNoWrap);
+    _rootFlexCSSNode->setContext((__bridge void *)(self));
+}
+//#endif
+
+- (void)_calculateRootFrame
+{
+//#ifndef USE_FLEX
+    
+    if(![WXComponent isUseFlex])
+    {
+        if (!_rootCSSNode->layout.should_update) {
+            return;
+        }
+        _rootCSSNode->layout.should_update = false;
+#ifdef DEBUG
+        WXLogDebug(@"flexLayout -> root _calculateRootFrame");
+#endif
+        
+        CGRect frame = CGRectMake(WXRoundPixelValue(_rootCSSNode->layout.position[CSS_LEFT]),
+                                  WXRoundPixelValue(_rootCSSNode->layout.position[CSS_TOP]),
+                                  WXRoundPixelValue(_rootCSSNode->layout.dimensions[CSS_WIDTH]),
+                                  WXRoundPixelValue(_rootCSSNode->layout.dimensions[CSS_HEIGHT]));
+        WXPerformBlockOnMainThread(^{
+            if(!self.weexInstance.isRootViewFrozen) {
+                self.weexInstance.rootView.frame = frame;
+            }
+        });
+        
+        resetNodeLayout(_rootCSSNode);
+    }
+//#else
+    else
+    {
+        if(!_rootFlexCSSNode->hasNewLayout()){
+            return;
+        }
+        _rootFlexCSSNode->setHasNewLayout(false);
+#ifdef DEBUG
+        WXLogDebug(@"flexLayout -> root _calculateRootFrame");
+#endif
+        
+        
+        CGRect frame = CGRectMake(WXRoundPixelValue(_rootFlexCSSNode->getLayoutPositionLeft()),
+                                  WXRoundPixelValue(_rootFlexCSSNode->getLayoutPositionTop()),
+                                  WXRoundPixelValue(_rootFlexCSSNode->getLayoutWidth()),
+                                  WXRoundPixelValue(_rootFlexCSSNode->getLayoutHeight()));
+        WXPerformBlockOnMainThread(^{
+            if(!self.weexInstance.isRootViewFrozen) {
+                self.weexInstance.rootView.frame = frame;
+            }
+        });
+        //   _rootFlexCSSNode->reset();
+        
+        //    resetNodeLayout(_rootFlexCSSNode);
+    }
+//#endif
+    
+   
+}
+
+
+#pragma mark Fixed 
+
+- (void)addFixedComponent:(WXComponent *)fixComponent
+{
+    [_fixedComponents addObject:fixComponent];
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        _rootCSSNode->children_count = (int)[_fixedComponents count] + 1;
+    }
+//#else
+    else
+    {
+        _rootFlexCSSNode->addChildAt(fixComponent.flexCssNode, (uint32_t)([_fixedComponents count]-1));
+    }
+//#endif
+}
+
+- (void)removeFixedComponent:(WXComponent *)fixComponent
+{
+    [_fixedComponents removeObject:fixComponent];
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        _rootCSSNode->children_count = (int)[_fixedComponents count] + 1;
+    }
+//#else
+    else
+    {
+        _rootFlexCSSNode->removeChild(fixComponent->_flexCssNode);
+    }
+//#endif
+}
+
+@end
+
+void WXPerformBlockOnComponentThread(void (^block)(void))
+{
+    [WXComponentManager _performBlockOnComponentThread:block];
+}
+
+void WXPerformBlockSyncOnComponentThread(void (^block)(void))
+{
+    [WXComponentManager _performBlockSyncOnComponentThread:block];
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.h b/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
index 5e8ba70..c0e6c9a 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
@@ -17,6 +17,12 @@
  * under the License.
  */
 
+/**
+ *  def : use weex_flex_engin
+ *  ndef: use yoga
+ **/
+
+
 #import <Foundation/Foundation.h>
 #import "WXLayoutDefine.h"
 #import "WXType.h"
@@ -143,13 +149,6 @@ NS_ASSUME_NONNULL_BEGIN
 //@property(nonatomic, assign) CGPoint absolutePosition;
 
 /**
- * @abstract Return the css node used to layout.
- *
- * @warning Subclasses must not override this.
- */
-@property(nonatomic, readonly, assign) css_node_t *cssNode;
-
-/**
  * @abstract Invalidates the component's layout and marks it as needing an update.
  *
  * @discussion You can call this method to indicate that the layout of a component has changed and must be updated. Weex typically calls this method automatically when the layout-related styles change or when subcomponents are added or removed.

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/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
deleted file mode 100644
index 300dbc9..0000000
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
+++ /dev/null
@@ -1,842 +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 "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"
-
-#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"]];
-        }
-        
-        [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;
-    }
-    memcpy(component->_cssNode, self.cssNode, sizeof(css_node_t));
-    component->_cssNode->context = (__bridge void *)component;
-    component->_calculatedFrame = self.calculatedFrame;
-    
-    NSMutableArray *subcomponentsCopy = [NSMutableArray array];
-    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
-{
-    free_css_node(_cssNode);
-
-//    [self _removeAllEvents];
-    // 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];
-        
-        _layer = _view.layer;
-        _view.frame = _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;
-    }
-}
-
-- (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;
-}
-
-- (css_node_t *)cssNode
-{
-    return _cssNode;
-}
-
-- (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;
-    }
-    
-    [self _recomputeCSSNodeChildren];
-    [self setNeedsLayout];
-}
-
-- (void)_removeSubcomponent:(WXComponent *)subcomponent
-{
-    pthread_mutex_lock(&_propertyMutex);
-    [_subcomponents removeObject:subcomponent];
-    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
-{
-    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];
-    }
-    [self _resetStyles:resetStyles];
-    [self _handleBorders:styles isUpdating:YES];
-    [self updateStyles:styles];
-    [self resetStyles:resetStyles];
-}
-
-- (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:[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


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

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
new file mode 100644
index 0000000..c951068
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
@@ -0,0 +1,1170 @@
+/*
+ * 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 "WXTextComponent.h"
+#import "WXSDKInstance_private.h"
+#import "WXComponent_internal.h"
+#import "WXLayer.h"
+#import "WXUtility.h"
+#import "WXConvert.h"
+#import "WXRuleManager.h"
+#import "WXDefine.h"
+#import "WXView.h"
+#import "WXComponent+Layout.h"
+#import <pthread/pthread.h>
+#import <CoreText/CoreText.h>
+#import "WXComponent+Layout.h"
+
+// WXText is a non-public is not permitted
+@interface WXTextView : WXView
+@property (nonatomic, strong) NSTextStorage *textStorage;
+@end
+
+@implementation WXTextView
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    if ((self = [super initWithFrame:frame])) {
+        self.accessibilityTraits |= UIAccessibilityTraitStaticText;
+        
+        self.opaque = NO;
+        self.contentMode = UIViewContentModeRedraw;
+        self.textStorage = [NSTextStorage new];
+    }
+    return self;
+}
+
++ (Class)layerClass
+{
+    return [WXLayer class];
+}
+
+- (void)copy:(id)sender
+{
+    [[UIPasteboard generalPasteboard] setString:((WXTextComponent*)self.wx_component).text];
+}
+
+- (void)setTextStorage:(NSTextStorage *)textStorage
+{
+    if (_textStorage != textStorage) {
+        _textStorage = textStorage;
+        [self.wx_component setNeedsDisplay];
+    }
+}
+
+- (BOOL)canBecomeFirstResponder
+{
+    return YES;
+}
+
+- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
+{
+    if (action == @selector(copy:)) {
+        return [[self.wx_component valueForKey:@"_enableCopy"] boolValue];
+    }
+    return [super canPerformAction:action withSender:sender];
+}
+
+- (NSString *)description
+{
+    NSString *superDescription = super.description;
+    NSRange semicolonRange = [superDescription rangeOfString:@";"];
+    NSString * content = _textStorage.string;
+    if ([(WXTextComponent*)self.wx_component useCoreText]) {
+        content = ((WXTextComponent*)self.wx_component).text;
+    }
+    NSString *replacement = [NSString stringWithFormat:@"; text: %@; frame:%f,%f,%f,%f", content, self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height];
+    return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement];
+}
+
+- (NSString *)accessibilityValue
+{
+    if (self.wx_component && self.wx_component->_ariaLabel) {
+        return [super accessibilityValue];
+    }
+    if (![(WXTextComponent*)self.wx_component useCoreText]) {
+        return _textStorage.string;
+    }
+    return ((WXTextComponent*)self.wx_component).text;
+}
+
+- (NSString *)accessibilityLabel
+{
+    if (self.wx_component) {
+        if (self.wx_component->_ariaLabel) {
+            return self.wx_component->_ariaLabel;
+        }
+    }
+    return [super accessibilityLabel];
+}
+
+@end
+
+static BOOL textRenderUsingCoreText = YES;
+
+NSString *const WXTextTruncationToken = @"\u2026";
+CGFloat WXTextDefaultLineThroughWidth = 1.2;
+
+@interface WXTextComponent()
+@property (nonatomic, strong) NSString *useCoreTextAttr;
+@end
+
+@implementation WXTextComponent
+{
+    UIEdgeInsets _border;
+    UIEdgeInsets _padding;
+    NSTextStorage *_textStorage;
+    CGFloat _textStorageWidth;
+    
+    UIColor *_color;
+    NSString *_fontFamily;
+    CGFloat _fontSize;
+    CGFloat _fontWeight;
+    WXTextStyle _fontStyle;
+    NSUInteger _lines;
+    NSTextAlignment _textAlign;
+    NSString *_direction;
+    WXTextDecoration _textDecoration;
+    NSString *_textOverflow;
+    CGFloat _lineHeight;
+    CGFloat _letterSpacing;
+    BOOL _truncationLine; // support trunk tail
+    
+    NSAttributedString * _ctAttributedString;
+    NSString *_wordWrap;
+    
+    pthread_mutex_t _ctAttributedStringMutex;
+    pthread_mutexattr_t _propertMutexAttr;
+    BOOL _observerIconfont;
+    BOOL _enableCopy;
+}
+
++ (void)setRenderUsingCoreText:(BOOL)usingCoreText
+{
+    textRenderUsingCoreText = usingCoreText;
+}
+
++ (BOOL)textRenderUsingCoreText
+{
+    return textRenderUsingCoreText;
+}
+
+- (instancetype)initWithRef:(NSString *)ref
+                       type:(NSString *)type
+                     styles:(NSDictionary *)styles
+                 attributes:(NSDictionary *)attributes
+                     events:(NSArray *)events
+               weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        // just for coretext and textkit render replacement
+        pthread_mutexattr_init(&(_propertMutexAttr));
+        pthread_mutexattr_settype(&(_propertMutexAttr), PTHREAD_MUTEX_RECURSIVE);
+        pthread_mutex_init(&(_ctAttributedStringMutex), &(_propertMutexAttr));
+        
+        if ([attributes objectForKey:@"coretext"]) {
+            _useCoreTextAttr = [WXConvert NSString:attributes[@"coretext"]];
+        } else {
+            _useCoreTextAttr = nil;
+        }
+        
+        [self fillCSSStyles:styles];
+        [self fillAttributes:attributes];
+        
+    }
+    return self;
+}
+
+- (BOOL)useCoreText
+{
+    if ([_useCoreTextAttr isEqualToString:@"true"]) {
+        return YES;
+    }
+    if ([_useCoreTextAttr isEqualToString:@"false"]) {
+        return NO;
+    }
+    
+    if ([WXTextComponent textRenderUsingCoreText]) {
+        return YES;
+    }
+    return NO;
+}
+
+- (void)dealloc
+{
+    if (_fontFamily && _observerIconfont) {
+        [[NSNotificationCenter defaultCenter] removeObserver:self name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
+    }
+    pthread_mutex_destroy(&_ctAttributedStringMutex);
+    pthread_mutexattr_destroy(&_propertMutexAttr);
+}
+
+#define WX_STYLE_FILL_TEXT(key, prop, type, needLayout)\
+do {\
+    id value = styles[@#key];\
+    if (value) {\
+        _##prop = [WXConvert type:value];\
+        [self setNeedsRepaint];\
+        if (needLayout) {\
+            [self setNeedsLayout];\
+        }\
+    }\
+} while(0);
+
+#define WX_STYLE_FILL_TEXT_WITH_DEFAULT_VALUE(key, prop, type, defaultValue,needLayout)\
+do {\
+    id value = styles[@#key];\
+    if (value) {\
+        if([WXUtility isBlankString:value]){\
+            _##prop = defaultValue;\
+        }else {\
+            _##prop = [WXConvert type:value];\
+        }\
+        [self setNeedsRepaint];\
+        if (needLayout) {\
+            [self setNeedsLayout];\
+        }\
+    }\
+} while(0);
+
+
+#define WX_STYLE_FILL_TEXT_PIXEL(key, prop, needLayout)\
+do {\
+    id value = styles[@#key];\
+    if (value) {\
+        _##prop = [WXConvert WXPixelType:value scaleFactor:self.weexInstance.pixelScaleFactor];\
+        [self setNeedsRepaint];\
+    if (needLayout) {\
+        [self setNeedsLayout];\
+    }\
+}\
+} while(0);
+
+- (void)fillCSSStyles:(NSDictionary *)styles
+{
+    WX_STYLE_FILL_TEXT_WITH_DEFAULT_VALUE(color, color, UIColor, [UIColor blackColor], NO)
+    WX_STYLE_FILL_TEXT(fontFamily, fontFamily, NSString, YES)
+    WX_STYLE_FILL_TEXT_PIXEL(fontSize, fontSize, YES)
+    WX_STYLE_FILL_TEXT(fontWeight, fontWeight, WXTextWeight, YES)
+    WX_STYLE_FILL_TEXT(fontStyle, fontStyle, WXTextStyle, YES)
+    WX_STYLE_FILL_TEXT(lines, lines, NSUInteger, YES)
+    WX_STYLE_FILL_TEXT(textAlign, textAlign, NSTextAlignment, NO)
+    WX_STYLE_FILL_TEXT(textDecoration, textDecoration, WXTextDecoration, YES)
+    WX_STYLE_FILL_TEXT(textOverflow, textOverflow, NSString, NO)
+    WX_STYLE_FILL_TEXT_PIXEL(lineHeight, lineHeight, YES)
+    WX_STYLE_FILL_TEXT_PIXEL(letterSpacing, letterSpacing, YES)
+    WX_STYLE_FILL_TEXT(wordWrap, wordWrap, NSString, YES);
+    WX_STYLE_FILL_TEXT(direction, direction, NSString, YES)
+    if (_fontFamily && !_observerIconfont) {
+        // notification received when custom icon font file download finish
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(repaintText:) name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
+        _observerIconfont = YES;
+    }
+    
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        UIEdgeInsets padding = {
+            WXFloorPixelValue(self.cssNode->style.padding[CSS_TOP] + self.cssNode->style.border[CSS_TOP]),
+            WXFloorPixelValue(self.cssNode->style.padding[CSS_LEFT] + self.cssNode->style.border[CSS_LEFT]),
+            WXFloorPixelValue(self.cssNode->style.padding[CSS_BOTTOM] + self.cssNode->style.border[CSS_BOTTOM]),
+            WXFloorPixelValue(self.cssNode->style.padding[CSS_RIGHT] + self.cssNode->style.border[CSS_RIGHT])
+        };
+        
+        if (!UIEdgeInsetsEqualToEdgeInsets(padding, _padding)) {
+            _padding = padding;
+            [self setNeedsRepaint];
+        }
+    }
+  
+//#else
+    else
+    {
+        UIEdgeInsets flex_padding = {
+            WXFloorPixelValue(self.flexCssNode->getPaddingTop()+ self.flexCssNode->getBorderWidthTop()),
+            WXFloorPixelValue(self.flexCssNode->getPaddingLeft() + self.flexCssNode->getBorderWidthLeft()),
+            WXFloorPixelValue(self.flexCssNode->getPaddingBottom() + self.flexCssNode->getBorderWidthBottom()),
+            WXFloorPixelValue(self.flexCssNode->getPaddingRight() + self.flexCssNode->getBorderWidthRight())
+        };
+        
+        if (!UIEdgeInsetsEqualToEdgeInsets(flex_padding, _padding)) {
+            _padding = flex_padding;
+            [self setNeedsRepaint];
+        }
+    }
+//#endif
+    
+}
+
+- (void)fillAttributes:(NSDictionary *)attributes
+{
+    id text = [WXConvert NSString:attributes[@"value"]];
+    if (text && ![self.text isEqualToString:text]) {
+        self.text = text;
+        [self setNeedsRepaint];
+        [self setNeedsLayout];
+    }
+    if (attributes[@"enableCopy"]) {
+        _enableCopy = [WXConvert BOOL:attributes[@"enableCopy"]];
+    }
+}
+
+- (void)setNeedsRepaint
+{
+    _textStorage = nil;
+    
+    pthread_mutex_lock(&(_ctAttributedStringMutex));
+    _ctAttributedString = nil;
+    pthread_mutex_unlock(&(_ctAttributedStringMutex));
+    
+}
+
+#pragma mark - Subclass
+
+- (void)setNeedsLayout
+{
+    [super setNeedsLayout];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    BOOL useCoreText = NO;
+    if ([self.view.wx_component isKindOfClass:NSClassFromString(@"WXTextComponent")] && [self.view.wx_component respondsToSelector:@selector(useCoreText)]) {
+        useCoreText = [(WXTextComponent*)self.view.wx_component useCoreText];
+    }
+    if (!useCoreText) {
+        ((WXTextView *)self.view).textStorage = _textStorage;
+    }
+    if (_enableCopy) {
+        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(displayMenuController:)];
+        [self.view addGestureRecognizer:longPress];
+    }
+    self.view.isAccessibilityElement = YES;
+    
+    [self setNeedsDisplay];
+}
+
+- (void)displayMenuController:(id)sender
+{
+    if ([self.view becomeFirstResponder] && ((UILongPressGestureRecognizer*)sender).state == UIGestureRecognizerStateBegan) {
+        UIMenuController *theMenu = [UIMenuController sharedMenuController];
+        CGSize size = [self ctAttributedString].size;
+        CGRect selectionRect = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, size.width, size.height);
+        [theMenu setTargetRect:selectionRect inView:self.view.superview];
+        [theMenu setMenuVisible:YES animated:YES];
+    }
+}
+
+- (UIView *)loadView
+{
+    return [[WXTextView alloc] init];
+}
+
+- (BOOL)needsDrawRect
+{
+    return YES;
+}
+
+- (UIImage *)drawRect:(CGRect)rect;
+{
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    if (_isCompositingChild) {
+        [self drawTextWithContext:context bounds:rect padding:_padding view:nil];
+    } else {
+        WXTextView *textView = (WXTextView *)_view;
+        [self drawTextWithContext:context bounds:rect padding:_padding view:textView];
+    }
+    
+    return nil;
+}
+
+- (CGSize (^)(CGSize))measureBlock
+{
+    __weak typeof(self) weakSelf = self;
+    return ^CGSize (CGSize constrainedSize) {
+#ifdef DEBUG
+        WXLogDebug(@"flexLayout -> measureblock %@, constrainedSize:%@",
+              self.type,
+              NSStringFromCGSize(constrainedSize)
+              );
+#endif
+        CGSize computedSize = CGSizeZero;
+        NSTextStorage *textStorage = nil;
+        
+        //TODO:more elegant way to use max and min constrained size
+//#ifndef USE_FLEX
+        if(![WXComponent isUseFlex])
+        {
+            if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
+                constrainedSize.width = MAX(constrainedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
+            }
+            
+            if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
+                constrainedSize.width = MIN(constrainedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
+            }
+        }
+//#else
+        else
+        {
+            if (!isnan(weakSelf.flexCssNode->getMinWidth())) {
+                constrainedSize.width = MAX(constrainedSize.width, weakSelf.flexCssNode->getMinWidth());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMaxWidth())) {
+                constrainedSize.width = MIN(constrainedSize.width, weakSelf.flexCssNode->getMaxWidth());
+            }
+        }
+//#endif
+        
+        if (![self useCoreText]) {
+            textStorage = [weakSelf textStorageWithWidth:constrainedSize.width];
+            NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
+            NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
+            computedSize = [layoutManager usedRectForTextContainer:textContainer].size;
+        } else {
+            computedSize = [weakSelf calculateTextHeightWithWidth:constrainedSize.width];
+        }
+//#ifndef USE_FLEX
+        if(![WXComponent isUseFlex])
+        {
+            //TODO:more elegant way to use max and min constrained size
+            if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
+                computedSize.width = MAX(computedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
+            }
+            
+            if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
+                computedSize.width = MIN(computedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
+            }
+            
+            if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_HEIGHT])) {
+                computedSize.height = MAX(computedSize.height, weakSelf.cssNode->style.minDimensions[CSS_HEIGHT]);
+            }
+            
+            if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT])) {
+                computedSize.height = MIN(computedSize.height, weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT]);
+            }
+        }
+       
+//#else
+        else
+        {
+            if (!isnan(weakSelf.flexCssNode->getMinWidth())) {
+                computedSize.width = MAX(computedSize.width, weakSelf.flexCssNode->getMinWidth());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMaxWidth())) {
+                computedSize.width = MIN(computedSize.width, weakSelf.flexCssNode->getMaxWidth());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMinHeight())) {
+                computedSize.height = MAX(computedSize.height, weakSelf.flexCssNode->getMinHeight());
+            }
+            
+            if (!isnan(weakSelf.flexCssNode->getMaxHeight())) {
+                computedSize.height = MIN(computedSize.height, weakSelf.flexCssNode->getMaxHeight());
+            }
+        }
+    
+//#endif
+        if (textStorage && [WXUtility isBlankString:textStorage.string]) {
+            //  if the text value is empty or nil, then set the height is 0.
+            computedSize.height = 0;
+        }
+        
+        return (CGSize) {
+            WXCeilPixelValue(computedSize.width),
+            WXCeilPixelValue(computedSize.height)
+        };
+    };
+}
+
+#pragma mark Text Building
+
+- (NSAttributedString *)ctAttributedString
+{
+    if (!self.text) {
+        return nil;
+    }
+    NSAttributedString * attributedString = nil;
+    pthread_mutex_lock(&(_ctAttributedStringMutex));
+    if (!_ctAttributedString) {
+        _ctAttributedString = [self buildCTAttributeString];
+        WXPerformBlockOnComponentThread(^{
+            [self.weexInstance.componentManager startComponentTasks];
+        });
+    }
+    attributedString = [_ctAttributedString copy];
+    pthread_mutex_unlock(&(_ctAttributedStringMutex));
+    return attributedString;
+}
+
+- (void)repaintText:(NSNotification *)notification
+{
+    if (![_fontFamily isEqualToString:notification.userInfo[@"fontFamily"]]) {
+        return;
+    }
+    [self setNeedsRepaint];
+    WXPerformBlockOnComponentThread(^{
+        [self.weexInstance.componentManager startComponentTasks];
+        WXPerformBlockOnMainThread(^{
+            [self setNeedsLayout];
+            [self setNeedsDisplay];
+        });
+    });
+}
+
+- (NSMutableAttributedString *)buildCTAttributeString
+{
+    NSString * string = self.text;
+    if (![string isKindOfClass:[NSString class]]) {
+        WXLogError(@"text %@ is invalid", self.text);
+        string = @"";
+    }
+    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString: string];
+    if (_color) {
+        [attributedString addAttribute:NSForegroundColorAttributeName value:_color range:NSMakeRange(0, string.length)];
+    }
+    
+    // set font
+    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor useCoreText:[self useCoreText]];
+    CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)font.fontName,
+                                           font.pointSize,
+                                           NULL);
+    if (ctFont) {
+        [attributedString addAttribute:(id)kCTFontAttributeName value:(__bridge id)(ctFont) range:NSMakeRange(0, string.length)];
+        CFRelease(ctFont);
+    }
+    
+    if(_textDecoration == WXTextDecorationUnderline){
+        [attributedString addAttribute:(id)kCTUnderlineStyleAttributeName value:@(kCTUnderlinePatternSolid | kCTUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
+    } else if(_textDecoration == WXTextDecorationLineThrough){
+        [attributedString addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
+    }
+    
+    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
+    
+    // handle text direction style, default ltr
+    BOOL isRtl = false;
+    if ([WXComponent isUseFlex]) {
+        isRtl = [_direction isEqualToString:@"rtl"];
+    }else{
+        isRtl = _cssNode->layout.direction == CSS_DIRECTION_RTL;
+    }
+    if (isRtl) {
+        if (0 == _textAlign) {
+            //force text right-align if don't specified any align.
+            _textAlign = NSTextAlignmentRight;
+        }
+        paragraphStyle.baseWritingDirection = NSWritingDirectionRightToLeft;
+    } else {
+        //if you specify NSWritingDirectionNaturalDirection, the receiver resolves the writing
+        //directionto eitherNSWritingDirectionLeftToRight or NSWritingDirectionRightToLeft,
+        //depending on the direction for the user’s language preference setting.
+        paragraphStyle.baseWritingDirection =  NSWritingDirectionNatural;
+    }
+    
+    if (_textAlign) {
+        paragraphStyle.alignment = _textAlign;
+    }
+    
+    if ([[_wordWrap lowercaseString] isEqualToString:@"break-word"]) {
+        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
+    } else if ([[_wordWrap lowercaseString] isEqualToString:@"normal"]){
+        paragraphStyle.lineBreakMode = NSLineBreakByClipping;
+    } else {
+         // set default lineBreakMode
+        paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
+    }
+    _truncationLine = NO;
+    if (_textOverflow && [_textOverflow length] > 0) {
+        if (_lines && [_textOverflow isEqualToString:@"ellipsis"])
+            _truncationLine = YES;
+    }
+    
+    if (_lineHeight) {
+        paragraphStyle.maximumLineHeight = _lineHeight;
+        paragraphStyle.minimumLineHeight = _lineHeight;
+    }
+    if (_lineHeight || _textAlign || [_textOverflow length] > 0) {
+        [attributedString addAttribute:NSParagraphStyleAttributeName
+                                 value:paragraphStyle
+                                 range:(NSRange){0, attributedString.length}];
+    }
+    
+    if (_letterSpacing) {
+        [attributedString addAttribute:NSKernAttributeName value:@(_letterSpacing) range:(NSRange){0, attributedString.length}];
+    }
+    
+    if ([self adjustLineHeight]) {
+        if (_lineHeight > font.lineHeight) {
+            [attributedString addAttribute:NSBaselineOffsetAttributeName
+                                     value:@((_lineHeight - font.lineHeight)/ 2)
+                                     range:(NSRange){0, attributedString.length}];
+        }
+    }
+    
+    return attributedString;
+}
+
+- (NSAttributedString *)buildAttributeString
+{
+    NSString *string = self.text ?: @"";
+    
+    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
+    
+    // set textColor
+    if(_color) {
+        [attributedString addAttribute:NSForegroundColorAttributeName value:_color range:NSMakeRange(0, string.length)];
+    }
+    
+    // set font
+    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
+    if (font) {
+        [attributedString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, string.length)];
+    }
+    
+    if(_textDecoration == WXTextDecorationUnderline){
+        [attributedString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
+    } else if(_textDecoration == WXTextDecorationLineThrough){
+        [attributedString addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
+    }
+    
+    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
+
+    // handle text direction style, default ltr
+    BOOL isRtl = false;
+    if ([WXComponent isUseFlex]) {
+        isRtl = [_direction isEqualToString:@"rtl"];
+    }else{
+        isRtl = _cssNode->layout.direction == CSS_DIRECTION_RTL;
+    }
+    if (isRtl) {
+        if (0 == _textAlign) {
+            //force text right-align if don't specified any align.
+            _textAlign = NSTextAlignmentRight;
+        }
+        paragraphStyle.baseWritingDirection = NSWritingDirectionRightToLeft;
+    } else {
+        //if you specify NSWritingDirectionNaturalDirection, the receiver resolves the writing
+        //directionto eitherNSWritingDirectionLeftToRight or NSWritingDirectionRightToLeft,
+        //depending on the direction for the user’s language preference setting.
+        paragraphStyle.baseWritingDirection =  NSWritingDirectionNatural;
+    }
+    
+    if (_textAlign) {
+        paragraphStyle.alignment = _textAlign;
+    }
+    
+    if (_lineHeight) {
+        paragraphStyle.maximumLineHeight = _lineHeight;
+        paragraphStyle.minimumLineHeight = _lineHeight;
+    }
+    
+    if (_lineHeight || _textAlign) {
+        [attributedString addAttribute:NSParagraphStyleAttributeName
+                                 value:paragraphStyle
+                                 range:(NSRange){0, attributedString.length}];
+    }
+    if ([self adjustLineHeight]) {
+        if (_lineHeight > font.lineHeight) {
+            [attributedString addAttribute:NSBaselineOffsetAttributeName
+                                     value:@((_lineHeight - font.lineHeight)/ 2)
+                                     range:(NSRange){0, attributedString.length}];
+        }
+    }
+
+    return attributedString;
+}
+
+- (BOOL)adjustLineHeight
+{
+    if (WX_SYS_VERSION_LESS_THAN(@"10.0")) {
+        return true;
+    }
+    return ![self useCoreText];
+}
+
+- (NSTextStorage *)textStorageWithWidth:(CGFloat)width
+{
+    if (_textStorage && width == _textStorageWidth) {
+        return _textStorage;
+    }
+    
+    NSLayoutManager *layoutManager = [NSLayoutManager new];
+    
+    // build AttributeString
+    NSAttributedString *attributedString = [self buildAttributeString];
+    
+    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
+    [textStorage addLayoutManager:layoutManager];
+    
+    NSTextContainer *textContainer = [NSTextContainer new];
+    textContainer.lineFragmentPadding = 0.0;
+    
+    if ([[_wordWrap lowercaseString] isEqualToString:@"break-word"]) {
+        textContainer.lineBreakMode = NSLineBreakByWordWrapping;
+    } else if ([[_wordWrap lowercaseString] isEqualToString:@"normal"]){
+        textContainer.lineBreakMode = NSLineBreakByClipping;
+    } else {
+        // set default lineBreakMode
+        textContainer.lineBreakMode = NSLineBreakByCharWrapping;
+    }
+    
+    if (_textOverflow && [_textOverflow length] > 0) {
+        if ([_textOverflow isEqualToString:@"ellipsis"])
+            textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
+    }
+    textContainer.maximumNumberOfLines = _lines > 0 ? _lines : 0;
+    textContainer.size = (CGSize){isnan(width) ? CGFLOAT_MAX : width, CGFLOAT_MAX};
+
+    [layoutManager addTextContainer:textContainer];
+    [layoutManager ensureLayoutForTextContainer:textContainer];
+    
+    _textStorageWidth = width;
+    _textStorage = textStorage;
+    
+    return textStorage;
+}
+
+- (void)syncTextStorageForView
+{
+    CGFloat width = self.calculatedFrame.size.width - (_padding.left + _padding.right);
+    NSTextStorage *textStorage = nil;
+    if (![self useCoreText]) {
+        textStorage = [self textStorageWithWidth:width];
+    }
+    [self.weexInstance.componentManager  _addUITask:^{
+        if ([self isViewLoaded]) {
+            if (![self useCoreText]) {
+                ((WXTextView *)self.view).textStorage = textStorage;
+            }
+            [self readyToRender]; // notify super component
+            [self setNeedsDisplay];
+        }
+    }];
+}
+
+- (void)_frameDidCalculated:(BOOL)isChanged
+{
+    [super _frameDidCalculated:isChanged];
+    [self syncTextStorageForView];
+}
+
+- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles
+{
+    [super _updateStylesOnComponentThread:styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:isUpdateStyles];
+    NSMutableDictionary * newStyles = [styles mutableCopy];
+    for (NSString * key in [resetStyles copy]) {
+        [newStyles setObject:@"" forKey:key];
+    }
+    [self fillCSSStyles:newStyles];
+    
+    [self syncTextStorageForView];
+}
+
+- (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes
+{
+    [super _updateAttributesOnComponentThread:attributes];
+    
+    [self fillAttributes:attributes];
+    
+    [self syncTextStorageForView];
+}
+
+- (void)drawTextWithContext:(CGContextRef)context bounds:(CGRect)bounds padding:(UIEdgeInsets)padding view:(WXTextView *)view
+{
+    if (bounds.size.width <= 0 || bounds.size.height <= 0) {
+        return;
+    }
+    
+    if ([self _needsDrawBorder]) {
+        [self _drawBorderWithContext:context size:bounds.size];
+    } else {
+        WXPerformBlockOnMainThread(^{
+            [self _resetNativeBorderRadius];
+        });
+    }
+    if (![self useCoreText]) {
+        NSLayoutManager *layoutManager = _textStorage.layoutManagers.firstObject;
+        NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
+        
+        CGRect textFrame = UIEdgeInsetsInsetRect(bounds, padding);
+        NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
+        
+        [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:textFrame.origin];
+        [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:textFrame.origin];
+    } else {
+        CGRect textFrame = UIEdgeInsetsInsetRect(bounds, padding);
+        // sufficient height for text to draw, or frame lines will be empty
+        textFrame.size.height = bounds.size.height * 2;
+        CGContextSaveGState(context);
+        //flip the coordinate system
+        CGContextSetTextMatrix(context, CGAffineTransformIdentity);
+        CGContextTranslateCTM(context, 0, textFrame.size.height);
+        CGContextScaleCTM(context, 1.0, -1.0);
+        
+        NSAttributedString * attributedStringCopy = [self ctAttributedString];
+        //add path
+        CGPathRef cgPath = NULL;
+        cgPath = CGPathCreateWithRect(textFrame, NULL);
+        CTFrameRef _coreTextFrameRef = NULL;
+        if (_coreTextFrameRef) {
+            CFRelease(_coreTextFrameRef);
+            _coreTextFrameRef = NULL;
+        }
+        if(!attributedStringCopy) {
+            return;
+        }
+        CTFramesetterRef ctframesetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedStringCopy));
+        _coreTextFrameRef = CTFramesetterCreateFrame(ctframesetterRef, CFRangeMake(0, attributedStringCopy.length), cgPath, NULL);
+        CFArrayRef ctLines = NULL;
+        if (NULL == _coreTextFrameRef) {
+            // try to protect crash from frame is NULL
+            return;
+        }
+        CFRelease(ctframesetterRef);
+        ctframesetterRef = NULL;
+        ctLines = CTFrameGetLines(_coreTextFrameRef);
+        CFIndex lineCount = CFArrayGetCount(ctLines);
+        NSMutableArray * mutableLines = [NSMutableArray new];
+        CGPoint lineOrigins[lineCount];
+        NSUInteger rowCount = 0;
+        BOOL needTruncation = NO;
+        CTLineRef ctTruncatedLine = NULL;
+        CTFrameGetLineOrigins(_coreTextFrameRef, CFRangeMake(0, 0), lineOrigins);
+        for (CFIndex lineIndex = 0;(!_lines || _lines > lineIndex) && lineIndex < lineCount; lineIndex ++) {
+            CTLineRef lineRef = NULL;
+            lineRef = (CTLineRef)CFArrayGetValueAtIndex(ctLines, lineIndex);
+            if (!lineRef) {
+                break;
+            }
+            CGPoint lineOrigin = lineOrigins[lineIndex];
+            lineOrigin.x += padding.left;
+            lineOrigin.y -= padding.top;
+            CFArrayRef runs = CTLineGetGlyphRuns(lineRef);
+            [mutableLines addObject:(__bridge id _Nonnull)(lineRef)];
+            // lineIndex base 0
+            rowCount = lineIndex + 1;
+            if (_lines > 0 && _truncationLine) {
+                if (_truncationLine && rowCount > _lines) {
+                    needTruncation = YES;
+                    do {
+                        NSUInteger lastRow = [mutableLines count];
+                        if (lastRow < rowCount) {
+                           break;
+                        }
+                        [mutableLines removeLastObject];
+                    } while (1);
+
+                }
+            }
+            if (_lines > 0 && _truncationLine) {
+                if (rowCount >= _lines &&!needTruncation && (CTLineGetStringRange(lineRef).length + CTLineGetStringRange(lineRef).location) < attributedStringCopy.length) {
+                    needTruncation = YES;
+                }
+            }
+            
+            if (needTruncation) {
+                CGContextSetTextPosition(context, lineOrigin.x, lineOrigin.y);
+                ctTruncatedLine = [self buildTruncatedLineWithRuns:runs lines:mutableLines path:cgPath];
+                if (ctTruncatedLine) {
+                    CFArrayRef truncatedRuns = CTLineGetGlyphRuns(ctTruncatedLine);
+                    [self drawTextWithRuns:truncatedRuns context:context lineOrigin:lineOrigin];
+                    CFRelease(ctTruncatedLine);
+                    ctTruncatedLine = NULL;
+                    continue;
+                }
+            }else {
+                [self drawTextWithRuns:runs context:context lineOrigin:lineOrigin];
+            }
+        }
+        
+        [mutableLines removeAllObjects];
+        CGPathRelease(cgPath);
+        CFRelease(_coreTextFrameRef);
+        _coreTextFrameRef = NULL;
+        cgPath = NULL;
+        CGContextRestoreGState(context);
+    }
+}
+
+- (void)drawTextWithRuns:(CFArrayRef)runs context:(CGContextRef)context lineOrigin:(CGPoint)lineOrigin
+{
+    for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runs); runIndex ++) {
+        CTRunRef run = NULL;
+        run = (CTRunRef)CFArrayGetValueAtIndex(runs, runIndex);
+        CFDictionaryRef attr = NULL;
+        attr = CTRunGetAttributes(run);
+        if (0 == runIndex) {
+            NSNumber *baselineOffset = (NSNumber*)CFDictionaryGetValue(attr, (__bridge void *)NSBaselineOffsetAttributeName);
+            if (baselineOffset) {
+                lineOrigin.y += [baselineOffset doubleValue];
+            }
+        }
+        CGContextSetTextPosition(context, lineOrigin.x, lineOrigin.y);
+        CTRunDraw(run, context, CFRangeMake(0, 0));
+        CFIndex glyphCount = CTRunGetGlyphCount(run);
+        if (glyphCount <= 0) continue;
+        
+        long longForStrikethroughStyleAttributeName= (long)CFDictionaryGetValue(attr, (__bridge void *)NSStrikethroughStyleAttributeName);
+        NSUnderlineStyle strikethrough = (NSUnderlineStyle)longForStrikethroughStyleAttributeName;
+        
+        if (strikethrough) {
+            // draw strikethrough
+            [self drawLineThroughWithRun:runs context:context index:runIndex origin:lineOrigin];
+        }
+    }
+}
+
+- (CTLineRef)buildTruncatedLineWithRuns:(CFArrayRef)runs lines:(NSMutableArray*)mutableLines path:(CGPathRef)cgPath
+{
+    NSAttributedString * truncationToken = nil;
+    CTLineRef ctTruncatedLine = NULL;
+    CTLineRef lastLine = (__bridge CTLineRef)(mutableLines.lastObject);
+   
+    CFArrayRef lastLineRuns = CTLineGetGlyphRuns(lastLine);
+    NSUInteger lastLineRunCount = CFArrayGetCount(lastLineRuns);
+    
+    CTLineRef truncationTokenLine = NULL;
+    NSMutableDictionary *attrs = nil;
+    if (lastLineRunCount > 0) {
+        CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, lastLineRunCount - 1);
+        attrs = (id)CTRunGetAttributes(run);
+        attrs = attrs ? attrs.mutableCopy : [NSMutableDictionary new];
+        CTFontRef font = (__bridge CTFontRef)(attrs[(id)kCTFontAttributeName]);
+        CGFloat fontSize = font ? CTFontGetSize(font):32 * self.weexInstance.pixelScaleFactor;
+        UIFont * uiFont = [UIFont systemFontOfSize:fontSize];
+        if (uiFont) {
+            font = CTFontCreateWithName((__bridge CFStringRef)uiFont.fontName, uiFont.pointSize, NULL);
+        }
+        if (font) {
+            attrs[(id)kCTFontAttributeName] = (__bridge id)(font);
+            uiFont = nil;
+            CFRelease(font);
+        }
+        CGColorRef color = (__bridge CGColorRef)(attrs[(id)kCTForegroundColorAttributeName]);
+        if (color && CFGetTypeID(color) == CGColorGetTypeID() && CGColorGetAlpha(color) == 0) {
+            [attrs removeObjectForKey:(id)kCTForegroundColorAttributeName];
+        }
+        
+        attrs = attrs?:[NSMutableDictionary new];
+        truncationToken = [[NSAttributedString alloc] initWithString:WXTextTruncationToken attributes:attrs];
+        truncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)truncationToken);
+    }
+    
+    if (truncationTokenLine) {
+        // default truncationType is kCTLineTruncationEnd
+        CTLineTruncationType truncationType = kCTLineTruncationEnd;
+        NSAttributedString *attributedString = [self ctAttributedString];
+        NSAttributedString * lastLineText = nil;
+        NSRange lastLineTextRange = WXNSRangeFromCFRange(CTLineGetStringRange(lastLine));
+        NSRange attributeStringRange = NSMakeRange(0, attributedString.string.length);
+        NSRange interSectionRange = NSIntersectionRange(lastLineTextRange, attributeStringRange);
+        if (!NSEqualRanges(interSectionRange, lastLineTextRange)) {
+            // out of bounds
+            lastLineTextRange = interSectionRange;
+        }
+        lastLineText = [attributedString attributedSubstringFromRange: lastLineTextRange];
+        if (!lastLineText) {
+            lastLineText = attributedString;
+        }
+        NSMutableAttributedString *mutableLastLineText = lastLineText.mutableCopy;
+        [mutableLastLineText appendAttributedString:truncationToken];
+        CTLineRef ctLastLineExtend = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)[mutableLastLineText copy]);
+        if (ctLastLineExtend) {
+            CGRect cgPathRect = CGRectZero;
+            CGFloat truncatedWidth = 0;
+            if (CGPathIsRect(cgPath, &cgPathRect)) {
+                truncatedWidth = cgPathRect.size.width;
+            }
+            ctTruncatedLine = CTLineCreateTruncatedLine(ctLastLineExtend, truncatedWidth, truncationType, truncationTokenLine);
+            CFRelease(ctLastLineExtend);
+            ctLastLineExtend = NULL;
+            CFRelease(truncationTokenLine);
+            truncationTokenLine = NULL;
+        }
+    }
+    
+    return ctTruncatedLine;
+}
+
+- (void)drawLineThroughWithRun:(CFArrayRef)runs context:(CGContextRef)context index:(CFIndex)runIndex origin:(CGPoint)lineOrigin
+{
+    CFRetain(runs);
+    CGContextRetain(context);
+    
+    CGContextSaveGState(context);
+    CGFloat xHeight = 0, underLinePosition = 0, lineThickness = 0;
+    CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, runIndex);
+    WXTextGetRunsMaxMetric(runs, &xHeight, &underLinePosition, &lineThickness);
+    
+    CGPoint strikethroughStart;
+    strikethroughStart.x =  lineOrigin.x - underLinePosition;
+    strikethroughStart.y = lineOrigin.y + xHeight/2;
+    CGPoint runPosition = CGPointZero;
+    CTRunGetPositions(run, CFRangeMake(0, 1), &runPosition);
+    strikethroughStart.x = lineOrigin.x + runPosition.x;
+    CGContextSetLineWidth(context, WXTextDefaultLineThroughWidth);
+    double length = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), NULL, NULL, NULL);
+    CGContextMoveToPoint(context, strikethroughStart.x, strikethroughStart.y);
+    CGContextAddLineToPoint(context, strikethroughStart.x + length, strikethroughStart.y);
+    CGContextStrokePath(context);
+    
+    CGContextRestoreGState(context);
+    CFRelease(runs);
+    CGContextRelease(context);
+}
+
+- (CGSize)calculateTextHeightWithWidth:(CGFloat)aWidth
+{
+    CGFloat totalHeight = 0;
+    CGSize suggestSize = CGSizeZero;
+    NSAttributedString * attributedStringCpy = [self ctAttributedString];
+    if (!attributedStringCpy) {
+        return CGSizeZero;
+    }
+    if (isnan(aWidth)) {
+        aWidth = CGFLOAT_MAX;
+    }
+    aWidth = [attributedStringCpy boundingRectWithSize:CGSizeMake(aWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading context:nil].size.width;
+    CTFramesetterRef ctframesetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedStringCpy));
+    suggestSize = CTFramesetterSuggestFrameSizeWithConstraints(ctframesetterRef, CFRangeMake(0, 0), NULL, CGSizeMake(aWidth, MAXFLOAT), NULL);
+    
+    CGMutablePathRef path = NULL;
+    path = CGPathCreateMutable();
+        // sufficient height to draw text
+    CGPathAddRect(path, NULL, CGRectMake(0, 0, aWidth, suggestSize.height * 10));
+        
+    CTFrameRef frameRef = NULL;
+    frameRef = CTFramesetterCreateFrame(ctframesetterRef, CFRangeMake(0, attributedStringCpy.length), path, NULL);
+    CGPathRelease(path);
+    
+    CFArrayRef lines = NULL;
+    if (NULL == frameRef) {
+        //try to protect unexpected crash.
+        return suggestSize;
+    }
+    CFRelease(ctframesetterRef);
+    ctframesetterRef = NULL;
+    lines = CTFrameGetLines(frameRef);
+    CFIndex lineCount = CFArrayGetCount(lines);
+    CGFloat ascent = 0;
+    CGFloat descent = 0;
+    CGFloat leading = 0;
+    
+    // height = ascent + descent + lineCount*leading
+    // ignore linespaing
+    NSUInteger actualLineCount = 0;
+    for (CFIndex lineIndex = 0; (!_lines|| lineIndex < _lines) && lineIndex < lineCount; lineIndex ++)
+    {
+        CTLineRef lineRef = NULL;
+        lineRef = (CTLineRef)CFArrayGetValueAtIndex(lines, lineIndex);
+        CTLineGetTypographicBounds(lineRef, &ascent, &descent, &leading);
+        totalHeight += ascent + descent;
+        actualLineCount ++;
+    }
+    
+    totalHeight = totalHeight + actualLineCount * leading;
+    CFRelease(frameRef);
+    frameRef = NULL;
+    
+    if (WX_SYS_VERSION_LESS_THAN(@"10.0")) {
+        // there is something wrong with coreText drawing text height, trying to fix this with more efficent way.
+        if(actualLineCount && actualLineCount < lineCount) {
+            suggestSize.height = suggestSize.height * actualLineCount / lineCount;
+        }
+        return CGSizeMake(aWidth, suggestSize.height);
+    }
+    return CGSizeMake(aWidth, totalHeight);
+}
+
+static void WXTextGetRunsMaxMetric(CFArrayRef runs, CGFloat *xHeight, CGFloat *underlinePosition, CGFloat *lineThickness)
+{
+    CFRetain(runs);
+    CGFloat maxXHeight = 0;
+    CGFloat maxUnderlinePos = 0;
+    CGFloat maxLineThickness = 0;
+    for (NSUInteger index = 0, runsCount = CFArrayGetCount(runs); index < runsCount; index ++) {
+        CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, index);
+        CFDictionaryRef attrs = CTRunGetAttributes(run);
+        if (attrs) {
+            CTFontRef font = (CTFontRef)CFDictionaryGetValue(attrs, kCTFontAttributeName);
+            if (font) {
+                CGFloat xHeight = CTFontGetXHeight(font);
+                if (xHeight > maxXHeight) {
+                    maxXHeight = xHeight;
+                }
+                
+                CGFloat underlinePos = CTFontGetUnderlinePosition(font);
+                if (underlinePos < maxUnderlinePos) {
+                    maxUnderlinePos = underlinePos;
+                }
+                
+                CGFloat lineThickness = CTFontGetUnderlineThickness(font);
+                if (lineThickness > maxLineThickness) {
+                    maxLineThickness = lineThickness;
+                }
+            }
+        }
+    }
+    
+    if (xHeight) {
+        *xHeight = maxXHeight;
+    }
+    
+    if (underlinePosition) {
+        *underlinePosition = maxUnderlinePos;
+    }
+    
+    if (lineThickness) {
+        *lineThickness = maxLineThickness;
+    }
+    
+    CFRelease(runs);
+}
+                                                                                                                                       
+NS_INLINE NSRange WXNSRangeFromCFRange(CFRange range) {
+    return NSMakeRange(range.location, range.length);
+}
+
+#ifdef UITEST
+- (NSString *)description
+{
+    return super.description;
+}
+#endif
+ 
+- (void)_resetCSSNodeStyles:(NSArray *)styles
+{
+    [super _resetCSSNodeStyles:styles];
+    if ([styles containsObject:@"color"]) {
+        _color = [UIColor blackColor];
+        [self setNeedsRepaint];
+    }
+    if ([styles containsObject:@"fontSize"]) {
+        _fontSize = WX_TEXT_FONT_SIZE;
+        [self setNeedsRepaint];
+        [self setNeedsLayout];
+    }
+}
+
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m b/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
index dad372c..e2d35d6 100644
--- a/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
+++ b/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
@@ -38,6 +38,8 @@
 #import "WXUtility.h"
 #import "WXExtendCallNativeManager.h"
 #import "WXExceptionUtils.h"
+#import "WXConfigCenterProtocol.h"
+#import "WXComponent+Layout.h"
 
 @implementation WXSDKEngine
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
index 1baa20f..651af7c 100644
--- a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
@@ -20,7 +20,65 @@
 #import "WXComponent.h"
 #import "WXSDKInstance.h"
 #import "WXUtility.h"
+#import "WXLayoutDefine.h"
+#import "WXCoreLayout.h"
 
-@interface WXComponent (Layout)
+#define FlexUndefined NAN
+//#define USE_FLEX
+
+
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    bool flexIsUndefined(float value);
+#ifdef __cplusplus
+}
+#endif
 
+@interface WXComponent ()
+{
+    @package
+    /**
+     *  Layout
+     */
+//#ifndef USE_FLEX
+    css_node_t *_cssNode;
+//#else
+#ifdef __cplusplus
+    WeexCore::WXCoreLayoutNode *_flexCssNode;
+#endif // __cplusplus
+//#endif //USE_FLEX
+    BOOL _isLayoutDirty;
+    CGRect _calculatedFrame;
+    CGPoint _absolutePosition;
+    WXPositionType _positionType;
+}
+
+//#ifndef USE_FLEX
+/**
+ * @abstract Return the css node used to layout.
+ *
+ * @warning Subclasses must not override this.
+ */
+@property(nonatomic, readonly, assign) css_node_t *cssNode;
+//#else
+#ifdef __cplusplus
+@property(nonatomic, readonly, assign) WeexCore::WXCoreLayoutNode *flexCssNode;
+#endif
+//#endif
+
+@end
+
+@interface WXComponent (Layout)
+//#ifndef USE_FLEX
+//#else
+- (void)_insertChildCssNode:(WXComponent*)subcomponent atIndex:(NSInteger)index;
+- (void)_rmChildCssNode:(WXComponent*)subcomponent;
+- (NSInteger) getActualNodeIndex:(WXComponent*)subcomponent atIndex:(NSInteger) index;
++ (void) setUseFlex:(BOOL) useFlex;
++ (BOOL) isUseFlex;
+//#endif
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
new file mode 100644
index 0000000..4bdb8f4
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
@@ -0,0 +1,963 @@
+/*
+ * 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+Layout.h"
+#import "WXComponent_internal.h"
+#import "WXTransform.h"
+#import "WXAssert.h"
+#import "WXSDKInstance_private.h"
+#import "WXComponent+BoxShadow.h"
+#import "WXLog.h"
+
+bool flexIsUndefined(float value) {
+    return isnan(value);
+}
+
+static BOOL sUseFlex = TRUE;
+
+
+@implementation WXComponent (Layout)
+
+#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+
+#pragma mark Public
+
+- (void)setNeedsLayout
+{
+    _isLayoutDirty = YES;
+    WXComponent *supercomponent = [self supercomponent];
+    if ([WXComponent isUseFlex]) {
+        //protet nil ptr
+        if (self.flexCssNode) {
+            self.flexCssNode->markDirty();
+        }else{
+            WXLogError(@"flexCssNode is nil");
+        }
+    }
+    
+    if(supercomponent){
+        [supercomponent setNeedsLayout];
+    }
+}
+
+- (BOOL)needsLayout
+{
+    return _isLayoutDirty;
+}
+
+- (CGSize (^)(CGSize))measureBlock
+{
+    return nil;
+}
+
+- (void)layoutDidFinish
+{
+    WXAssertMainThread();
+}
+
+#pragma mark Private
+
+- (void)_initCSSNodeWithStyles:(NSDictionary *)styles
+{
+//#ifndef USE_FLEX
+    if (! [WXComponent isUseFlex]) {
+        _cssNode = new_css_node();
+        
+        _cssNode->print = cssNodePrint;
+        _cssNode->get_child = cssNodeGetChild;
+        _cssNode->is_dirty = cssNodeIsDirty;
+        if ([self measureBlock]) {
+            _cssNode->measure = cssNodeMeasure;
+        }
+        _cssNode->context = (__bridge void *)self;
+        
+        [self _recomputeCSSNodeChildren];
+        [self _fillCSSNode:styles isUpdate:NO];
+        
+        // To be in conformity with Android/Web, hopefully remove this in the future.
+        if ([self.ref isEqualToString:WX_SDK_ROOT_REF]) {
+            if (isUndefined(_cssNode->style.dimensions[CSS_HEIGHT]) && self.weexInstance.frame.size.height) {
+                _cssNode->style.dimensions[CSS_HEIGHT] = self.weexInstance.frame.size.height;
+            }
+            
+            if (isUndefined(_cssNode->style.dimensions[CSS_WIDTH]) && self.weexInstance.frame.size.width) {
+                _cssNode->style.dimensions[CSS_WIDTH] = self.weexInstance.frame.size.width;
+            }
+        }
+    }
+
+//#else
+    else
+    {
+        _flexCssNode = new WeexCore::WXCoreLayoutNode();
+        if ([self measureBlock]) {
+            _flexCssNode->setMeasureFunc(flexCssNodeMeasure);
+        }
+        _flexCssNode->setContext((__bridge void *)self);
+        [self _recomputeCSSNodeChildren];
+        [self _fillCSSNode:styles isUpdate:NO];
+        
+        if ([self.ref isEqualToString:WX_SDK_ROOT_REF]) {
+            if (flexIsUndefined(_flexCssNode->getStyleHeight()) && self.weexInstance.frame.size.height) {
+                _flexCssNode->setStyleHeight(self.weexInstance.frame.size.height);
+            }
+            
+            if (flexIsUndefined(_flexCssNode->getStyleWidth()) && self.weexInstance.frame.size.width) {
+                _flexCssNode->setStyleWidth(self.weexInstance.frame.size.width,NO);
+            }
+        }
+    }
+//#endif
+}
+
+- (void)_updateCSSNodeStyles:(NSDictionary *)styles
+{
+    [self _fillCSSNode:styles isUpdate:YES];
+}
+
+-(void)_resetCSSNodeStyles:(NSArray *)styles
+{
+    [self _resetCSSNode:styles];
+}
+
+- (void)_recomputeCSSNodeChildren
+{
+//#ifndef USE_FLEX
+    if (![WXComponent isUseFlex]) {
+        _cssNode->children_count = (int)[self _childrenCountForLayout];
+    }
+//#else
+    
+//#endif
+}
+
+- (NSUInteger)_childrenCountForLayout
+{
+    NSArray *subcomponents = _subcomponents;
+    NSUInteger count = subcomponents.count;
+    for (WXComponent *component in subcomponents) {
+        if (!component->_isNeedJoinLayoutSystem) {
+            count--;
+        }
+    }
+    return (int)(count);
+}
+
+
+- (void)_frameDidCalculated:(BOOL)isChanged
+{
+    WXAssertComponentThread();
+    
+    if ([self isViewLoaded] && isChanged && [self isViewFrameSyncWithCalculated]) {
+        
+        __weak typeof(self) weakSelf = self;
+        [self.weexInstance.componentManager _addUITask:^{
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            if (strongSelf->_transform && !CATransform3DEqualToTransform(strongSelf.layer.transform, CATransform3DIdentity)) {
+                // From the UIView's frame documentation:
+                // https://developer.apple.com/reference/uikit/uiview#//apple_ref/occ/instp/UIView/frame
+                // Warning : If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
+                // So layer's transform must be reset to CATransform3DIdentity before setFrame, otherwise frame will be incorrect
+                strongSelf.layer.transform = CATransform3DIdentity;
+            }
+            
+            if (!CGRectEqualToRect(strongSelf.view.frame,strongSelf.calculatedFrame)) {
+                strongSelf.view.frame = strongSelf.calculatedFrame;
+                strongSelf->_absolutePosition = CGPointMake(NAN, NAN);
+                [strongSelf configBoxShadow:_boxShadow];
+            } else {
+                if (![strongSelf equalBoxShadow:_boxShadow withBoxShadow:_lastBoxShadow]) {
+                    [strongSelf configBoxShadow:_boxShadow];
+                }
+            }
+            
+            [self _resetNativeBorderRadius];
+            
+            if (strongSelf->_transform) {
+                [strongSelf->_transform applyTransformForView:strongSelf.view];
+            }
+            
+            if (strongSelf->_backgroundImage) {
+                [strongSelf setGradientLayer];
+            }
+            [strongSelf setNeedsDisplay];
+        }];
+    }
+}
+
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition
+                           gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
+{
+    WXAssertComponentThread();
+
+//#ifndef USE_FLEX
+    if (![WXComponent isUseFlex])
+    {
+        if (!_cssNode->layout.should_update) {
+            return;
+        }
+        _cssNode->layout.should_update = false;
+        _isLayoutDirty = NO;
+        
+        CGRect newFrame = CGRectMake(isnan(WXRoundPixelValue(_cssNode->layout.position[CSS_LEFT]))?0:WXRoundPixelValue(_cssNode->layout.position[CSS_LEFT]),
+                                     isnan(WXRoundPixelValue(_cssNode->layout.position[CSS_TOP]))?0:WXRoundPixelValue(_cssNode->layout.position[CSS_TOP]),
+                                     isnan(WXRoundPixelValue(_cssNode->layout.dimensions[CSS_WIDTH]))?0:WXRoundPixelValue(_cssNode->layout.dimensions[CSS_WIDTH]),
+                                     isnan(WXRoundPixelValue(_cssNode->layout.dimensions[CSS_HEIGHT]))?0:WXRoundPixelValue(_cssNode->layout.dimensions[CSS_HEIGHT]));
+        
+        BOOL isFrameChanged = NO;
+        if (!CGRectEqualToRect(newFrame, _calculatedFrame)) {
+            isFrameChanged = YES;
+            _calculatedFrame = newFrame;
+            [dirtyComponents addObject:self];
+        }
+        
+        _cssNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
+        _cssNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
+        _cssNode->layout.position[CSS_LEFT] = 0;
+        _cssNode->layout.position[CSS_TOP] = 0;
+        
+        [self _frameDidCalculated:isFrameChanged];
+        NSArray * subcomponents = [_subcomponents copy];
+        for (WXComponent *subcomponent in subcomponents) {
+            [subcomponent _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+        }
+#ifdef DEBUG
+        WXLogDebug(@"flexLayout -> newFrame ,type:%@,ref:%@, parentRef:%@,size :%@ ,instance:%@",self.type,self.ref,self.supercomponent.ref,NSStringFromCGRect(newFrame),self.weexInstance.instanceId);
+#endif
+    }
+    
+//#else
+    else
+    {
+        if (self.flexCssNode->hasNewLayout()) {
+            self.flexCssNode->setHasNewLayout(false);
+            _isLayoutDirty = NO;
+            CGRect newFrame = CGRectMake(
+                                         isnan(WXRoundPixelValue(_flexCssNode->getLayoutPositionLeft()))?0:WXRoundPixelValue(_flexCssNode->getLayoutPositionLeft())
+                                         ,isnan(WXRoundPixelValue(_flexCssNode->getLayoutPositionTop()))?0:WXRoundPixelValue(_flexCssNode->getLayoutPositionTop())
+                                         ,isnan(WXRoundPixelValue(_flexCssNode->getLayoutWidth()))?0:WXRoundPixelValue(_flexCssNode->getLayoutWidth())
+                                         ,isnan(WXRoundPixelValue(_flexCssNode->getLayoutHeight()))?0:WXRoundPixelValue(_flexCssNode->getLayoutHeight())
+                                         );
+            BOOL isFrameChanged = NO;
+            
+            if (!CGRectEqualToRect(newFrame, _calculatedFrame)) {
+                
+                isFrameChanged = YES;
+                _calculatedFrame = newFrame;
+                [dirtyComponents addObject:self];
+            }
+            
+            [self _frameDidCalculated:isFrameChanged];
+#ifdef DEBUG
+            WXLogDebug(@"flexLayout -> newFrame ,type:%@,ref:%@, parentRef:%@,size :%@ ,instance:%@",self.type,self.ref,self.supercomponent.ref,NSStringFromCGRect(newFrame),self.weexInstance.instanceId);
+#endif
+        }
+    
+        NSArray * subcomponents = [_subcomponents copy];
+        for (WXComponent *subcomponent in subcomponents) {
+            [subcomponent _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+        }
+    }
+//#endif
+}
+
+- (void)_layoutDidFinish
+{
+    WXAssertMainThread();
+
+    if (_positionType == WXPositionTypeSticky) {
+        [self.ancestorScroller adjustSticky];
+    }
+    [self layoutDidFinish];
+}
+
+//#ifndef USE_FLEX
+
+#define WX_STYLE_FILL_CSS_NODE(key, cssProp, type)\
+do {\
+    id value = styles[@#key];\
+    if (value) {\
+        typeof(_cssNode->style.cssProp) convertedValue = (typeof(_cssNode->style.cssProp))[WXConvert type:value];\
+        _cssNode->style.cssProp = convertedValue;\
+        [self setNeedsLayout];\
+    }\
+} while(0);
+
+#define WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp)\
+do {\
+    id value = styles[@#key];\
+    if (value) {\
+        CGFloat pixel = [self WXPixelType:value];\
+        if (isnan(pixel)) {\
+            WXLogError(@"Invalid NaN value for style:%@, ref:%@", @#key, self.ref);\
+        } else {\
+            _cssNode->style.cssProp = pixel;\
+            [self setNeedsLayout];\
+        }\
+    }\
+} while(0);
+
+#define WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION(key, cssProp)\
+do {\
+    WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp[CSS_TOP])\
+    WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp[CSS_LEFT])\
+    WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp[CSS_RIGHT])\
+    WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp[CSS_BOTTOM])\
+} while(0);
+
+//#else
+
+#define WX_STYLE_FLEX_NODE_JUDGE_LEGAL(key) styles[key]&&!isnan([WXConvert WXPixelType:styles[key] scaleFactor:self.weexInstance.pixelScaleFactor])
+
+//#endif
+
+- (CGFloat)WXPixelType:(id)value
+{
+    return [WXConvert WXPixelType:value scaleFactor:self.weexInstance.pixelScaleFactor];
+}
+
+- (void)_fillCSSNode:(NSDictionary *)styles isUpdate:(BOOL)isUpdate
+{
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        WX_STYLE_FILL_CSS_NODE(direction, direction, css_direction_t)
+        // flex
+        WX_STYLE_FILL_CSS_NODE(flex, flex, CGFloat)
+        WX_STYLE_FILL_CSS_NODE(flexDirection, flex_direction, css_flex_direction_t)
+        WX_STYLE_FILL_CSS_NODE(alignItems, align_items, css_align_t)
+        WX_STYLE_FILL_CSS_NODE(alignSelf, align_self, css_align_t)
+        WX_STYLE_FILL_CSS_NODE(flexWrap, flex_wrap, css_wrap_type_t)
+        WX_STYLE_FILL_CSS_NODE(justifyContent, justify_content, css_justify_t)
+        
+        // position
+        WX_STYLE_FILL_CSS_NODE(position, position_type, css_position_type_t)
+        WX_STYLE_FILL_CSS_NODE_PIXEL(top, position[CSS_TOP])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(left, position[CSS_LEFT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(right, position[CSS_RIGHT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(bottom, position[CSS_BOTTOM])
+        
+        // dimension
+        WX_STYLE_FILL_CSS_NODE_PIXEL(width, dimensions[CSS_WIDTH])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(height, dimensions[CSS_HEIGHT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(minWidth, minDimensions[CSS_WIDTH])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(minHeight, minDimensions[CSS_HEIGHT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(maxWidth, maxDimensions[CSS_WIDTH])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(maxHeight, maxDimensions[CSS_HEIGHT])
+        
+        // margin
+        WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION(margin, margin)
+        WX_STYLE_FILL_CSS_NODE_PIXEL(marginTop, margin[CSS_TOP])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(marginLeft, margin[CSS_LEFT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(marginRight, margin[CSS_RIGHT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(marginBottom, margin[CSS_BOTTOM])
+        
+        // border
+        WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION(borderWidth, border)
+        WX_STYLE_FILL_CSS_NODE_PIXEL(borderTopWidth, border[CSS_TOP])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(borderLeftWidth, border[CSS_LEFT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(borderRightWidth, border[CSS_RIGHT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(borderBottomWidth, border[CSS_BOTTOM])
+        
+        // padding
+        WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION(padding, padding)
+        WX_STYLE_FILL_CSS_NODE_PIXEL(paddingTop, padding[CSS_TOP])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(paddingLeft, padding[CSS_LEFT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(paddingRight, padding[CSS_RIGHT])
+        WX_STYLE_FILL_CSS_NODE_PIXEL(paddingBottom, padding[CSS_BOTTOM])
+    }
+   
+//#else
+    else
+    {
+        // flex
+        if (styles[@"flex"]) {
+            _flexCssNode->setFlex([WXConvert CGFloat:styles[@"flex"]]);
+        }
+        if (isnan(_flexCssNode->getFlex())) {
+            // to make the default flex value is zero, yoga is nan, maybe this can configured by yoga config
+            _flexCssNode->setFlex(0);
+        }
+        
+        if (styles[@"flexDirection"]) {
+            _flexCssNode->setFlexDirection([self fxFlexDirection:styles[@"flexDirection"]],isUpdate);
+        }
+        if (styles[@"alignItems"]) {
+            _flexCssNode->setAlignItems([self fxAlign:styles[@"alignItems"]]);
+        }
+        if (styles[@"alignSelf"]) {
+            _flexCssNode->setAlignSelf([self fxAlignSelf:styles[@"alignSelf"]]);
+        }
+        if (styles[@"flexWrap"]) {
+            _flexCssNode->setFlexWrap([self fxWrap:styles[@"flexWrap"]]);
+        }
+        if (styles[@"justifyContent"]) {
+            _flexCssNode->setJustifyContent([self fxJustify:styles[@"justifyContent"]]);
+        }
+        
+        // position
+        if (styles[@"position"]) {
+            _flexCssNode->setStylePositionType([self fxPositionType:styles[@"position"]]);
+        }
+        if (styles[@"top"]) {
+            _flexCssNode->setStylePosition(WeexCore::kPositionEdgeTop,
+                                           [self judgePropValuePropValue:styles[@"top"] defaultValue:NAN]);
+        }
+        if (styles[@"left"]) {
+            _flexCssNode->setStylePosition(WeexCore::kPositionEdgeLeft,
+                                           [self judgePropValuePropValue:styles[@"left"] defaultValue:NAN]);
+        }
+        if(styles[@"right"]) {
+            _flexCssNode->setStylePosition(WeexCore::kPositionEdgeRight,
+                                           [self judgePropValuePropValue:styles[@"right"] defaultValue:NAN]);
+        }
+        if (styles[@"bottom"]) {
+            _flexCssNode->setStylePosition(WeexCore::kPositionEdgeBottom,
+                                           [self judgePropValuePropValue:styles[@"bottom"] defaultValue:NAN]);
+        }
+        
+        // dimension
+        if (styles[@"width"]) {
+            _flexCssNode->setStyleWidth([self judgePropValuePropValue:styles[@"width"] defaultValue:NAN]
+                                        ,isUpdate);
+        }
+        if (styles[@"height"]) {
+            _flexCssNode->setStyleHeight([self judgePropValuePropValue:styles[@"height"] defaultValue:NAN]);
+        }
+        if (styles[@"minWidth"]) {
+            _flexCssNode->setMinWidth([self judgePropValuePropValue:styles[@"minWidth"] defaultValue:NAN]
+                                      ,isUpdate);
+        }
+        if (styles[@"minHeight"]) {
+            _flexCssNode->setMinHeight([self judgePropValuePropValue:styles[@"minHeight"] defaultValue:NAN]);
+        }
+        if (styles[@"maxWidth"]) {
+            _flexCssNode->setMaxWidth([self judgePropValuePropValue:styles[@"maxWidth"] defaultValue:NAN]
+                                      ,isUpdate);
+        }
+        if (styles[@"maxHeight"]) {
+            _flexCssNode->setMaxHeight([self judgePropValuePropValue:styles[@"maxHeight"] defaultValue:NAN]);
+        }
+        
+        // margin
+        if (styles[@"margin"]) {
+            _flexCssNode->setMargin(WeexCore::kMarginALL,
+                                    [self judgePropValuePropValue:styles[@"margin"] defaultValue:0]);
+        }
+        if (styles[@"marginTop"]) {
+            _flexCssNode->setMargin(WeexCore::kMarginTop,
+                                    [self judgePropValuePropValue:styles[@"marginTop"] defaultValue:0]);
+        }
+        if (styles[@"marginBottom"]) {
+            _flexCssNode->setMargin(WeexCore::kMarginBottom,
+                                    [self judgePropValuePropValue:styles[@"marginBottom"] defaultValue:0]);
+        }
+        if (styles[@"marginRight"]) {
+            _flexCssNode->setMargin(WeexCore::kMarginRight,
+                                    [self judgePropValuePropValue:styles[@"marginRight"] defaultValue:0]);
+        }
+        if (styles[@"marginLeft"]) {
+            _flexCssNode->setMargin(WeexCore::kMarginLeft,
+                                    [self judgePropValuePropValue:styles[@"marginLeft"] defaultValue:0]);
+        }
+        
+        // border
+        if (styles[@"borderWidth"]) {
+            _flexCssNode->setBorderWidth(WeexCore::kBorderWidthALL,
+                                         [self judgePropValuePropValue:styles[@"borderWidth"] defaultValue:0]);
+        }
+        if (styles[@"borderTopWidth"]) {
+            _flexCssNode->setBorderWidth(WeexCore::kBorderWidthTop,
+                                         [self judgePropValuePropValue:styles[@"borderTopWidth"] defaultValue:0]);
+        }
+        
+        if (styles[@"borderLeftWidth"]) {
+            _flexCssNode->setBorderWidth(WeexCore::kBorderWidthLeft,
+                                         [self judgePropValuePropValue:styles[@"borderLeftWidth"] defaultValue:0]);
+        }
+        
+        if (styles[@"borderBottomWidth"]) {
+            _flexCssNode->setBorderWidth(WeexCore::kBorderWidthBottom,
+                                         [self judgePropValuePropValue:styles[@"borderBottomWidth"] defaultValue:0]);
+        }
+        if (styles[@"borderRightWidth"]) {
+            _flexCssNode->setBorderWidth(WeexCore::kBorderWidthRight,
+                                         [self judgePropValuePropValue:styles[@"borderRightWidth"] defaultValue:0]);
+        }
+        
+        // padding
+        if (styles[@"padding"]) {
+            _flexCssNode->setPadding(WeexCore::kPaddingALL,
+                                     [self judgePropValuePropValue:styles[@"padding"] defaultValue:0]);
+        }
+        if (styles[@"paddingTop"]) {
+            _flexCssNode->setPadding(WeexCore::kPaddingTop,
+                                     [self judgePropValuePropValue:styles[@"paddingTop"] defaultValue:0]);
+        }
+        if (styles[@"paddingLeft"]) {
+            _flexCssNode->setPadding(WeexCore::kPaddingLeft,
+                                     [self judgePropValuePropValue:styles[@"paddingLeft"] defaultValue:0]);
+        }
+        if (styles[@"paddingBottom"]) {
+            _flexCssNode->setPadding(WeexCore::kPaddingBottom,
+                                     [self judgePropValuePropValue:styles[@"paddingBottom"] defaultValue:0]);
+        }
+        if (styles[@"paddingRight"]) {
+            _flexCssNode->setPadding(WeexCore::kPaddingRight,
+                                     [self judgePropValuePropValue:styles[@"paddingRight"] defaultValue:0]);
+        }
+        
+        [self setNeedsLayout];
+    }
+ 
+//#endif
+}
+
+-(CGFloat)judgePropValuePropValue:(NSString *)propValue defaultValue:(CGFloat)defaultValue{
+    CGFloat convertValue = (CGFloat)[WXConvert WXPixelType:propValue scaleFactor:self.weexInstance.pixelScaleFactor];
+    if (!isnan(convertValue)) {
+        return convertValue;
+    }
+    return defaultValue;
+}
+
+//#ifndef USE_FLEX
+
+#define WX_STYLE_RESET_CSS_NODE(key, cssProp, defaultValue)\
+do {\
+    if (styles && [styles containsObject:@#key]) {\
+        _cssNode->style.cssProp = defaultValue;\
+        [self setNeedsLayout];\
+    }\
+} while(0);
+
+#define WX_STYLE_RESET_CSS_NODE_ALL_DIRECTION(key, cssProp, defaultValue)\
+do {\
+    WX_STYLE_RESET_CSS_NODE(key, cssProp[CSS_TOP], defaultValue)\
+    WX_STYLE_RESET_CSS_NODE(key, cssProp[CSS_LEFT], defaultValue)\
+    WX_STYLE_RESET_CSS_NODE(key, cssProp[CSS_RIGHT], defaultValue)\
+    WX_STYLE_RESET_CSS_NODE(key, cssProp[CSS_BOTTOM], defaultValue)\
+} while(0);
+
+//#else
+
+#define WX_FLEX_STYLE_RESET_CSS_NODE(key, defaultValue)\
+do {\
+    WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_KEY(key,key,defaultValue)\
+} while(0);
+
+#define WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_KEY(judgeKey, propKey, defaultValue)\
+do {\
+    if (styles && [styles containsObject:@#judgeKey]) {\
+        NSMutableDictionary *resetStyleDic = [[NSMutableDictionary alloc] init];\
+        [resetStyleDic setValue:defaultValue forKey:@#propKey];\
+        [self _updateCSSNodeStyles:resetStyleDic];\
+        [self setNeedsLayout];\
+    }\
+} while(0);
+
+#define WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(judgeKey, propTopKey,propLeftKey,propRightKey,propBottomKey, defaultValue)\
+do {\
+    if (styles && [styles containsObject:@#judgeKey]) {\
+        NSMutableDictionary *resetStyleDic = [[NSMutableDictionary alloc] init];\
+        [resetStyleDic setValue:defaultValue forKey:@#propTopKey];\
+        [resetStyleDic setValue:defaultValue forKey:@#propLeftKey];\
+        [resetStyleDic setValue:defaultValue forKey:@#propRightKey];\
+        [resetStyleDic setValue:defaultValue forKey:@#propBottomKey];\
+        [self _updateCSSNodeStyles:resetStyleDic];\
+        [self setNeedsLayout];\
+    }\
+} while(0);
+
+//#endif
+
+
+- (void)_resetCSSNode:(NSArray *)styles
+{
+//#ifndef USE_FLEX
+    if(![WXComponent isUseFlex])
+    {
+        WX_STYLE_RESET_CSS_NODE(direction, direction, CSS_DIRECTION_LTR)
+        // flex
+        WX_STYLE_RESET_CSS_NODE(flex, flex, 0.0)
+        WX_STYLE_RESET_CSS_NODE(flexDirection, flex_direction, CSS_FLEX_DIRECTION_COLUMN)
+        WX_STYLE_RESET_CSS_NODE(alignItems, align_items, CSS_ALIGN_STRETCH)
+        WX_STYLE_RESET_CSS_NODE(alignSelf, align_self, CSS_ALIGN_AUTO)
+        WX_STYLE_RESET_CSS_NODE(flexWrap, flex_wrap, CSS_NOWRAP)
+        WX_STYLE_RESET_CSS_NODE(justifyContent, justify_content, CSS_JUSTIFY_FLEX_START)
+        
+        // position
+        WX_STYLE_RESET_CSS_NODE(position, position_type, CSS_POSITION_RELATIVE)
+        WX_STYLE_RESET_CSS_NODE(top, position[CSS_TOP], CSS_UNDEFINED)
+        WX_STYLE_RESET_CSS_NODE(left, position[CSS_LEFT], CSS_UNDEFINED)
+        WX_STYLE_RESET_CSS_NODE(right, position[CSS_RIGHT], CSS_UNDEFINED)
+        WX_STYLE_RESET_CSS_NODE(bottom, position[CSS_BOTTOM], CSS_UNDEFINED)
+        
+        // dimension
+        WX_STYLE_RESET_CSS_NODE(width, dimensions[CSS_WIDTH], CSS_UNDEFINED)
+        WX_STYLE_RESET_CSS_NODE(height, dimensions[CSS_HEIGHT], CSS_UNDEFINED)
+        WX_STYLE_RESET_CSS_NODE(minWidth, minDimensions[CSS_WIDTH], CSS_UNDEFINED)
+        WX_STYLE_RESET_CSS_NODE(minHeight, minDimensions[CSS_HEIGHT], CSS_UNDEFINED)
+        WX_STYLE_RESET_CSS_NODE(maxWidth, maxDimensions[CSS_WIDTH], CSS_UNDEFINED)
+        WX_STYLE_RESET_CSS_NODE(maxHeight, maxDimensions[CSS_HEIGHT], CSS_UNDEFINED)
+        
+        // margin
+        WX_STYLE_RESET_CSS_NODE_ALL_DIRECTION(margin, margin, 0.0)
+        WX_STYLE_RESET_CSS_NODE(marginTop, margin[CSS_TOP], 0.0)
+        WX_STYLE_RESET_CSS_NODE(marginLeft, margin[CSS_LEFT], 0.0)
+        WX_STYLE_RESET_CSS_NODE(marginRight, margin[CSS_RIGHT], 0.0)
+        WX_STYLE_RESET_CSS_NODE(marginBottom, margin[CSS_BOTTOM], 0.0)
+        
+        // border
+        WX_STYLE_RESET_CSS_NODE_ALL_DIRECTION(borderWidth, border, 0.0)
+        WX_STYLE_RESET_CSS_NODE(borderTopWidth, border[CSS_TOP], 0.0)
+        WX_STYLE_RESET_CSS_NODE(borderLeftWidth, border[CSS_LEFT], 0.0)
+        WX_STYLE_RESET_CSS_NODE(borderRightWidth, border[CSS_RIGHT], 0.0)
+        WX_STYLE_RESET_CSS_NODE(borderBottomWidth, border[CSS_BOTTOM], 0.0)
+        
+        // padding
+        WX_STYLE_RESET_CSS_NODE_ALL_DIRECTION(padding, padding, 0.0)
+        WX_STYLE_RESET_CSS_NODE(paddingTop, padding[CSS_TOP], 0.0)
+        WX_STYLE_RESET_CSS_NODE(paddingLeft, padding[CSS_LEFT], 0.0)
+        WX_STYLE_RESET_CSS_NODE(paddingRight, padding[CSS_RIGHT], 0.0)
+        WX_STYLE_RESET_CSS_NODE(paddingBottom, padding[CSS_BOTTOM], 0.0)
+    }
+   
+//#else
+    else
+    {
+        if (styles.count<=0) {
+            return;
+        }
+        
+        WX_FLEX_STYLE_RESET_CSS_NODE(flex, @0.0)
+        WX_FLEX_STYLE_RESET_CSS_NODE(flexDirection, @(CSS_FLEX_DIRECTION_COLUMN))
+        WX_FLEX_STYLE_RESET_CSS_NODE(alignItems, @(CSS_ALIGN_STRETCH))
+        WX_FLEX_STYLE_RESET_CSS_NODE(alignSelf, @(CSS_ALIGN_AUTO))
+        WX_FLEX_STYLE_RESET_CSS_NODE(flexWrap, @(CSS_NOWRAP))
+        WX_FLEX_STYLE_RESET_CSS_NODE(justifyContent, @(CSS_JUSTIFY_FLEX_START))
+        
+        // position
+        WX_FLEX_STYLE_RESET_CSS_NODE(position, @(CSS_POSITION_RELATIVE))
+        WX_FLEX_STYLE_RESET_CSS_NODE(top, @(CSS_UNDEFINED))
+        WX_FLEX_STYLE_RESET_CSS_NODE(left, @(CSS_UNDEFINED))
+        WX_FLEX_STYLE_RESET_CSS_NODE(right, @(CSS_UNDEFINED))
+        WX_FLEX_STYLE_RESET_CSS_NODE(bottom, @(CSS_UNDEFINED))
+        
+        // dimension
+        WX_FLEX_STYLE_RESET_CSS_NODE(width, @(CSS_UNDEFINED))
+        WX_FLEX_STYLE_RESET_CSS_NODE(height, @(CSS_UNDEFINED))
+        WX_FLEX_STYLE_RESET_CSS_NODE(minWidth, @(CSS_UNDEFINED))
+        WX_FLEX_STYLE_RESET_CSS_NODE(minHeight, @(CSS_UNDEFINED))
+        WX_FLEX_STYLE_RESET_CSS_NODE(maxWidth, @(CSS_UNDEFINED))
+        WX_FLEX_STYLE_RESET_CSS_NODE(maxHeight, @(CSS_UNDEFINED))
+        
+        // margin
+        WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(margin
+                                                         ,marginTop
+                                                         ,marginLeft
+                                                         ,marginRight
+                                                         ,marginBottom
+                                                         , @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(marginTop, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(marginLeft, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(marginRight, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(marginBottom, @(0.0))
+        
+        // border
+        WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(borderWidth
+                                                         , borderTopWidth
+                                                         , borderLeftWidth
+                                                         , borderRightWidth
+                                                         , borderBottomWidth
+                                                         , @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(borderTopWidth, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(borderLeftWidth, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(borderRightWidth, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(borderBottomWidth, @(0.0))
+        
+        // padding
+        WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(padding
+                                                         , paddingTop
+                                                         , paddingLeft
+                                                         , paddingRight
+                                                         , paddingBottom
+                                                         , @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(paddingTop, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(paddingLeft, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(paddingRight, @(0.0))
+        WX_FLEX_STYLE_RESET_CSS_NODE(paddingBottom, @(0.0))
+    }
+    
+    
+//#endif
+}
+
+#pragma mark CSS Node Override
+
+//#ifndef USE_FLEX
+#if defined __cplusplus
+extern "C" {
+#endif
+static void cssNodePrint(void *context)
+{
+    WXComponent *component = (__bridge WXComponent *)context;
+    // TODO:
+    printf("%s:%s ", component.ref.UTF8String, component->_type.UTF8String);
+}
+
+static css_node_t * cssNodeGetChild(void *context, int i)
+{
+    WXComponent *component = (__bridge WXComponent *)context;
+    NSArray *subcomponents = component->_subcomponents;
+    for (int j = 0; j <= i && j < subcomponents.count; j++) {
+        WXComponent *child = subcomponents[j];
+        if (!child->_isNeedJoinLayoutSystem) {
+            i++;
+        }
+    }
+    
+    if(i >= 0 && i < subcomponents.count){
+        WXComponent *child = subcomponents[i];
+//        WXLogInfo(@"FlexLayout -- P:%@ -> C:%@",component,(__bridge WXComponent *)child->_cssNode->context);
+        return child->_cssNode;
+    }
+    
+    WXAssert(NO, @"Can not find component:%@'s css node child at index: %ld, totalCount:%ld", component, i, subcomponents.count);
+    return NULL;
+}
+
+static bool cssNodeIsDirty(void *context)
+{
+    WXAssertComponentThread();
+    
+    WXComponent *component = (__bridge WXComponent *)context;
+    BOOL needsLayout = [component needsLayout];
+    
+    return needsLayout;
+}
+    
+static css_dim_t cssNodeMeasure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode)
+{
+    WXComponent *component = (__bridge WXComponent *)context;
+    CGSize (^measureBlock)(CGSize) = [component measureBlock];
+    
+    if (!measureBlock) {
+        return (css_dim_t){NAN, NAN};
+    }
+    
+    CGSize constrainedSize = CGSizeMake(width, height);
+    CGSize resultSize = measureBlock(constrainedSize);
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> measureblock %@, resultSize:%@",
+          component.type,
+          NSStringFromCGSize(resultSize)
+          );
+#endif
+    
+    return (css_dim_t){(float)resultSize.width, (float)resultSize.height};
+}
+#if defined __cplusplus
+};
+#endif
+
+//#else
+
+static WeexCore::WXCoreSize flexCssNodeMeasure(WeexCore::WXCoreLayoutNode *node, float width, WeexCore::MeasureMode widthMeasureMode,float height, WeexCore::MeasureMode heightMeasureMode){
+    
+    if (node->getContext() == nullptr) { //为空
+        return WeexCore::WXCoreSize();
+    }
+    WXComponent *component = (__bridge WXComponent *)(node->getContext());
+    
+    if (![component respondsToSelector:@selector(measureBlock)]) {
+        return WeexCore::WXCoreSize();
+    }
+    
+    CGSize (^measureBlock)(CGSize) = [component measureBlock];
+    
+    if (!measureBlock) {
+        return WeexCore::WXCoreSize();
+    }
+    
+    CGSize constrainedSize = CGSizeMake(width, height);
+    CGSize resultSize = measureBlock(constrainedSize);
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> measureblock %@, resultSize:%@",
+          component.type,
+          NSStringFromCGSize(resultSize)
+          );
+#endif
+    WeexCore::WXCoreSize size;
+    size.height=(float)resultSize.height;
+    size.width=(float)resultSize.width;
+    return size;
+}
+
+-(WeexCore::WXCorePositionType)fxPositionType:(id)value
+{
+    if([value isKindOfClass:[NSString class]]){
+        if ([value isEqualToString:@"absolute"]) {
+            return WeexCore::kAbsolute;
+        } else if ([value isEqualToString:@"relative"]) {
+            return WeexCore::kRelative;
+        } else if ([value isEqualToString:@"fixed"]) {
+            return WeexCore::kFixed;
+        } else if ([value isEqualToString:@"sticky"]) {
+            return WeexCore::kRelative;
+        }
+    }
+    return WeexCore::kRelative;
+}
+
+- (WeexCore::WXCoreFlexDirection)fxFlexDirection:(id)value
+{
+    if([value isKindOfClass:[NSString class]]){
+        if ([value isEqualToString:@"column"]) {
+            return WeexCore::kFlexDirectionColumn;
+        } else if ([value isEqualToString:@"column-reverse"]) {
+            return WeexCore::kFlexDirectionColumnReverse;
+        } else if ([value isEqualToString:@"row"]) {
+            return WeexCore::kFlexDirectionRow;
+        } else if ([value isEqualToString:@"row-reverse"]) {
+            return WeexCore::kFlexDirectionRowReverse;
+        }
+    }
+    return WeexCore::kFlexDirectionColumn;
+}
+
+//TODO
+- (WeexCore::WXCoreAlignItems)fxAlign:(id)value
+{
+    if([value isKindOfClass:[NSString class]]){
+        if ([value isEqualToString:@"stretch"]) {
+            return WeexCore::kAlignItemsStretch;
+        } else if ([value isEqualToString:@"flex-start"]) {
+            return WeexCore::kAlignItemsFlexStart;
+        } else if ([value isEqualToString:@"flex-end"]) {
+            return WeexCore::kAlignItemsFlexEnd;
+        } else if ([value isEqualToString:@"center"]) {
+            return WeexCore::kAlignItemsCenter;
+            //return WXCoreFlexLayout::WXCore_AlignItems_Center;
+        } else if ([value isEqualToString:@"auto"]) {
+//            return YGAlignAuto;
+        } else if ([value isEqualToString:@"baseline"]) {
+//            return YGAlignBaseline;
+        }
+    }
+    
+    return WeexCore::kAlignItemsStretch;
+}
+
+- (WeexCore::WXCoreAlignSelf)fxAlignSelf:(id)value
+{
+    if([value isKindOfClass:[NSString class]]){
+        if ([value isEqualToString:@"stretch"]) {
+            return WeexCore::kAlignSelfStretch;
+        } else if ([value isEqualToString:@"flex-start"]) {
+            return WeexCore::kAlignSelfFlexStart;
+        } else if ([value isEqualToString:@"flex-end"]) {
+            return WeexCore::kAlignSelfFlexEnd;
+        } else if ([value isEqualToString:@"center"]) {
+            return WeexCore::kAlignSelfCenter;
+        } else if ([value isEqualToString:@"auto"]) {
+            return WeexCore::kAlignSelfAuto;
+        } else if ([value isEqualToString:@"baseline"]) {
+            //            return YGAlignBaseline;
+        }
+    }
+    
+    return WeexCore::kAlignSelfStretch;
+}
+
+- (WeexCore::WXCoreFlexWrap)fxWrap:(id)value
+{
+    if([value isKindOfClass:[NSString class]]) {
+        if ([value isEqualToString:@"nowrap"]) {
+            return WeexCore::kNoWrap;
+        } else if ([value isEqualToString:@"wrap"]) {
+            return WeexCore::kWrap;
+        } else if ([value isEqualToString:@"wrap-reverse"]) {
+            return WeexCore::kWrapReverse;
+        }
+    }
+    return WeexCore::kNoWrap;
+}
+
+- (WeexCore::WXCoreJustifyContent)fxJustify:(id)value
+{
+    if([value isKindOfClass:[NSString class]]){
+        if ([value isEqualToString:@"flex-start"]) {
+            return WeexCore::kJustifyFlexStart;
+        } else if ([value isEqualToString:@"center"]) {
+            return WeexCore::kJustifyCenter;
+        } else if ([value isEqualToString:@"flex-end"]) {
+            return WeexCore::kJustifyFlexEnd;
+        } else if ([value isEqualToString:@"space-between"]) {
+            return WeexCore::kJustifySpaceBetween;
+        } else if ([value isEqualToString:@"space-around"]) {
+            return WeexCore::kJustifySpaceAround;
+        }
+    }
+    return WeexCore::kJustifyFlexStart;
+}
+
+
+- (NSInteger) getActualNodeIndex:(WXComponent*)subcomponent atIndex:(NSInteger) index
+{
+    NSInteger actualIndex = 0; //实际除去不需要布局的subComponent,此时所在的正确位置
+    for (WXComponent *child in _subcomponents) {
+        if ([child.ref isEqualToString:subcomponent.ref]) {
+            break;
+        }
+        if (child->_isNeedJoinLayoutSystem) {
+            actualIndex ++;
+        }
+    }
+    return actualIndex;
+}
+
+- (void)_insertChildCssNode:(WXComponent*)subcomponent atIndex:(NSInteger)index
+{
+    self.flexCssNode->addChildAt(subcomponent.flexCssNode, (uint32_t)index);
+}
+
+- (void)_rmChildCssNode:(WXComponent *)subcomponent
+{
+    self.flexCssNode->removeChild(subcomponent->_flexCssNode);
+#ifdef DEBUG
+    WXLogDebug(@"flexLayout -> ref:%@ ,flexCssNode->removeChild ,childRef:%@",self.ref,subcomponent.ref);
+#endif
+}
+
+
++ (void) setUseFlex:(BOOL)useFlex
+{
+    sUseFlex =useFlex;
+}
+
+
++ (BOOL) isUseFlex
+{
+    return sUseFlex;
+}
+
+//#endif
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h b/ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h
new file mode 100644
index 0000000..26fe8a3
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h
@@ -0,0 +1,107 @@
+#ifdef __cplusplus
+
+#ifndef WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUM_H
+#define WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUM_H
+
+namespace WeexCore {
+
+  /**
+   * MainAxis direction
+   */
+  enum WXCoreFlexDirection {
+    kFlexDirectionColumn,
+    kFlexDirectionColumnReverse,
+    kFlexDirectionRow,
+    kFlexDirectionRowReverse,
+  };
+
+  /**
+   * Controls the position of the element on the MainAxis
+   */
+  enum WXCoreJustifyContent {
+    kJustifyFlexStart,
+    kJustifyCenter,
+    kJustifyFlexEnd,
+    kJustifySpaceBetween,
+    kJustifySpaceAround,
+  };
+
+  /**
+   * Controls the position of the element on the CrossAxis and whether Stretch
+   */
+  enum WXCoreAlignItems {
+    kAlignItemsFlexStart,
+    kAlignItemsCenter,
+    kAlignItemsFlexEnd,
+    kAlignItemsStretch,
+  };
+
+  /**
+   * Controls the count of flexlines
+   */
+  enum WXCoreFlexWrap {
+    kNoWrap,
+    kWrap,
+    kWrapReverse,
+  };
+
+  /**
+   * The align-self will overrides the align-items specified by the Flex container.
+   * The two attributes have the same range of values.
+   */
+  enum WXCoreAlignSelf {
+    kAlignSelfAuto = -1,
+    kAlignSelfFlexStart = kAlignItemsFlexStart,
+    kAlignSelfCenter = kAlignItemsCenter,
+    kAlignSelfFlexEnd = kAlignItemsFlexEnd,
+    kAlignSelfStretch = kAlignItemsStretch,
+  };
+
+  enum WXCorePositionType {
+    kRelative,
+    kAbsolute,
+    kFixed,
+    kSticky = kRelative
+  };
+
+  enum WXCorePositionEdge {
+    kPositionEdgeTop,
+    kPositionEdgeBottom,
+    kPositionEdgeLeft,
+    kPositionEdgeRight,
+  };
+
+  enum WXCoreMarginEdge {
+    kMarginALL,
+    kMarginTop,
+    kMarginBottom,
+    kMarginLeft,
+    kMarginRight,
+  };
+
+  enum WXCorePaddingEdge {
+    kPaddingALL,
+    kPaddingTop,
+    kPaddingBottom,
+    kPaddingLeft,
+    kPaddingRight,
+  };
+
+  enum WXCoreBorderWidthEdge {
+    kBorderWidthALL,
+    kBorderWidthTop,
+    kBorderWidthBottom,
+    kBorderWidthLeft,
+    kBorderWidthRight,
+  };
+
+  enum WXCoreEdge{
+    kTop,
+    kRight,
+    kBottom,
+    kLeft,
+  };
+
+}
+#endif //WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUM_H
+#endif
\ No newline at end of file