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

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

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/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