You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ji...@apache.org on 2017/01/24 08:18:32 UTC

[17/50] [abbrv] incubator-weex git commit: + [ios] iOS init.

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/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
new file mode 100644
index 0000000..030b5d5
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.m
@@ -0,0 +1,143 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#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, 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) {
+        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)layoutDidFinish
+{
+    if ([self isViewLoaded]) {
+        
+        [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)viewDidLoad
+{
+     _initFinished = YES;
+    [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) return;
+    [self fireEvent:@"refresh" params:nil];
+}
+
+- (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;
+    }
+}
+
+- (void)removeEvent:(NSString *)evetName
+{
+    if ([evetName isEqualToString:@"refresh"]) {
+        _refreshEvent = NO;
+    }
+}
+
+- (void)setDisplay
+{
+    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
+    if (scrollerProtocol == nil || !_initFinished)
+        return;
+    
+    CGPoint offset = [scrollerProtocol contentOffset];
+    if (_displayState) {
+        offset.y = -self.calculatedFrame.size.height;
+        [_indicator start];
+    }
+    else {
+        offset.y = 0;
+        [_indicator stop];
+    }
+    [scrollerProtocol setContentOffset:offset animated:YES];
+}
+
+- (void)setFrame:(CGRect)frame
+{
+    CGRect rect = frame;
+    rect.origin.y = 0 - frame.size.height;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/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
new file mode 100644
index 0000000..d256567
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.h
@@ -0,0 +1,25 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXScrollerProtocol.h"
+#import "WXComponent.h"
+
+@interface WXScrollerComponent : WXComponent <WXScrollerProtocol, UIScrollViewDelegate>
+
+@property (nonatomic, copy) void (^onScroll)(UIScrollView *);
+
+@property (nonatomic, assign) NSUInteger loadmoreretry;
+
+@property (nonatomic, assign) CGSize contentSize;
+
+@property (nonatomic, readonly, assign) css_node_t *scrollerCSSNode;
+
+- (NSUInteger)childrenCountForScrollerLayout;
+
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/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
new file mode 100644
index 0000000..7ebf492
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.m
@@ -0,0 +1,579 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#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"
+
+@interface WXScrollToTarget : NSObject
+
+@property (nonatomic, weak)   WXComponent *target;
+@property (nonatomic, assign) BOOL hasAppear;
+
+@end
+
+@implementation WXScrollToTarget
+
+@end
+
+@interface WXScrollView_new : UIScrollView
+@end
+@implementation WXScrollView_new
+@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;
+    CGFloat _loadMoreOffset;
+    CGFloat _previousLoadMoreContentHeight;
+    CGPoint _lastContentOffset;
+    
+    // vertical & horizontal
+    WXScrollDirection _scrollDirection;
+    // left & right & up & down
+    NSString *_direction;
+    BOOL _showScrollBar;
+
+    css_node_t *_scrollerCSSNode;
+}
+
+-(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];
+        
+        _scrollDirection = attributes[@"scrollDirection"] ? [WXConvert WXScrollDirection:attributes[@"scrollDirection"]] : WXScrollDirectionVertical;
+        _showScrollBar = attributes[@"showScrollbar"] ? [WXConvert BOOL:attributes[@"showScrollbar"]] : YES;
+        _loadMoreOffset = attributes[@"loadmoreoffset"] ? [WXConvert CGFloat:attributes[@"loadmoreoffset"]] : 0;
+        _loadmoreretry = attributes[@"loadmoreretry"] ? [WXConvert NSUInteger:attributes[@"loadmoreretry"]] : 0;
+        _listenLoadMore = [events containsObject:@"loadmore"];
+
+        
+        _scrollerCSSNode = new_css_node();
+    }
+    
+    return self;
+}
+
+- (void)viewWillUnload
+{
+    ((UIScrollView *)(self.view)).delegate = nil;
+}
+
+- (void)dealloc
+{
+    [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[@"loadmoreoffset"]) {
+        _loadMoreOffset = [WXConvert CGFloat:attributes[@"loadmoreoffset"]];
+    }
+    
+    if (attributes[@"loadmoreretry"]) {
+        NSUInteger loadmoreretry = [WXConvert NSUInteger:attributes[@"loadmoreretry"]];
+        if (loadmoreretry != _loadmoreretry) {
+            _previousLoadMoreContentHeight = 0;
+        }
+        _loadmoreretry = loadmoreretry;
+    }
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"loadmore"]) {
+        _listenLoadMore = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"loadmore"]) {
+        _listenLoadMore = NO;
+    }
+}
+
+- (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];
+    }
+}
+
+- (css_node_t *)scrollerCSSNode
+{
+    return _scrollerCSSNode;
+}
+
+- (void)setContentSize:(CGSize)size
+{
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    scrollView.contentSize = size;
+}
+
+- (CGSize)contentSize
+{
+    return ((UIScrollView *)self.view).contentSize;
+}
+
+/**
+ * add response to scrollTo
+ **/
+- (void)addScrollToListener:(WXComponent *)target
+{
+    BOOL has = NO;
+    for (WXScrollToTarget *targetData in self.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];
+    }
+}
+
+/**
+ * remove response to scrollTo
+ **/
+- (void)removeScrollToListener:(WXComponent *)target
+{
+    WXScrollToTarget *targetData = nil;
+    for (WXScrollToTarget *targetData in self.listenerArray) {
+        if (targetData.target == target) {
+            break;
+        }
+    }
+    if(targetData){
+        [self.listenerArray removeObject:targetData];
+    }
+}
+
+- (UIView *)loadView
+{
+    return [[UIScrollView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+    [self setContentSize:_contentSize];
+    UIScrollView* scrollView = (UIScrollView *)self.view;
+    scrollView.scrollEnabled = YES;
+    scrollView.delegate = self;
+    scrollView.exclusiveTouch = YES;
+    scrollView.autoresizesSubviews = NO;
+    scrollView.clipsToBounds = YES;
+    scrollView.showsVerticalScrollIndicator = _showScrollBar;
+    scrollView.showsHorizontalScrollIndicator = _showScrollBar;
+
+    if (self.ancestorScroller) {
+        scrollView.scrollsToTop = NO;
+    } else {
+        scrollView.scrollsToTop = YES;
+    }
+}
+
+- (void)scrollToTarget:(WXScrollToTarget *)target scrollRect:(CGRect)rect
+{
+    WXComponent *component = target.target;
+    CGFloat ctop = component.absolutePosition.y - self.absolutePosition.y;
+    CGFloat cbottom = ctop + CGRectGetHeight(component.calculatedFrame);
+    CGFloat cleft = component.absolutePosition.x - self.absolutePosition.x;
+    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) {
+                [component fireEvent:@"appear" params:_direction ? @{@"direction":_direction} : nil];
+
+            }
+        }
+    } else {
+        if(target.hasAppear && component){
+            target.hasAppear = NO;
+            if(component->_disappearEvent){
+                [component fireEvent:@"disappear" params:_direction ? @{@"direction":_direction} : nil];
+            }
+
+        }
+    }
+}
+#pragma mark -
+
+- (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";
+    } else if(_lastContentOffset.y > scrollView.contentOffset.y){
+        _direction = @"down";
+    } else if(_lastContentOffset.y < scrollView.contentOffset.y) {
+        _direction = @"up";
+    }
+    
+    _lastContentOffset = scrollView.contentOffset;
+    
+    // chekck sticky
+    [self adjustSticky];
+    [self handleLoadMore];
+    
+    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
+    for(WXScrollToTarget *target in self.listenerArray){
+        [self scrollToTarget:target scrollRect:scrollRect];
+    }
+    
+    if (self.onScroll) {
+        self.onScroll(scrollView);
+    }
+}
+
+- (void)layoutDidFinish
+{
+    if ([self isViewLoaded]) {
+        [self setContentSize:_contentSize];
+    }
+    [self adjustSticky];
+    [self handleAppear];
+    [_loadingComponent resizeFrame];
+}
+
+- (void)handleAppear
+{
+    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
+    for(WXScrollToTarget *target in self.listenerArray){
+        [self scrollToTarget:target scrollRect:scrollRect];
+    }
+}
+
+- (void)adjustSticky
+{
+    CGFloat scrollOffset = ((UIScrollView *)self.view).contentOffset.y;
+    for(WXComponent *component in self.stickyArray) {
+        if (isnan(component.absolutePosition.y)) {
+            continue;
+        }
+
+        if(component.supercomponent != self && component.view.superview != self.view) {
+            [component.view removeFromSuperview];
+            [self.view addSubview:component.view];
+        } else {
+            [self.view bringSubviewToFront:component.view];
+        }
+
+        CGFloat componentY = component.absolutePosition.y - self.absolutePosition.y;
+        BOOL needSticky = NO;
+
+        if (scrollOffset >= componentY) {
+            needSticky = YES;
+        } else {
+            // important: reset views' frame
+            component.view.frame = CGRectMake(component.absolutePosition.x - self.absolutePosition.x, componentY, component.calculatedFrame.size.width, component.calculatedFrame.size.height);
+        }
+
+        if (!needSticky) {
+            continue;
+        }
+
+        // The minimum Y sticky view can reach is its original position
+        CGFloat minY = component.absolutePosition.y - self.absolutePosition.y;
+        WXComponent *superComponent = (WXComponent *)(component.supercomponent);
+        CGFloat maxY = superComponent.absolutePosition.y - self.absolutePosition.y + superComponent.calculatedFrame.size.height - component.calculatedFrame.size.height;
+
+        CGFloat stickyY = scrollOffset;
+        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)addLoadMoreEvent
+{
+    _listenLoadMore = YES;
+}
+
+- (void)removeLoadMoreEvent
+{
+    _listenLoadMore = NO;
+}
+
+- (BOOL)isNeedLoadMore
+{
+    if (_loadMoreOffset >= 0.0) {
+        return _previousLoadMoreContentHeight != ((UIScrollView *)self.view).contentSize.height && ((UIScrollView *)self.view).contentSize.height - ((UIScrollView *)self.view).contentOffset.y -  self.view.frame.size.height <= _loadMoreOffset;
+    }
+    
+    return NO;
+}
+
+- (void)loadMore
+{
+    [self fireEvent:@"loadmore" params:nil];
+    _previousLoadMoreContentHeight = ((UIScrollView *)self.view).contentSize.height;
+}
+
+- (void)handleLoadMore
+{
+    if (_listenLoadMore && [self isNeedLoadMore]) {
+        [self loadMore];
+    }
+}
+
+- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset
+{
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    CGPoint contentOffset = scrollView.contentOffset;
+    
+    if (_scrollDirection == WXScrollDirectionHorizontal) {
+        CGFloat contentOffetX = component.absolutePosition.x - self.absolutePosition.x;
+        contentOffetX += offset * WXScreenResizeRadio();
+        
+        if (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.absolutePosition.y - self.absolutePosition.y;
+        contentOffetY += offset * WXScreenResizeRadio();
+        
+        if (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:YES];
+}
+
+#pragma mark -
+#pragma mark refresh
+
+- (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;
+        }
+}
+
+- (void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
+{
+    //refresh
+        if (_refreshComponent && scrollView.contentOffset.y < _refreshComponent.calculatedFrame.origin.y) {
+    
+            [_refreshComponent refresh];
+        }
+    
+    //loading
+        if (_loadingComponent &&
+            scrollView.contentOffset.y + scrollView.frame.size.height > _loadingComponent.view.frame.origin.y + _loadingComponent.calculatedFrame.size.height) {
+    
+            [_loadingComponent loading];
+        }
+}
+
+- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
+{
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    [scrollView setContentOffset:contentOffset animated:animated];
+}
+
+- (CGPoint)contentOffset
+{
+    CGPoint rtv = CGPointZero;
+    UIScrollView *scrollView = (UIScrollView *)self.view;
+    if (scrollView) {
+        rtv = scrollView.contentOffset;
+    }
+    return rtv;
+}
+
+- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
+{
+    UIEdgeInsets inset = [scrollView contentInset];
+    if ([_refreshComponent displayState]) {
+        inset.top = _refreshComponent.calculatedFrame.size.height;
+    }
+    else {
+        inset.top = 0;
+    }
+    if ([_loadingComponent displayState]) {
+        inset.bottom = _loadingComponent.calculatedFrame.size.height;
+    }
+    else {
+        inset.bottom = 0;
+    }
+
+    [scrollView setContentInset:inset];
+}
+
+- (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];
+}
+
+#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);
+//        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 (_scrollDirection == WXScrollDirectionVertical && size.height > self.cssNode->layout.dimensions[CSS_HEIGHT] && superAbsolutePosition.y + size.height <= self.weexInstance.rootView.frame.size.height) {
+//            // vertical frame
+//            self.cssNode->layout.dimensions[CSS_HEIGHT] = size.height;
+//        } else if (_scrollDirection == WXScrollDirectionHorizontal && size.width > self.cssNode->layout.dimensions[CSS_WIDTH] && superAbsolutePosition.x + size.width <= self.weexInstance.rootView.frame.size.width) {
+//            // horizontal frame
+//            self.cssNode->layout.dimensions[CSS_WIDTH] = size.width;
+//        } else
+        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/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXSliderComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXSliderComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXSliderComponent.h
new file mode 100644
index 0000000..6a223e3
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXSliderComponent.h
@@ -0,0 +1,18 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import <Foundation/Foundation.h>
+#import "WXComponent.h"
+
+@class WXIndicatorView;
+
+@interface WXSliderComponent : WXComponent
+
+- (void)setIndicatorView:(WXIndicatorView *)indicatorView;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXSliderComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXSliderComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXSliderComponent.m
new file mode 100644
index 0000000..b81f099
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXSliderComponent.m
@@ -0,0 +1,446 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXSliderComponent.h"
+#import "WXIndicatorComponent.h"
+#import "NSTimer+Weex.h"
+#import "WXSDKManager.h"
+#import "WXUtility.h"
+
+@class WXSliderView;
+@class WXIndicatorView;
+
+@protocol WXSliderViewDelegate <UIScrollViewDelegate>
+
+- (void)sliderView:(WXSliderView *)sliderView didScrollToItemAtIndex:(NSInteger)index;
+
+@end
+
+@interface WXSliderView : UIView <UIScrollViewDelegate>
+
+@property (nonatomic, strong) WXIndicatorView *indicator;
+@property (nonatomic, weak) id<WXSliderViewDelegate> delegate;
+
+@property (nonatomic, strong) UIScrollView *scrollView;
+@property (nonatomic, strong) NSMutableArray *itemViews;
+@property (nonatomic, assign) NSInteger currentIndex;
+
+- (UIScrollView *)scrollView;
+- (void)insertItemView:(UIView *)view atIndex:(NSInteger)index;
+- (void)removeItemView:(UIView *)view;
+- (void)scroll2ItemView:(NSInteger)index animated:(BOOL)animated;
+- (void)loadData;
+
+@end
+
+@implementation WXSliderView
+
+- (id)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        UIView *tempBackGround = [[UIView alloc] init];
+        tempBackGround.backgroundColor = [UIColor clearColor];
+        [self addSubview:tempBackGround];
+        
+        _scrollView = [[UIScrollView alloc] init];
+        _scrollView.backgroundColor = [UIColor clearColor];
+        _scrollView.delegate = self;
+        _scrollView.showsHorizontalScrollIndicator = NO;
+        _scrollView.showsVerticalScrollIndicator = NO;
+        _scrollView.scrollsToTop = NO;
+        [self addSubview:_scrollView];
+        
+        _itemViews = [NSMutableArray array];
+    }
+    return self;
+}
+
+- (void)setIndicator:(WXIndicatorView *)indicator
+{
+    _indicator = indicator;
+    [_indicator setPointCount:self.itemViews.count];
+    [_indicator setCurrentPoint:_currentIndex];
+}
+
+- (void)setCurrentIndex:(NSInteger)currentIndex
+{
+    if (_currentIndex == currentIndex) return;
+    
+    _currentIndex = currentIndex;
+    [self.indicator setCurrentPoint:_currentIndex];
+    
+    [self _resortItemViews];
+    [self _resetItemFrames];
+    [self _scroll2Center];
+    [self setNeedsLayout];
+    
+    if (self.delegate && [self.delegate respondsToSelector:@selector(sliderView:didScrollToItemAtIndex:)]) {
+        [self.delegate sliderView:self didScrollToItemAtIndex:_currentIndex];
+    }
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    
+    self.scrollView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
+    self.scrollView.contentSize = CGSizeMake(self.itemViews.count * self.frame.size.width, self.frame.size.height);
+}
+
+#pragma mark Public Methods
+
+- (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.indicator setPointCount:self.itemViews.count];
+    [self setNeedsLayout];
+}
+
+- (void)removeItemView:(UIView *)view
+{
+    if ([self.itemViews containsObject:view]) {
+        [self.itemViews removeObject:view];
+    }
+    
+    if ([self.scrollView.subviews containsObject:view]) {
+        [view removeFromSuperview];
+    }
+    
+    [self.indicator setPointCount:self.itemViews.count];
+    [self setNeedsLayout];
+}
+
+- (void)scroll2ItemView:(NSInteger)index animated:(BOOL)animated
+{
+    UIView *itemView = nil;
+    for (itemView in self.itemViews) {
+        if (itemView.tag == index){
+            break;
+        }
+    }
+    
+    if (itemView) {
+        [self.scrollView setContentOffset:itemView.frame.origin animated:YES];
+    }
+}
+
+- (void)loadData
+{
+    self.scrollView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
+    self.scrollView.contentSize = CGSizeMake(self.itemViews.count * self.frame.size.width, self.frame.size.height);
+    
+    [self _resortItemViews];
+    [self _scroll2Center];
+    [self setNeedsLayout];
+}
+
+#pragma mark Private Methods
+
+- (void)_resortItemViews
+{
+    if (self.itemViews.count <= 2) return;
+    
+    NSInteger center = [self _centerItemIndex];
+    NSInteger index = 0;
+    if (self.currentIndex > center) {
+        index = self.currentIndex - center;
+    } else {
+        index = self.currentIndex + self.itemViews.count - center;
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    [self.itemViews sortUsingComparator:^NSComparisonResult(UIView *obj1, UIView *obj2) {
+        NSInteger tag1 = obj1.tag >= index ? obj1.tag - index : obj1.tag + weakSelf.itemViews.count - index;
+        NSInteger tag2 = obj2.tag >= index ? obj2.tag - index : obj2.tag + weakSelf.itemViews.count - index;
+        
+        if (tag1 > tag2) {
+            return 1;
+        } else if (tag1 < tag2) {
+            return -1;
+        } else {
+            return 0;
+        }
+    }];
+}
+
+- (void)_resetItemFrames
+{
+    CGFloat xOffset = 0; CGRect frame = CGRectZero;
+    for(UIView *itemView in self.itemViews){
+        frame = itemView.frame;
+        frame.origin.x = xOffset;
+        frame.size.width = self.frame.size.width;
+        itemView.frame = frame;
+        xOffset += frame.size.width;
+    }
+}
+
+- (NSInteger)_centerItemIndex
+{
+    if (self.itemViews.count > 2) {
+        return self.itemViews.count % 2 ? self.itemViews.count / 2 : self.itemViews.count / 2 - 1;
+    }
+    return 0;
+}
+
+- (void)_scroll2Center
+{
+    if (self.itemViews.count > 2) {
+        UIView *itemView = [self.itemViews objectAtIndex:[self _centerItemIndex]];
+        [self.scrollView scrollRectToVisible:itemView.frame animated:NO];
+    }
+}
+
+- (BOOL)_isItemViewVisiable:(UIView *)itemView
+{
+    CGRect itemFrame = itemView.frame;
+    
+    CGFloat vx = self.scrollView.contentInset.left + self.scrollView.contentOffset.x;
+    CGFloat vy = self.scrollView.contentInset.top + self.scrollView.contentOffset.y;
+    CGFloat vw = self.scrollView.frame.size.width - self.scrollView.contentInset.left - self.scrollView.contentInset.right;
+    CGFloat vh = self.scrollView.frame.size.height - self.scrollView.contentInset.top - self.scrollView.contentInset.bottom;
+    CGRect visiableRect = CGRectMake(vx - 2, vy, vw + 4, vh);
+    
+    CGRect intersection = CGRectIntersection(visiableRect, itemFrame);
+    if (intersection.size.width > visiableRect.size.width - 10) {
+        return YES;
+    } else {
+        return NO;
+    }
+}
+
+#pragma mark ScrollView Delegate
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView
+{
+    UIView *itemView = nil;
+    for (itemView in self.itemViews) {
+        if ([self _isItemViewVisiable:itemView]) {
+            break;
+        }
+    }
+    
+    if (itemView) {
+        self.currentIndex = itemView.tag;
+    }
+}
+
+- (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];
+    }
+}
+
+@end
+
+@interface WXSliderComponent ()<WXSliderViewDelegate>
+
+@property (nonatomic, strong) WXSliderView *sliderView;
+@property (nonatomic, strong) NSTimer *autoTimer;
+@property (nonatomic, assign) NSInteger currentIndex;
+@property (nonatomic, assign) BOOL  autoPlay;
+@property (nonatomic, assign) BOOL  sliderChangeEvent;
+@property (nonatomic, strong) NSMutableArray *childrenView;
+
+@end
+
+@implementation WXSliderComponent
+
+- (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;
+        _childrenView = [NSMutableArray new];
+        
+        if (attributes[@"autoPlay"]) {
+            _autoPlay = [attributes[@"autoPlay"] boolValue];
+        }
+        
+        self.cssNode->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+    }
+    return self;
+}
+
+- (UIView *)loadView
+{
+    return [[WXSliderView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    
+    _sliderView = (WXSliderView *)self.view;
+    _sliderView.delegate = self;
+    _sliderView.scrollView.pagingEnabled = YES;
+    _sliderView.exclusiveTouch = YES;
+    
+    if (_autoPlay) {
+        [self _startAutoPlayTimer];
+    } else {
+        [self _stopAutoPlayTimer];
+    }
+}
+
+- (void)viewDidUnload
+{
+    [_childrenView removeAllObjects];
+}
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    UIView *view = subcomponent.view;
+    
+    if(index < 0) {
+        [self.childrenView addObject:view];
+    }
+    else {
+        [self.childrenView insertObject:view atIndex:index];
+    }
+    
+    WXSliderView *sliderView = (WXSliderView *)self.view;
+    if ([view isKindOfClass:[WXIndicatorView class]]) {
+        [sliderView addSubview:view];
+        return;
+    }
+    
+    if (index == -1) {
+        [sliderView 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++;
+            }
+        }
+        [sliderView insertItemView:view atIndex:index - offset];
+    }
+    [sliderView loadData];
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"autoPlay"]) {
+        _autoPlay = [attributes[@"autoPlay"] boolValue];
+        if (_autoPlay) {
+            [self _startAutoPlayTimer];
+        } else {
+            [self _stopAutoPlayTimer];
+        }
+    }
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"change"]) {
+        _sliderChangeEvent = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"change"]) {
+        _sliderChangeEvent = NO;
+    }
+}
+
+#pragma mark Public Methods
+
+-(void)setIndicatorView:(WXIndicatorView *)indicatorView
+{
+    NSAssert(_sliderView, @"");
+    [_sliderView setIndicator:indicatorView];
+}
+
+#pragma mark Private Methods
+
+- (void)_startAutoPlayTimer
+{
+    if (!self.autoTimer || ![self.autoTimer isValid]) {
+        __weak __typeof__(self) weakSelf = self;
+        self.autoTimer = [NSTimer wx_scheduledTimerWithTimeInterval:3 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
+{
+    WXSliderView *sliderView = (WXSliderView *)self.view;
+    if (self.currentIndex < self.childrenView.count - 1) {
+        self.currentIndex ++;
+        [sliderView scroll2ItemView:self.currentIndex animated:YES];
+    } else {
+        self.currentIndex = 0;
+        [sliderView scroll2ItemView:self.currentIndex animated:YES];
+    }
+}
+
+- (void)sliderView:(WXSliderView *)sliderView didScrollToItemAtIndex:(NSInteger)index
+{
+    self.currentIndex = index;
+    
+    if (_sliderChangeEvent) {
+        [self fireEvent:@"change" params:@{@"index":@(index)}];
+    }
+}
+
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
+{
+    [self _stopAutoPlayTimer];
+}
+
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
+{
+    if (_autoPlay) {
+        [self _startAutoPlayTimer];
+    }
+}
+
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.h
new file mode 100644
index 0000000..f3f0634
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXSwitchComponent : WXComponent
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/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
new file mode 100644
index 0000000..e874a13
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXSwitchComponent.m
@@ -0,0 +1,89 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXSwitchComponent.h"
+#import "WXConvert.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;
+
+@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;
+        
+        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 setOn:_checked animated:YES];
+    [_switchView setEnabled:!_disabled];
+    [_switchView addTarget:self action:@selector(checkChanged) forControlEvents:UIControlEventValueChanged];
+}
+
+- (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];
+    }
+}
+
+- (void)checkChanged
+{
+    if (_changeEvent) {
+        [self fireEvent:@"change" params:@{@"value":@([_switchView isOn])}];
+    }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.h
new file mode 100644
index 0000000..72dd3ab
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXTextComponent : WXComponent
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/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
new file mode 100644
index 0000000..5417bac
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.m
@@ -0,0 +1,365 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXTextComponent.h"
+#import "WXComponent_internal.h"
+#import "WXLayer.h"
+#import "WXUtility.h"
+#import "WXConvert.h"
+
+@interface WXText : UIView
+
+@property (nonatomic, strong) NSTextStorage *textStorage;
+
+@end
+
+@implementation WXText
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    if ((self = [super initWithFrame:frame])) {
+        self.isAccessibilityElement = YES;
+        self.accessibilityTraits |= UIAccessibilityTraitStaticText;
+        
+        self.opaque = NO;
+        self.contentMode = UIViewContentModeRedraw;
+    }
+    return self;
+}
+
++ (Class)layerClass
+{
+    return [WXLayer class];
+}
+
+- (UIImage *)drawTextWithBounds:(CGRect)bounds padding:(UIEdgeInsets)padding
+{
+    if (bounds.size.width <=0 || bounds.size.height <= 0) {
+        return nil;
+    }
+    UIGraphicsBeginImageContextWithOptions(bounds.size, self.layer.opaque, WXScreenScale());
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    
+    if ([self.wx_component _needsDrawBorder]) {
+        [self.wx_component _drawBorderWithContext:context size:bounds.size];
+    }
+    
+    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];
+    
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+    
+    UIGraphicsEndImageContext();
+    
+    return image;
+}
+
+- (NSString *)description
+{
+    NSString *superDescription = super.description;
+    NSRange semicolonRange = [superDescription rangeOfString:@";"];
+    NSString *replacement = [NSString stringWithFormat:@"; text: %@; frame:%f,%f,%f,%f", _textStorage.string, self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height];
+    return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement];
+}
+
+- (NSString *)accessibilityValue
+{
+    return _textStorage.string;
+}
+
+@end
+
+@implementation WXTextComponent
+{
+    UIEdgeInsets _border;
+    UIEdgeInsets _padding;
+    NSTextStorage *_textStorage;
+    CGFloat _textStorageWidth;
+    
+    NSString *_text;
+    UIColor *_color;
+    NSString *_fontFamily;
+    CGFloat _fontSize;
+    WXTextWeight _fontWeight;
+    WXTextStyle _fontStyle;
+    NSUInteger _lines;
+    NSTextAlignment _textAlign;
+    WXTextDecoration _textDecoration;
+    NSString *_textOverflow;
+}
+
+- (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) {
+        [self fillCSSStyles:styles];
+        [self fillAttributes:attributes];
+    }
+    
+    return self;
+}
+
+#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);
+
+- (void)fillCSSStyles:(NSDictionary *)styles
+{
+    WX_STYLE_FILL_TEXT(color, color, UIColor, NO)
+    WX_STYLE_FILL_TEXT(fontFamily, fontFamily, NSString, YES)
+    WX_STYLE_FILL_TEXT(fontSize, fontSize, WXPixelType, 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)
+    
+    UIEdgeInsets padding = UIEdgeInsetsMake(self.cssNode->style.padding[CSS_TOP] + self.cssNode->style.border[CSS_TOP], self.cssNode->style.padding[CSS_LEFT] + self.cssNode->style.border[CSS_LEFT], self.cssNode->style.padding[CSS_BOTTOM] + self.cssNode->style.border[CSS_BOTTOM], 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 = attributes[@"value"];
+    if (text) {
+        _text = [WXConvert NSString:text];
+        [self setNeedsRepaint];
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setNeedsRepaint
+{
+    _textStorage = nil;
+}
+
+#pragma mark - Subclass
+
+- (void)setNeedsLayout
+{
+    [super setNeedsLayout];
+}
+
+- (void)layoutDidFinish
+{
+    if ([self isViewLoaded]) {
+        ((WXText *)self.view).textStorage = _textStorage;
+        [self setNeedsDisplay];
+    }
+}
+
+- (void)viewDidLoad
+{
+    ((WXText *)self.view).textStorage = _textStorage;
+    [self setNeedsDisplay];
+}
+
+- (UIView *)loadView
+{
+    return [[WXText alloc] init];
+}
+
+- (WXDisplayBlock)displayBlock
+{
+    WXText *textView = ((WXText *)self.view);
+    return ^UIImage *(CGRect bounds, BOOL(^isCancelled)(void)) {
+        if (isCancelled()) {
+            return nil;
+        }
+        return [textView drawTextWithBounds:bounds padding:_padding];
+    };
+}
+
+- (CGSize (^)(CGSize))measureBlock
+{
+    __weak typeof(self) weakSelf = self;
+    return ^CGSize (CGSize constrainedSize) {
+        NSTextStorage *textStorage = [weakSelf textStorageWithWidth:constrainedSize.width];
+        
+        NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
+        NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
+        CGSize computedSize = [layoutManager usedRectForTextContainer:textContainer].size;
+        
+        //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.width = MAX(computedSize.height, weakSelf.cssNode->style.minDimensions[CSS_HEIGHT]);
+        }
+        
+        if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT])) {
+            computedSize.width = MIN(computedSize.height, weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT]);
+        }
+        
+        return (CGSize) {
+            WXCeilPixelValue(computedSize.width),
+            WXCeilPixelValue(computedSize.height)
+        };
+    };
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+    if (((WXText *)(self.view)).textStorage != _textStorage) {
+        ((WXText *)(self.view)).textStorage = _textStorage;
+        [self setNeedsDisplay];
+    }
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (((WXText *)(self.view)).textStorage != _textStorage) {
+        ((WXText *)(self.view)).textStorage = _textStorage;
+        [self setNeedsDisplay];
+    }
+}
+
+#pragma mark Text Building
+- (NSString *)text
+{
+    return _text;
+}
+
+- (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];
+    [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)];
+    }
+    if (_textAlign) {
+        
+        NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
+        paragraphStyle.alignment = _textAlign;
+        [attributedString addAttribute:NSParagraphStyleAttributeName
+                                 value:paragraphStyle
+                                 range:(NSRange){0, attributedString.length}];
+        
+    }
+    
+    return attributedString;
+}
+
+- (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;
+    
+    textContainer.lineBreakMode = NSLineBreakByClipping;
+    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)_calculatedFrameDidChange
+{
+    [super _calculatedFrameDidChange];
+    
+    CGFloat width = self.calculatedFrame.size.width - (_padding.left + _padding.right);
+    _textStorage = [self textStorageWithWidth:width];
+}
+
+- (void)_updateStylesOnComponentThread:(NSDictionary *)styles
+{
+    [super _updateStylesOnComponentThread:styles];
+    
+    [self fillCSSStyles:styles];
+    
+    if (!_textStorage) {
+        CGFloat width = self.calculatedFrame.size.width - (_padding.left + _padding.right);
+        _textStorage = [self textStorageWithWidth:width];
+    }
+}
+
+- (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes
+{
+    [super _updateAttributesOnComponentThread:attributes];
+    
+    [self fillAttributes:attributes];
+    
+    if (!_textStorage) {
+        CGFloat width = self.calculatedFrame.size.width - (_padding.left + _padding.right);
+        _textStorage = [self textStorageWithWidth:width];
+    }
+}
+
+#ifdef UITEST
+- (NSString *)description
+{
+    return super.description;
+}
+#endif
+
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXTextInputComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextInputComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXTextInputComponent.h
new file mode 100644
index 0000000..2371426
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextInputComponent.h
@@ -0,0 +1,14 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+#import "WXTextComponentProtocol.h"
+
+@interface WXTextInputComponent : WXComponent<WXTextComponentProtocol, UITextFieldDelegate>
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXTextInputComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextInputComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXTextInputComponent.m
new file mode 100644
index 0000000..c78af61
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextInputComponent.m
@@ -0,0 +1,385 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXTextInputComponent.h"
+#import "WXConvert.h"
+#import "WXUtility.h"
+
+@interface WXTextInputView : UITextField
+@property (nonatomic, assign) UIEdgeInsets border;
+@property (nonatomic, assign) UIEdgeInsets padding;
+@end
+
+@implementation WXTextInputView
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+        _padding = UIEdgeInsetsZero;
+        _border = UIEdgeInsetsZero;
+    }
+    return self;
+}
+
+- (CGRect)textRectForBounds:(CGRect)bounds
+{
+    bounds.size.width -= self.padding.left + self.border.left;
+    bounds.origin.x += self.padding.left + self.border.left;
+    
+    bounds.size.height -= self.padding.top + self.border.top;
+    bounds.origin.y += self.padding.top + self.border.top;
+    
+    bounds.size.width -= self.padding.right + self.border.right;
+    
+    bounds.size.height -= self.padding.bottom + self.border.bottom;
+    
+    return bounds;
+}
+
+- (CGRect)editingRectForBounds:(CGRect)bounds
+{
+    return [self textRectForBounds:bounds];
+}
+@end
+
+@interface WXTextInputComponent()
+
+@property (nonatomic, strong) WXTextInputView *inputView;
+//attribute
+@property (nonatomic, strong) UIColor *placeholderColor;
+@property (nonatomic, strong) NSString *placeholder;
+//style
+@property (nonatomic) WXPixelType fontSize;
+@property (nonatomic) WXTextStyle fontStyle;
+@property (nonatomic) WXTextWeight fontWeight;
+@property (nonatomic, strong) NSString *fontFamily;
+//event
+@property (nonatomic) BOOL inputEvent;
+@property (nonatomic) BOOL focusEvent;
+@property (nonatomic) BOOL blurEvent;
+@property (nonatomic) BOOL changeEvent;
+@property (nonatomic, strong) NSString *changeEventString;
+
+@end
+
+@implementation WXTextInputComponent
+{
+    UIEdgeInsets _border;
+    UIEdgeInsets _padding;
+    NSTextStorage* _textStorage;
+}
+
+@synthesize border = _border;
+@synthesize padding = _padding;
+@synthesize textStorage = _textStorage;
+
+- (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;
+        
+        _inputView = [[WXTextInputView alloc] init];
+        if (attributes[@"type"]) {
+            [self setType: attributes[@"type"]];
+        }
+        
+        if (attributes[@"autofocus"]) {
+            [self setAutofocus:[attributes[@"autofocus"] boolValue]];
+        }
+        if (attributes[@"disabled"]) {
+            [_inputView setEnabled:[attributes[@"disabled"] boolValue]];
+        }
+        if (attributes[@"placeholder"]) {
+            _placeholder = attributes[@"placeholder"];
+            _inputView.placeholder = _placeholder;
+        } else {
+            _placeholder = @"";
+        }
+        if (attributes[@"value"]) {
+            _inputView.text = attributes[@"value"];
+        }
+        
+        if (styles[@"color"]) {
+            [_inputView setTextColor:[WXConvert UIColor:styles[@"color"]]];
+        }
+        if (styles[@"fontSize"]) {
+            _fontSize = [WXConvert WXPixelType:styles[@"fontSize"]];
+        }
+        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"]) {
+            [_inputView setTextAlignment:[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];
+        }
+        [self setPlaceholderAttributedString];
+        [self setTextFont];
+        
+        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];
+        }
+    }
+    
+    return self;
+}
+
+-(UIView *)loadView
+{
+    return _inputView;
+}
+
+#pragma mark - lifeCircle
+
+- (void)viewDidLoad
+{
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFiledEditChanged:)
+                                                 name:UITextFieldTextDidChangeNotification
+                                               object:_inputView];
+    _padding = UIEdgeInsetsZero;
+    _border = UIEdgeInsetsZero;
+    _inputView.delegate = self;
+    
+    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];
+    
+    _inputView.inputAccessoryView = toolbar;
+}
+
+- (void)viewWillUnload
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:_inputView];
+}
+
+#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;
+    }
+}
+
+#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;
+    }
+}
+
+#pragma mark - upate attributes
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"type"]) {
+        [self setType: attributes[@"type"]];
+    }
+    if (attributes[@"autofocus"]) {
+        [self setAutofocus:[attributes[@"autofocus"] boolValue]];
+    }
+    if (attributes[@"disabled"]) {
+        [_inputView setEnabled:[attributes[@"disabled"] boolValue]];
+    }
+    if (attributes[@"placeholder"]) {
+        _placeholder = attributes[@"placeholder"];
+        _inputView.placeholder = _placeholder;
+    }
+    if (attributes[@"value"]) {
+        _inputView.text = attributes[@"value"];
+    }
+    
+    [self setPlaceholderAttributedString];
+}
+
+#pragma mark - upate styles
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+    if (styles[@"color"]) {
+        [_inputView setTextColor:[WXConvert UIColor:styles[@"color"]]];
+    }
+    if (styles[@"fontSize"]) {
+        _fontSize = [WXConvert WXPixelType:styles[@"fontSize"]];
+    }
+    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"]) {
+        [_inputView setTextAlignment:[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];
+    }
+    [self setPlaceholderAttributedString];
+    
+    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];
+    }
+}
+
+#pragma mark -
+#pragma mark UITextFieldDelegate
+
+- (void)textFieldDidBeginEditing:(UITextField *)textField
+{
+    _changeEventString = [textField text];
+    if (_focusEvent) {
+        [self fireEvent:@"focus" params:nil];
+    }
+}
+
+- (void)textFieldDidEndEditing:(UITextField *)textField
+{
+    if (_changeEvent) {
+        if (![[textField text] isEqualToString:_changeEventString]) {
+            [self fireEvent:@"change" params:@{@"value":[textField text]}];
+        }
+    }
+    if (_blurEvent) {
+        [self fireEvent:@"blur" params:nil];
+    }
+}
+
+- (void)textFiledEditChanged:(NSNotification *)notifi{
+    if (_inputEvent) {
+        UITextField *textField = (UITextField *)notifi.object;
+        [self fireEvent:@"input" params:@{@"value":textField.text}];
+    }
+}
+
+#pragma mark
+
+- (void)setPlaceholderAttributedString
+{
+    if (_placeholderColor) {
+        NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:_placeholder];
+        [attributedString addAttribute:NSForegroundColorAttributeName value:_placeholderColor range:NSMakeRange(0, _placeholder.length)];
+        [_inputView setAttributedPlaceholder:attributedString];
+    }
+}
+
+- (void)setTextFont
+{
+    UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily];
+    [_inputView setFont:font];
+}
+
+- (void)setAutofocus:(BOOL)b
+{
+    if (b) {
+        [_inputView becomeFirstResponder];
+    }
+    else {
+        [_inputView resignFirstResponder];
+    }
+}
+
+- (void)setType:(NSString*)type
+{
+    [_inputView setKeyboardType:UIKeyboardTypeDefault];
+    [_inputView setSecureTextEntry:NO];
+    
+    if ([type isEqualToString:@"text"]) {
+        [_inputView setKeyboardType:UIKeyboardTypeDefault];
+    }
+    else if ([type isEqualToString:@"password"]) {
+        [_inputView setSecureTextEntry:YES];
+    }
+    else if ([type isEqualToString:@"tel"]) {
+        [_inputView setKeyboardType:UIKeyboardTypePhonePad];
+    }
+    else if ([type isEqualToString:@"email"]) {
+        [_inputView setKeyboardType:UIKeyboardTypeEmailAddress];
+    }
+    else if ([type isEqualToString:@"url"]) {
+        [_inputView setKeyboardType:UIKeyboardTypeURL];
+    }
+    else if ([type isEqualToString:@"date"]) {
+        [_inputView setKeyboardType:UIKeyboardTypeNumberPad];
+    }
+    else if ([type isEqualToString:@"time"]) {
+        [_inputView setKeyboardType:UIKeyboardTypeNumberPad];
+    }
+    else if ([type isEqualToString:@"datetime"]) {
+        [_inputView setKeyboardType:UIKeyboardTypeNumberPad];
+    }
+}
+
+- (void)setPadding:(UIEdgeInsets)padding
+{
+    _padding = padding;
+    [_inputView setPadding:padding];
+}
+
+- (void)setBorder:(UIEdgeInsets)border
+{
+    _border = border;
+    [_inputView setBorder:border];
+}
+
+- (void)closeKeyboard
+{
+    [_inputView resignFirstResponder];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXTransform.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTransform.h b/ios/sdk/WeexSDK/Sources/Component/WXTransform.h
new file mode 100644
index 0000000..b83f4ef
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTransform.h
@@ -0,0 +1,20 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface WXTransform : NSObject
+
+@property CGAffineTransform transform;
+
+- (CATransform3D)getTransform:(NSString *)cssValue;
+- (CATransform3D)getTransform:(NSString *)cssValue withView:(UIView *)view;
+- (CATransform3D)getTransform:(NSString *)cssValue withView:(UIView *)view withOrigin:(NSString *)origin;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXTransform.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTransform.m b/ios/sdk/WeexSDK/Sources/Component/WXTransform.m
new file mode 100644
index 0000000..debae37
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTransform.m
@@ -0,0 +1,216 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXTransform.h"
+#import "math.h"
+#import "WXUtility.h"
+
+@interface WXTransform()
+
+@property (nonatomic, weak) UIView *view;
+
+@end
+
+@implementation WXTransform
+
+- (CATransform3D)getTransform:(NSString *)cssValue
+{
+    _transform = CGAffineTransformIdentity;
+
+    if (!cssValue || cssValue.length == 0 || [cssValue isEqualToString:@"none"]) {
+        return CATransform3DMakeAffineTransform(_transform);
+    }
+    NSError *error = NULL;
+    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(\\w+)\\((.+?)\\)"
+                                                                           options:NSRegularExpressionCaseInsensitive
+                                                                             error:&error];
+
+    NSArray *matches = [regex matchesInString:cssValue options:0 range:NSMakeRange(0, cssValue.length)];
+
+    for (NSTextCheckingResult *match in matches) {
+        NSString *name = [cssValue substringWithRange:[match rangeAtIndex:1]];
+        NSArray *value = [[cssValue substringWithRange:[match rangeAtIndex:2]] componentsSeparatedByString:@","];
+
+        SEL method = NSSelectorFromString([NSString stringWithFormat:@"do%@:", [name capitalizedString]]);
+        if ([self respondsToSelector:method]) {
+            @try {
+                [self performSelectorOnMainThread:method withObject:value waitUntilDone:YES];
+            }
+            @catch (NSException *exception) {
+                WXLogError(@"WXTransform exception:%@", [exception reason]);
+            }
+        }
+    }
+
+    return CATransform3DMakeAffineTransform(_transform);
+}
+
+- (CATransform3D)getTransform:(NSString *)cssValue withView:(UIView *)view
+{
+    _view = view;
+    CATransform3D transform = [self getTransform:cssValue];
+    _view = nil;
+    return transform;
+}
+
+- (CATransform3D)getTransform:(NSString *)cssValue withView:(UIView *)view withOrigin:(NSString *)origin
+{
+    if (origin && origin.length > 0 && ![origin isEqualToString:@"none"]) {
+        CGPoint originPoint = [self getTransformOrigin:origin withView:view];
+        if (originPoint.x != 0 || originPoint.y != 0) {
+            cssValue = [NSString stringWithFormat:@"translate(%f,%f) %@ translate(%f,%f)", originPoint.x, originPoint.y, cssValue, -originPoint.x, -originPoint.y];
+        }
+    }
+    
+    return [self getTransform:cssValue withView:view];
+}
+
+- (CGPoint)getTransformOrigin:(NSString *)cssValue withView:(UIView *)view
+{
+    NSArray *values = [cssValue componentsSeparatedByString:@" "];
+    double width = view.bounds.size.width;
+    double height = view.bounds.size.height;
+    double x = width / 2;
+    double y = height / 2;
+
+    for (NSInteger i = 0; i < values.count; i++) {
+        NSString *value = values[i];
+        if ([value isEqualToString:@"left"]) {
+            x = 0;
+        } else if ([value isEqualToString:@"right"]) {
+            x = width;
+        } else if ([value isEqualToString:@"top"]) {
+            y = 0;
+        } else if ([value isEqualToString:@"bottom"]) {
+            y = height;
+        } else if ([value isEqualToString:@"center"]) {
+            if (i == 0) {
+                x = width / 2;
+            } else {
+                y = height / 2;
+            }
+        } else {
+            double val = [value doubleValue];
+            if (i == 0) {
+                if ([value hasSuffix:@"%"]) {
+                    val *= width / 100;
+                } else {
+                    val = WXPixelResize(val);
+                }
+                x = val;
+            } else {
+                if ([value hasSuffix:@"%"]) {
+                    val *= height / 100;
+                } else {
+                    val = WXPixelResize(val);
+                }
+                y = val;
+            }
+        }
+    }
+    x -= width / 2.0;
+    y -= height / 2.0;
+    return CGPointMake(round(x / WXScreenResizeRadio()), round(y / WXScreenResizeRadio()));
+}
+
+// Angle in radians
+- (double)getAngle:(NSString *)value
+{
+    double angle = [value doubleValue];
+    if ([value hasSuffix:@"deg"]) {
+        angle *= M_PI / 180;
+    }
+    return angle;
+}
+
+// css transfrom
+- (void)doTranslate:(NSArray *)value
+{
+    double x = [value[0] doubleValue];
+    if ([value[0] hasSuffix:@"%"] && _view) {
+        x *= _view.bounds.size.width / 100;
+    } else {
+        x = WXPixelResize(x);
+    }
+
+    double y = 0;
+
+    if (value.count > 1) {
+        y = [value[1] doubleValue];
+        if ([value[0] hasSuffix:@"%"] && _view) {
+            y *= _view.bounds.size.height / 100;
+        } else {
+            y = WXPixelResize(y);
+        }
+    }
+    _transform = CGAffineTransformTranslate(_transform, x, y);
+}
+
+- (void)doTranslatex:(NSArray *)value
+{
+    [self doTranslate:@[value[0], @"0"]];
+}
+
+- (void)doTranslatey:(NSArray *)value
+{
+    [self doTranslate:@[@"0", value[0]]];
+}
+
+- (void)doRotate:(NSArray *)value
+{
+    _transform = CGAffineTransformRotate(_transform, [self getAngle:value[0]]);
+}
+
+- (void)doScale:(NSArray *)value
+{
+    double x = [value[0] doubleValue];
+    double y = x;
+    if (value.count == 2) {
+        y = [value[1] doubleValue];
+    }
+    _transform = CGAffineTransformScale(_transform, x, y);
+}
+
+- (void)doScalex:(NSArray *)value
+{
+    [self doScale:@[value[0], @1]];
+}
+
+- (void)doScaley:(NSArray *)value
+{
+    [self doScale:@[@1, value[0]]];
+}
+
+- (void)doSkew:(NSArray *)value
+{
+    CGAffineTransform skew = CGAffineTransformIdentity;
+    skew.c = tan([self getAngle:value[0]]);
+    if (value.count == 2) {
+        skew.b = tan([self getAngle:value[1]]);
+    }
+    _transform = CGAffineTransformConcat(skew, _transform);
+}
+
+- (void)doSkewx:(NSArray *)value
+{
+    [self doSkew:@[value[0], @0]];
+}
+
+- (void)doSkewy:(NSArray *)value
+{
+    [self doSkew:@[@0, value[0]]];
+}
+
+- (void)doMatrix:(NSArray *) value
+{
+    if (value.count < 6) return;
+    
+    _transform = CGAffineTransformConcat(CGAffineTransformMake([value[0] doubleValue], [value[1] doubleValue], [value[2] doubleValue], [value[3] doubleValue], [value[4] doubleValue], [value[5] doubleValue]), _transform);
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXVideoComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXVideoComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXVideoComponent.h
new file mode 100644
index 0000000..3f61da8
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXVideoComponent.h
@@ -0,0 +1,34 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+typedef NS_ENUM(NSInteger, WXPlaybackState) {
+    WXPlaybackStatePlaying,
+    WXPlaybackStatePaused,
+    //    WXPlaybackStateStopped,
+    WXPlaybackStatePlayFinish,
+    WXPlaybackStateFailed,
+};
+
+@interface WXVideoView : UIView
+
+@property (nonatomic, copy) void (^playbackStateChanged)(WXPlaybackState state);
+
+- (void) setURL:(NSURL*)URL;
+
+- (void) play;
+- (void) pause;
+
+@end
+
+@interface WXVideoComponent : WXComponent
+
+@end
+
+