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
+
+