You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by cx...@apache.org on 2017/03/06 11:10:11 UTC

[05/12] incubator-weex git commit: * [dev] Add Feature Recycler and Waterfall

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
index 2a0f761..29ccab4 100644
--- a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
+++ b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
@@ -115,6 +115,22 @@
 		744BEA561D05178F00452B5D /* WXComponent+Display.m in Sources */ = {isa = PBXBuildFile; fileRef = 744BEA541D05178F00452B5D /* WXComponent+Display.m */; };
 		744BEA591D0520F300452B5D /* WXComponent+Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 744BEA571D0520F300452B5D /* WXComponent+Layout.h */; };
 		744BEA5A1D0520F300452B5D /* WXComponent+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 744BEA581D0520F300452B5D /* WXComponent+Layout.m */; };
+		744D610C1E49978200B624B3 /* WXHeaderComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 744D610A1E49978200B624B3 /* WXHeaderComponent.h */; };
+		744D610D1E49978200B624B3 /* WXHeaderComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 744D610B1E49978200B624B3 /* WXHeaderComponent.m */; };
+		744D61101E49979000B624B3 /* WXFooterComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 744D610E1E49979000B624B3 /* WXFooterComponent.h */; };
+		744D61111E49979000B624B3 /* WXFooterComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 744D610F1E49979000B624B3 /* WXFooterComponent.m */; };
+		744D61141E4AF23E00B624B3 /* WXDiffUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 744D61121E4AF23E00B624B3 /* WXDiffUtil.h */; };
+		744D61151E4AF23E00B624B3 /* WXDiffUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 744D61131E4AF23E00B624B3 /* WXDiffUtil.m */; };
+		745B2D681E5A8E1E0092D38A /* WXMultiColumnLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D5E1E5A8E1E0092D38A /* WXMultiColumnLayout.h */; };
+		745B2D691E5A8E1E0092D38A /* WXMultiColumnLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D5F1E5A8E1E0092D38A /* WXMultiColumnLayout.m */; };
+		745B2D6A1E5A8E1E0092D38A /* WXRecyclerComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D601E5A8E1E0092D38A /* WXRecyclerComponent.h */; };
+		745B2D6B1E5A8E1E0092D38A /* WXRecyclerComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.m */; };
+		745B2D6C1E5A8E1E0092D38A /* WXRecyclerDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D621E5A8E1E0092D38A /* WXRecyclerDataController.h */; };
+		745B2D6D1E5A8E1E0092D38A /* WXRecyclerDataController.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D631E5A8E1E0092D38A /* WXRecyclerDataController.m */; };
+		745B2D6E1E5A8E1E0092D38A /* WXRecyclerUpdateController.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D641E5A8E1E0092D38A /* WXRecyclerUpdateController.h */; };
+		745B2D6F1E5A8E1E0092D38A /* WXRecyclerUpdateController.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D651E5A8E1E0092D38A /* WXRecyclerUpdateController.m */; };
+		745B2D701E5A8E1E0092D38A /* WXSectionDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 745B2D661E5A8E1E0092D38A /* WXSectionDataController.h */; };
+		745B2D711E5A8E1E0092D38A /* WXSectionDataController.m in Sources */ = {isa = PBXBuildFile; fileRef = 745B2D671E5A8E1E0092D38A /* WXSectionDataController.m */; };
 		745ED2DA1C5F2C7E002DB5A8 /* WXView.h in Headers */ = {isa = PBXBuildFile; fileRef = 745ED2D61C5F2C7E002DB5A8 /* WXView.h */; };
 		745ED2DB1C5F2C7E002DB5A8 /* WXView.m in Sources */ = {isa = PBXBuildFile; fileRef = 745ED2D71C5F2C7E002DB5A8 /* WXView.m */; };
 		7461F8901CFB373100F62D44 /* WXDisplayQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 7461F88C1CFB373100F62D44 /* WXDisplayQueue.h */; };
@@ -407,6 +423,22 @@
 		744BEA541D05178F00452B5D /* WXComponent+Display.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WXComponent+Display.m"; sourceTree = "<group>"; };
 		744BEA571D0520F300452B5D /* WXComponent+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "WXComponent+Layout.h"; path = "Layout/WXComponent+Layout.h"; sourceTree = "<group>"; };
 		744BEA581D0520F300452B5D /* WXComponent+Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "WXComponent+Layout.m"; path = "Layout/WXComponent+Layout.m"; sourceTree = "<group>"; };
+		744D610A1E49978200B624B3 /* WXHeaderComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXHeaderComponent.h; sourceTree = "<group>"; };
+		744D610B1E49978200B624B3 /* WXHeaderComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXHeaderComponent.m; sourceTree = "<group>"; };
+		744D610E1E49979000B624B3 /* WXFooterComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXFooterComponent.h; sourceTree = "<group>"; };
+		744D610F1E49979000B624B3 /* WXFooterComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXFooterComponent.m; sourceTree = "<group>"; };
+		744D61121E4AF23E00B624B3 /* WXDiffUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXDiffUtil.h; sourceTree = "<group>"; };
+		744D61131E4AF23E00B624B3 /* WXDiffUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXDiffUtil.m; sourceTree = "<group>"; };
+		745B2D5E1E5A8E1E0092D38A /* WXMultiColumnLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXMultiColumnLayout.h; path = WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.h; sourceTree = SOURCE_ROOT; };
+		745B2D5F1E5A8E1E0092D38A /* WXMultiColumnLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXMultiColumnLayout.m; path = WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.m; sourceTree = SOURCE_ROOT; };
+		745B2D601E5A8E1E0092D38A /* WXRecyclerComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXRecyclerComponent.h; path = WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.h; sourceTree = SOURCE_ROOT; };
+		745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXRecyclerComponent.m; path = WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m; sourceTree = SOURCE_ROOT; };
+		745B2D621E5A8E1E0092D38A /* WXRecyclerDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXRecyclerDataController.h; path = WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.h; sourceTree = SOURCE_ROOT; };
+		745B2D631E5A8E1E0092D38A /* WXRecyclerDataController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXRecyclerDataController.m; path = WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.m; sourceTree = SOURCE_ROOT; };
+		745B2D641E5A8E1E0092D38A /* WXRecyclerUpdateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXRecyclerUpdateController.h; path = WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.h; sourceTree = SOURCE_ROOT; };
+		745B2D651E5A8E1E0092D38A /* WXRecyclerUpdateController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXRecyclerUpdateController.m; path = WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.m; sourceTree = SOURCE_ROOT; };
+		745B2D661E5A8E1E0092D38A /* WXSectionDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WXSectionDataController.h; path = WeexSDK/Sources/Component/Recycler/WXSectionDataController.h; sourceTree = SOURCE_ROOT; };
+		745B2D671E5A8E1E0092D38A /* WXSectionDataController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WXSectionDataController.m; path = WeexSDK/Sources/Component/Recycler/WXSectionDataController.m; sourceTree = SOURCE_ROOT; };
 		745ED2D61C5F2C7E002DB5A8 /* WXView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXView.h; sourceTree = "<group>"; };
 		745ED2D71C5F2C7E002DB5A8 /* WXView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXView.m; sourceTree = "<group>"; };
 		7461F88C1CFB373100F62D44 /* WXDisplayQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXDisplayQueue.h; sourceTree = "<group>"; };
@@ -778,6 +810,24 @@
 			path = WeexSDKTests;
 			sourceTree = "<group>";
 		};
+		74D8DB401E4825920078B667 /* Recycler */ = {
+			isa = PBXGroup;
+			children = (
+				745B2D5E1E5A8E1E0092D38A /* WXMultiColumnLayout.h */,
+				745B2D5F1E5A8E1E0092D38A /* WXMultiColumnLayout.m */,
+				745B2D601E5A8E1E0092D38A /* WXRecyclerComponent.h */,
+				745B2D611E5A8E1E0092D38A /* WXRecyclerComponent.m */,
+				745B2D621E5A8E1E0092D38A /* WXRecyclerDataController.h */,
+				745B2D631E5A8E1E0092D38A /* WXRecyclerDataController.m */,
+				745B2D641E5A8E1E0092D38A /* WXRecyclerUpdateController.h */,
+				745B2D651E5A8E1E0092D38A /* WXRecyclerUpdateController.m */,
+				745B2D661E5A8E1E0092D38A /* WXSectionDataController.h */,
+				745B2D671E5A8E1E0092D38A /* WXSectionDataController.m */,
+			);
+			name = Recycler;
+			path = Grid;
+			sourceTree = "<group>";
+		};
 		74EF31C11DE6932900667A07 /* handler */ = {
 			isa = PBXGroup;
 			children = (
@@ -990,6 +1040,8 @@
 				74896F2F1D1AC79400D1D593 /* NSObject+WXSwizzle.m */,
 				747DF6801E31AEE4005C53A8 /* WXLength.h */,
 				747DF6811E31AEE4005C53A8 /* WXLength.m */,
+				744D61121E4AF23E00B624B3 /* WXDiffUtil.h */,
+				744D61131E4AF23E00B624B3 /* WXDiffUtil.m */,
 			);
 			path = Utility;
 			sourceTree = "<group>";
@@ -1036,6 +1088,7 @@
 			children = (
 				C4B3D6D21E6954300013F38D /* WXEditComponent.h */,
 				C4B3D6D31E6954300013F38D /* WXEditComponent.m */,
+				74D8DB401E4825920078B667 /* Recycler */,
 				2A837AAC1CD9DE9200AEDF03 /* WXLoadingComponent.h */,
 				2A837AAD1CD9DE9200AEDF03 /* WXLoadingComponent.m */,
 				2A837AAE1CD9DE9200AEDF03 /* WXLoadingIndicator.h */,
@@ -1060,12 +1113,12 @@
 				77E65A181C155F25008B8775 /* WXScrollerComponent.m */,
 				2A44AB0F1C1AD5B00067A7EA /* WXSliderComponent.h */,
 				59D3CA461CFC3CC0008835DC /* WXSliderComponent.m */,
-				74CC7A1A1C2BC5F800829368 /* WXCellComponent.h */,
 				74CC7A1B1C2BC5F800829368 /* WXCellComponent.m */,
 				74CC7A1E1C2BF9DC00829368 /* WXListComponent.h */,
 				74CC7A1F1C2BF9DC00829368 /* WXListComponent.m */,
 				2AC750221C7565690041D390 /* WXIndicatorComponent.h */,
 				2AC750231C7565690041D390 /* WXIndicatorComponent.m */,
+				74CC7A1A1C2BC5F800829368 /* WXCellComponent.h */,
 				2A1F57B51C75C6A600B58017 /* WXTextInputComponent.h */,
 				2A1F57B61C75C6A600B58017 /* WXTextInputComponent.m */,
 				DC03ADB81D508719003F76E7 /* WXTextAreaComponent.h */,
@@ -1083,6 +1136,10 @@
 				D33451071D3E19480083598A /* WXCanvasComponent.m */,
 				59970D2C1E0D228D0049F535 /* WXComponent+GradientColor.h */,
 				59970D2D1E0D228D0049F535 /* WXComponent+GradientColor.m */,
+				744D610A1E49978200B624B3 /* WXHeaderComponent.h */,
+				744D610B1E49978200B624B3 /* WXHeaderComponent.m */,
+				744D610E1E49979000B624B3 /* WXFooterComponent.h */,
+				744D610F1E49979000B624B3 /* WXFooterComponent.m */,
 			);
 			path = Component;
 			sourceTree = "<group>";
@@ -1182,9 +1239,12 @@
 				77D161621C02ED790010B15B /* WXLog.h in Headers */,
 				77D1614B1C02E3790010B15B /* WXConvert.h in Headers */,
 				59A596221CB6311F0012CD52 /* WXNavigatorModule.h in Headers */,
+				745B2D6A1E5A8E1E0092D38A /* WXRecyclerComponent.h in Headers */,
 				749DC27B1D40827B009E1C91 /* WXMonitor.h in Headers */,
 				77E659DA1C07F594008B8775 /* WXDomModule.h in Headers */,
 				74EF31AD1DE58BE200667A07 /* WXURLRewriteDefaultImpl.h in Headers */,
+				744D61101E49979000B624B3 /* WXFooterComponent.h in Headers */,
+				744D61141E4AF23E00B624B3 /* WXDiffUtil.h in Headers */,
 				74862F791E02B88D00B7A041 /* JSValue+Weex.h in Headers */,
 				2A1F57B71C75C6A600B58017 /* WXTextInputComponent.h in Headers */,
 				C4F012791E1502A6003378D0 /* SRWebSocket+Weex.h in Headers */,
@@ -1198,6 +1258,8 @@
 				74A4BA961CB365D100195969 /* WXAppConfiguration.h in Headers */,
 				7461F8921CFB373100F62D44 /* WXLayer.h in Headers */,
 				594C28931CF9E61A009793A4 /* WXAnimationModule.h in Headers */,
+				745B2D701E5A8E1E0092D38A /* WXSectionDataController.h in Headers */,
+				745B2D6E1E5A8E1E0092D38A /* WXRecyclerUpdateController.h in Headers */,
 				D3FC0DF71C508B2A002B9E31 /* WXTimerModule.h in Headers */,
 				D312CE3B1C730DEB00046D68 /* WXWebComponent.h in Headers */,
 				741081261CEDB4EC001BC6E5 /* WXComponent_internal.h in Headers */,
@@ -1240,10 +1302,13 @@
 				D33451081D3E19480083598A /* WXCanvasComponent.h in Headers */,
 				74B8BEFE1DC47B72004A6027 /* WXRootView.h in Headers */,
 				77E65A111C155EA8008B8775 /* WXImageComponent.h in Headers */,
+				745B2D6C1E5A8E1E0092D38A /* WXRecyclerDataController.h in Headers */,
+				745B2D681E5A8E1E0092D38A /* WXMultiColumnLayout.h in Headers */,
 				2A60CE9C1C91733E00857B9F /* WXSwitchComponent.h in Headers */,
 				DCDFED011E68238F00C228D7 /* WXJSExceptionProtocol.h in Headers */,
 				2A4445BF1CA8FD56009E7C6D /* WXTextComponentProtocol.h in Headers */,
 				746319021C60AFC100EFEBD4 /* WXThreadSafeCounter.h in Headers */,
+				744D610C1E49978200B624B3 /* WXHeaderComponent.h in Headers */,
 				77D1613C1C02DEA60010B15B /* WXJSCoreBridge.h in Headers */,
 				74D205201E091B8000128F44 /* WXCallJSMethod.h in Headers */,
 				741DFE061DDD9B30009B020F /* UIBezierPath+Weex.h in Headers */,
@@ -1460,6 +1525,9 @@
 				C4F0127C1E1502A6003378D0 /* WXWebSocketDefaultImpl.m in Sources */,
 				77E65A0E1C155E99008B8775 /* WXDivComponent.m in Sources */,
 				2A60CE9D1C91733E00857B9F /* WXSwitchComponent.m in Sources */,
+				744D61111E49979000B624B3 /* WXFooterComponent.m in Sources */,
+				745B2D6F1E5A8E1E0092D38A /* WXRecyclerUpdateController.m in Sources */,
+				745B2D6B1E5A8E1E0092D38A /* WXRecyclerComponent.m in Sources */,
 				2A837AB71CD9DE9200AEDF03 /* WXRefreshComponent.m in Sources */,
 				74A4BA9B1CB3BAA100195969 /* WXThreadSafeMutableDictionary.m in Sources */,
 				77E65A1A1C155F25008B8775 /* WXScrollerComponent.m in Sources */,
@@ -1488,6 +1556,7 @@
 				74AD99851D5B0E59008F0336 /* WXPolyfillSet.m in Sources */,
 				D317338D1C57257000BB7539 /* WXTransform.m in Sources */,
 				7461F8A91CFC33A800F62D44 /* WXThreadSafeMutableArray.m in Sources */,
+				745B2D6D1E5A8E1E0092D38A /* WXRecyclerDataController.m in Sources */,
 				2AC750251C7565690041D390 /* WXIndicatorComponent.m in Sources */,
 				591DD3311D23AD5800BE8709 /* WXErrorView.m in Sources */,
 				59D3CA4B1CFC3CE1008835DC /* NSTimer+Weex.m in Sources */,
@@ -1500,6 +1569,7 @@
 				C4D872261E5DDF7500E39BC1 /* WXBoxShadow.m in Sources */,
 				746319031C60AFC100EFEBD4 /* WXThreadSafeCounter.m in Sources */,
 				74A4BAA71CB4F98300195969 /* WXStreamModule.m in Sources */,
+				744D610D1E49978200B624B3 /* WXHeaderComponent.m in Sources */,
 				59597F991D2A041700EE9317 /* WXDebugLoggerBridge.m in Sources */,
 				77E659F21C0C3612008B8775 /* WXModuleFactory.m in Sources */,
 				DCF343681E49CAEE00A2FB34 /* WXJSExceptionInfo.m in Sources */,
@@ -1508,6 +1578,7 @@
 				2A919DA71E321F1F006EB6B5 /* WXBridgeMethod.m in Sources */,
 				DCAB35FF1D658EB700C0EA70 /* WXRuleManager.m in Sources */,
 				77D161251C02DDD10010B15B /* WXSDKInstance.m in Sources */,
+				744D61151E4AF23E00B624B3 /* WXDiffUtil.m in Sources */,
 				74EF31AE1DE58BE200667A07 /* WXURLRewriteDefaultImpl.m in Sources */,
 				C4B3D6D51E6954300013F38D /* WXEditComponent.m in Sources */,
 				C4C30DE81E1B833D00786B6C /* WXComponent+PseudoClassManagement.m in Sources */,
@@ -1519,6 +1590,7 @@
 				D334510D1D3E19B80083598A /* WXCanvasModule.m in Sources */,
 				741081241CED6756001BC6E5 /* WXComponentFactory.m in Sources */,
 				D362F9501C83EDA20003F546 /* WXWebViewModule.m in Sources */,
+				745B2D711E5A8E1E0092D38A /* WXSectionDataController.m in Sources */,
 				2A1F57B81C75C6A600B58017 /* WXTextInputComponent.m in Sources */,
 				74CC7A1D1C2BC5F800829368 /* WXCellComponent.m in Sources */,
 				74862F821E03A24500B7A041 /* WXComponentMethod.m in Sources */,
@@ -1554,6 +1626,7 @@
 				C4B834271DE69B09007AD27E /* WXPickerModule.m in Sources */,
 				C4F0127A1E1502A6003378D0 /* SRWebSocket+Weex.m in Sources */,
 				59970D2F1E0D228D0049F535 /* WXComponent+GradientColor.m in Sources */,
+				745B2D691E5A8E1E0092D38A /* WXMultiColumnLayout.m in Sources */,
 				77D161391C02DE940010B15B /* WXBridgeManager.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.h b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.h
new file mode 100644
index 0000000..f107db0
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.h
@@ -0,0 +1,42 @@
+/**
+ * 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 <UIKit/UIKit.h>
+#import "WXLength.h"
+
+extern NSString * const kCollectionSupplementaryViewKindHeader;
+
+@protocol WXMultiColumnLayoutDelegate <NSObject>
+
+- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView insetForLayout:(UICollectionViewLayout *)collectionViewLayout;
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView contentWidthForLayout:(UICollectionViewLayout *)collectionViewLayout;
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForItemAtIndexPath:(NSIndexPath *)indexPath;
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForHeaderInSection:(NSInteger)section;
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout isNeedStickyForHeaderInSection:(NSInteger)section;
+
+@end
+
+@interface WXMultiColumnLayout : UICollectionViewLayout
+
+@property (nonatomic, weak) id<WXMultiColumnLayoutDelegate> delegate;
+
+@property (nonatomic, strong) WXLength *columnCount;
+
+@property (nonatomic, strong) WXLength *columnWidth;
+
+@property (nonatomic, assign) float columnGap;
+
+@property (nonatomic, assign, readonly) CGFloat computedColumnWidth;
+@property (nonatomic, assign, readonly) int computedColumnCount;
+@property (nonatomic, assign, readonly) CGFloat computedHeaderWidth;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.m b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.m
new file mode 100644
index 0000000..f5d641e
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXMultiColumnLayout.m
@@ -0,0 +1,388 @@
+/**
+ * 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 "WXMultiColumnLayout.h"
+#import "NSArray+Weex.h"
+#import "WXUtility.h"
+#import "WXAssert.h"
+
+void computeColumnWidthAndCount(float availableWidth, WXLength *columnCount, WXLength *columnWidth, float columnGap, int *N, float *W)
+{
+    /* Pseudo-algorithm according to
+     * https://www.w3.org/TR/css3-multicol/
+     * Note that, in most cases, only one of \u2018column-width\u2019 and \u2018column-count\u2019 affect the layout. 
+     * If \u2018column-width\u2019 has a value other than \u2018auto\u2019, \u2018column-count\u2019 indicates the maximum number of columns.
+     **/
+    if (columnWidth.isAuto && columnCount.isAuto) {
+        WXAssert(NO, @"Unsupport both of column-width and column-count being auto.");
+        return;
+    }
+    
+    if (columnWidth.isAuto && !columnCount.isAuto) {
+        *N = columnCount.intValue;
+        *W = MAX(0, (availableWidth - ((*N -1) * columnGap)) / *N);
+    }
+    
+    if (!columnWidth.isAuto && columnCount.isAuto) {
+        *N = MAX(1, WXFloorPixelValue((availableWidth + columnGap) / (columnWidth.floatValue + columnGap)));
+        *W = ((availableWidth + columnGap) / *N) - columnGap;
+    }
+    
+    if (!columnWidth.isAuto && !columnCount.isAuto) {
+        *N = MIN(columnCount.intValue, WXFloorPixelValue((availableWidth + columnGap) / (columnWidth.floatValue + columnGap)));
+        *W = ((availableWidth + columnGap) / *N) - columnGap;
+    }
+}
+
+NSString * const kCollectionSupplementaryViewKindHeader = @"WXCollectionSupplementaryViewKindHeader";
+NSString * const kMultiColumnLayoutHeader = @"WXMultiColumnLayoutHeader";
+NSString * const kMultiColumnLayoutCell = @"WXMultiColumnLayoutCell";
+
+@interface WXMultiColumnLayoutHeaderAttributes : UICollectionViewLayoutAttributes
+
+@property (nonatomic, assign) BOOL isSticky;
+
+@end
+
+@implementation WXMultiColumnLayoutHeaderAttributes
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    WXMultiColumnLayoutHeaderAttributes *copy = [super copyWithZone:zone];
+    copy.isSticky = self.isSticky;
+    
+    return copy;
+}
+
+@end
+
+@interface WXMultiColumnLayout ()
+
+@property (nonatomic, strong) NSMutableDictionary<NSString *, NSDictionary<id, UICollectionViewLayoutAttributes *> *> *layoutAttributes;
+@property (nonatomic, strong) NSMutableArray<NSNumber *> *columnsMaxHeights;
+
+@property (nonatomic, assign, readwrite) CGFloat computedColumnWidth;
+@property (nonatomic, assign, readwrite) int computedColumnCount;
+
+@end
+
+@implementation WXMultiColumnLayout
+
+- (instancetype)init
+{
+    if (self = [super init]) {
+        _layoutAttributes = [NSMutableDictionary dictionary];
+        _columnsMaxHeights = [NSMutableArray array];
+    }
+    
+    return self;
+}
+
+#pragma mark - Public Accessors
+
+- (void)setColumnCount:(WXLength *)columnCount
+{
+    if (!(columnCount.isAuto && _columnCount.isAuto) || _columnCount.intValue != columnCount.intValue) {
+        _columnCount = columnCount;
+        [self _cleanComputed];
+    }
+}
+
+- (void)setColumnWidth:(WXLength *)columnWidth
+{
+    if (!(columnWidth.isAuto && _columnWidth.isAuto) || _columnWidth.floatValue != columnWidth.floatValue) {
+        _columnWidth = columnWidth;
+        [self _cleanComputed];
+    }
+}
+
+- (void)setColumnGap:(float)columnGap
+{
+    if (_columnGap != columnGap) {
+        _columnGap = columnGap;
+        [self _cleanComputed];
+    }
+}
+
+- (CGFloat)computedColumnWidth
+{
+    if (!_computedColumnWidth && !_computedColumnCount) {
+        [self _computeColumnWidthAndCount];
+    }
+    
+    return _computedColumnWidth;
+}
+
+- (int)computedColumnCount
+{
+    if (!_computedColumnWidth && !_computedColumnCount) {
+        [self _computeColumnWidthAndCount];
+    }
+    
+    return _computedColumnCount;
+}
+
+- (CGFloat)computedHeaderWidth
+{
+    UIEdgeInsets insets = [self.delegate collectionView:self.collectionView insetForLayout:self];
+    return self.contentWidth - (insets.left + insets.right);
+}
+
+#pragma mark - Methods to Override for UICollectionViewLayout
+
+- (void)prepareLayout
+{
+    [super prepareLayout];
+    
+    [self _cleanup];
+    
+    NSInteger numberOfSections = [self.collectionView numberOfSections];
+    UIEdgeInsets insets = [self.delegate collectionView:self.collectionView insetForLayout:self];
+    
+    float columnWidth = self.computedColumnWidth;
+    int columnCount = self.computedColumnCount;
+    float columnGap = self.columnGap;
+    
+    CGFloat currentHeight = insets.top;
+    NSMutableDictionary *headersAttributes = [NSMutableDictionary dictionaryWithCapacity:numberOfSections];
+    NSMutableDictionary *cellAttributes = [NSMutableDictionary dictionary];
+    for (NSInteger i = 0; i < columnCount; i++) {
+        [self.columnsMaxHeights addObject:@(currentHeight)];
+    }
+    
+    for (NSInteger section = 0; section < numberOfSections; section++) {
+        CGFloat headerHeight = [self.delegate collectionView:self.collectionView layout:self heightForHeaderInSection:section];
+        // header
+        if (headerHeight > 0) {
+            WXMultiColumnLayoutHeaderAttributes *headerAttributes = [WXMultiColumnLayoutHeaderAttributes layoutAttributesForSupplementaryViewOfKind:kCollectionSupplementaryViewKindHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
+            headerAttributes.frame = CGRectMake(insets.left, currentHeight, self.contentWidth - (insets.left + insets.right), headerHeight);
+            headerAttributes.isSticky = [self.delegate collectionView:self.collectionView layout:self isNeedStickyForHeaderInSection:section];
+            headerAttributes.zIndex = headerAttributes.isSticky ? 1 : 0;
+            headersAttributes[@(section)] = headerAttributes;
+            
+            currentHeight = CGRectGetMaxY(headerAttributes.frame);
+            [self _columnsReachToHeight:currentHeight];
+        }
+        
+        // cells
+        for (NSInteger item = 0; item < [self.collectionView numberOfItemsInSection:section]; item++) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
+            CGFloat itemHeight = [self.delegate collectionView:self.collectionView layout:self heightForItemAtIndexPath:indexPath];
+            UICollectionViewLayoutAttributes *itemAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
+            NSUInteger column = [self _minHeightColumnForAllColumns];
+            CGFloat x = insets.left + (columnWidth + columnGap) * column;
+            CGFloat y = [self.columnsMaxHeights[column] floatValue];
+            itemAttributes.frame = CGRectMake(x, y, columnWidth, itemHeight);
+            cellAttributes[indexPath] = itemAttributes;
+            
+            self.columnsMaxHeights[column] = @(CGRectGetMaxY(itemAttributes.frame));
+        }
+    }
+    
+    currentHeight = [self _maxHeightForAllColumns] + insets.bottom;
+    [self _columnsReachToHeight:currentHeight];
+    
+    self.layoutAttributes[kMultiColumnLayoutHeader] = headersAttributes;
+    self.layoutAttributes[kMultiColumnLayoutCell] = cellAttributes;
+}
+
+- (CGSize)collectionViewContentSize
+{
+    NSInteger numberOfSections = [self.collectionView numberOfSections];
+    if (numberOfSections == 0) {
+        return CGSizeZero;
+    }
+    
+    return CGSizeMake(self.contentWidth, self.contentHeight);
+}
+
+- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
+{
+    NSMutableArray<WXMultiColumnLayoutHeaderAttributes *> *stickyHeaders = [NSMutableArray array];
+    NSMutableArray<UICollectionViewLayoutAttributes *> *result = [NSMutableArray array];
+    
+    [self.layoutAttributes enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull kind, NSDictionary<id,UICollectionViewLayoutAttributes *> * _Nonnull dictionary, BOOL * _Nonnull stop) {
+        [dictionary enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, UICollectionViewLayoutAttributes * _Nonnull attributes, BOOL * _Nonnull stop) {
+            if (attributes.representedElementKind == kCollectionSupplementaryViewKindHeader
+                && [self.delegate collectionView:self.collectionView layout:self isNeedStickyForHeaderInSection:attributes.indexPath.section]) {
+                [stickyHeaders addObject:(WXMultiColumnLayoutHeaderAttributes *)attributes];
+            } else if (CGRectIntersectsRect(rect, attributes.frame)) {
+                [result addObject:attributes];
+            }
+        }];
+    }];
+    
+    [stickyHeaders sortUsingComparator:^NSComparisonResult(WXMultiColumnLayoutHeaderAttributes *obj1, WXMultiColumnLayoutHeaderAttributes *obj2) {
+        if (obj1.indexPath.section < obj2.indexPath.section) {
+            return NSOrderedAscending;
+        } else {
+            return NSOrderedDescending;
+        }
+    }];
+    
+    for (int i = 0; i < stickyHeaders.count; i++) {
+        WXMultiColumnLayoutHeaderAttributes *header = stickyHeaders[i];
+        [self _adjustStickyForHeaderAttributes:header next:(i == stickyHeaders.count - 1) ? nil : stickyHeaders[i + 1]];
+        [result addObject:header];
+    }
+    
+    WXLogDebug(@"return result attributes:%@ for rect:%@", result, NSStringFromCGRect(rect));
+    
+    return result;
+}
+
+- (void)_adjustStickyForHeaderAttributes:(WXMultiColumnLayoutHeaderAttributes *)header
+                                   next:(WXMultiColumnLayoutHeaderAttributes *)nextHeader
+{
+    CGRect bounds = self.collectionView.bounds;
+    CGFloat originY = header.frame.origin.y;
+    CGFloat maxY = nextHeader ? (nextHeader.frame.origin.y - header.frame.size.height) : (CGRectGetMaxY(bounds) - header.frame.size.height);
+    CGFloat currentY = CGRectGetMaxY(bounds) - bounds.size.height + self.collectionView.contentInset.top;
+    
+    CGFloat resultY = MIN(MAX(currentY, originY), maxY);
+    CGPoint origin = header.frame.origin;
+    origin.y = resultY;
+    
+    header.frame = (CGRect){origin, header.frame.size};
+    header.hidden = NO;
+}
+
+- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
+{
+    if ([elementKind isEqualToString:kCollectionSupplementaryViewKindHeader]) {
+        UICollectionViewLayoutAttributes *attributes = self.layoutAttributes[kMultiColumnLayoutHeader][@(indexPath.section)];
+        WXLogDebug(@"return header attributes:%@ for index path:%@", attributes, indexPath);
+        
+        return attributes;
+    }
+    
+    return nil;
+}
+
+- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    if (self.layoutAttributes.count == 0) {
+        [self prepareLayout];
+    }
+    
+    UICollectionViewLayoutAttributes *attributes = self.layoutAttributes[kMultiColumnLayoutCell][indexPath];
+    WXLogDebug(@"return item attributes:%@ for index path:%@", attributes, indexPath);
+    return attributes;
+}
+
+- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
+{
+    __block BOOL hasStickyHeader = NO;
+    [self.layoutAttributes[kMultiColumnLayoutHeader] enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, UICollectionViewLayoutAttributes * _Nonnull obj, BOOL * _Nonnull stop) {
+        WXMultiColumnLayoutHeaderAttributes *attribute = (WXMultiColumnLayoutHeaderAttributes *)obj;
+        if (attribute.isSticky) {
+            hasStickyHeader = YES;
+            *stop = YES;
+        }
+    }];
+    
+    if (hasStickyHeader) {
+        // always return yes no trigger resetting sticky header's frame.
+        return YES;
+    } else {
+        CGRect oldBounds = self.collectionView.bounds;
+        if (CGRectGetWidth(newBounds) != CGRectGetWidth(oldBounds)) {
+            return YES;
+        }
+    }
+    
+    return NO;
+}
+
+#pragma mark - Private
+
+- (CGFloat)contentWidth
+{
+    return [self.delegate collectionView:self.collectionView contentWidthForLayout:self];
+}
+
+- (CGFloat)contentHeight
+{
+    return [self _maxHeightForAllColumns];
+}
+
+- (void)_computeColumnWidthAndCount
+{
+    UIEdgeInsets insets = [self.delegate collectionView:self.collectionView insetForLayout:self];
+    
+    int columnCount;
+    float columnWidth ;
+    float availableWidth = self.contentWidth - (insets.left + insets.right);
+    computeColumnWidthAndCount(availableWidth, self.columnCount, self.columnWidth, self.columnGap, &columnCount, &columnWidth);
+    if (availableWidth <= 0) {
+        return;
+    }
+    WXAssert(columnCount > 0, @"invalid column count");
+    WXAssert(columnWidth > 0, @"invalid column width");
+    
+    _computedColumnWidth = columnWidth;
+    _computedColumnCount = columnCount;
+}
+
+- (CGFloat)_maxHeightForAllColumns
+{
+    CGFloat maxHeight = 0.0;
+    for (NSNumber *number in self.columnsMaxHeights) {
+        CGFloat height = [number floatValue];
+        if (height > maxHeight) {
+            maxHeight = height;
+        }
+    }
+    
+    return maxHeight;
+}
+
+- (NSUInteger)_minHeightColumnForAllColumns
+{
+    __block NSUInteger index = 0;
+    __block CGFloat minHeight = FLT_MAX;
+    
+    [self.columnsMaxHeights enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        CGFloat height = [obj floatValue];
+        if (height < minHeight) {
+            minHeight = height;
+            index = idx;
+        }
+    }];
+    
+    return index;
+}
+
+- (void)_columnsReachToHeight:(CGFloat)height
+{
+    for (NSInteger i = 0; i < self.columnsMaxHeights.count; i ++) {
+        self.columnsMaxHeights[i] = @(height);
+    }
+}
+
+- (void)_cleanup
+{
+    [self.layoutAttributes removeAllObjects];
+    [self.columnsMaxHeights removeAllObjects];
+}
+
+- (void)_cleanComputed
+{
+    _computedColumnWidth = 0;
+    _computedColumnCount = 0;
+}
+
+- (void)invalidateLayout
+{
+    [super invalidateLayout];
+    
+    [self _cleanComputed];
+}
+
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.h b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.h
new file mode 100644
index 0000000..2b13e4b
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.h
@@ -0,0 +1,12 @@
+/**
+ * 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 <WeexSDK/WeexSDK.h>
+
+@interface WXRecyclerComponent : WXScrollerComponent
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
new file mode 100644
index 0000000..7dffe8c
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
@@ -0,0 +1,525 @@
+/**
+ * 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 "WXRecyclerComponent.h"
+#import "WXComponent_internal.h"
+#import "WXSDKInstance_private.h"
+#import "WXRecyclerDataController.h"
+#import "WXRecyclerUpdateController.h"
+#import "WXMultiColumnLayout.h"
+#import "WXHeaderComponent.h"
+#import "WXFooterComponent.h"
+#import "WXCellComponent.h"
+#import "WXAssert.h"
+#import "WXConvert.h"
+
+static NSString * const kCollectionCellReuseIdentifier = @"WXRecyclerCell";
+static NSString * const kCollectionHeaderReuseIdentifier = @"WXRecyclerHeader";
+static float const kRecyclerNormalColumnGap = 32;
+
+typedef enum : NSUInteger {
+    WXRecyclerLayoutTypeMultiColumn,
+    WXRecyclerLayoutTypeFlex,
+    WXRecyclerLayoutTypeGrid,
+} WXRecyclerLayoutType;
+
+@interface WXCollectionView : UICollectionView
+
+@end
+
+@implementation WXCollectionView
+
+- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index
+{
+    [super insertSubview:view atIndex:index];
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    [self.wx_component layoutDidFinish];
+}
+
+@end
+
+@interface WXCollectionViewCell : UICollectionViewCell
+
+@end
+
+@implementation WXCollectionViewCell
+
+- (void)prepareForReuse
+{
+    [super prepareForReuse];
+
+    WXCellComponent *cellComponent = (WXCellComponent *)self.wx_component;
+    if (cellComponent.isRecycle && [cellComponent isViewLoaded] && [self.contentView.subviews containsObject:cellComponent.view]) {
+        [cellComponent _unloadViewWithReusing:YES];
+    }
+}
+
+@end
+
+@interface WXRecyclerComponent () <UICollectionViewDataSource, UICollectionViewDelegate, WXMultiColumnLayoutDelegate, WXRecyclerUpdateControllerDelegate, WXCellRenderDelegate, WXHeaderRenderDelegate>
+
+@property (nonatomic, strong, readonly) WXRecyclerDataController *dataController;
+@property (nonatomic, strong, readonly) WXRecyclerUpdateController *updateController;
+@property (nonatomic, weak, readonly) UICollectionView *collectionView;
+
+@end
+
+@implementation WXRecyclerComponent
+{
+    WXRecyclerLayoutType _layoutType;
+    UICollectionViewLayout *_collectionViewlayout;
+    
+    UIEdgeInsets _padding;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        [self _fillPadding];
+        
+        if ([type isEqualToString:@"waterfall"] || (attributes[@"layout"] && [attributes[@"layout"] isEqualToString:@"multi-column"])) {
+            // TODO: abstraction
+            _layoutType = WXRecyclerLayoutTypeMultiColumn;
+            CGFloat scaleFactor = weexInstance.pixelScaleFactor;
+            _collectionViewlayout = [WXMultiColumnLayout new];
+            WXMultiColumnLayout *layout = (WXMultiColumnLayout *)_collectionViewlayout;
+            layout.columnWidth = [WXConvert WXLength:attributes[@"columnWidth"] isFloat:YES scaleFactor:scaleFactor] ? : [WXLength lengthWithFloat:0.0 type:WXLengthTypeAuto];
+            layout.columnCount = [WXConvert WXLength:attributes[@"columnCount"] isFloat:NO scaleFactor:1.0] ? : [WXLength lengthWithInt:1 type:WXLengthTypeFixed];
+            layout.columnGap = [self _floatValueForColumnGap:([WXConvert WXLength:attributes[@"columnGap"] isFloat:YES scaleFactor:scaleFactor] ? : [WXLength lengthWithFloat:0.0 type:WXLengthTypeNormal])];
+            
+            layout.delegate = self;
+        }
+        
+        _dataController = [WXRecyclerDataController new];
+        _updateController = [WXRecyclerUpdateController new];
+        _updateController.delegate = self;
+    }
+    
+    return self;
+}
+
+- (void)dealloc
+{
+    _collectionView.delegate = nil;
+    _collectionView.dataSource = nil;
+}
+
+#pragma mark - Public Subclass Methods
+
+- (UIView *)loadView
+{
+    return [[WXCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_collectionViewlayout];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    
+    _collectionView = (UICollectionView *)self.view;
+    _collectionView.allowsSelection = NO;
+    _collectionView.allowsMultipleSelection = NO;
+    _collectionView.dataSource = self;
+    _collectionView.delegate = self;
+    
+    [_collectionView registerClass:[WXCollectionViewCell class] forCellWithReuseIdentifier:kCollectionCellReuseIdentifier];
+    [_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:kCollectionSupplementaryViewKindHeader withReuseIdentifier:kCollectionHeaderReuseIdentifier];
+    
+    [self performUpdatesWithCompletion:^(BOOL finished) {
+        
+    }];
+}
+
+- (void)viewWillUnload
+{
+    [super viewWillUnload];
+    
+    _collectionView.dataSource = nil;
+    _collectionView.delegate = nil;
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    [super updateAttributes:attributes];
+    
+    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
+        CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
+        WXMultiColumnLayout *layout = (WXMultiColumnLayout *)_collectionViewlayout;
+        BOOL needUpdateLayout = NO;
+        if (attributes[@"columnWidth"]) {
+            layout.columnWidth = [WXConvert WXLength:attributes[@"columnWidth"] isFloat:YES scaleFactor:scaleFactor];
+            needUpdateLayout = YES;
+        }
+        
+        if (attributes[@"columnCount"]) {
+            layout.columnCount = [WXConvert WXLength:attributes[@"columnCount"] isFloat:NO scaleFactor:1.0];
+            
+            needUpdateLayout = YES;
+        }
+        if (attributes[@"columnGap"]) {
+            layout.columnGap = [self _floatValueForColumnGap:([WXConvert WXLength:attributes[@"columnGap"] isFloat:YES scaleFactor:scaleFactor])];
+            needUpdateLayout = YES;
+        }
+        
+        if (needUpdateLayout) {
+            for (WXComponent *component in self.subcomponents) {
+                [component setNeedsLayout];
+            }
+            
+            [self.collectionView reloadData];
+            [self.collectionView.collectionViewLayout invalidateLayout];
+        }
+    }
+    
+}
+
+- (void)setContentSize:(CGSize)contentSize
+{
+    // Do Nothing
+}
+
+- (void)adjustSticky
+{
+    // Do Nothing, sticky is adjusted by layout
+}
+
+#pragma mark - Private Subclass Methods
+
+- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles
+{
+    [super _updateStylesOnComponentThread:styles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
+    
+    [self _fillPadding];
+}
+
+- (void)_handleFirstScreenTime
+{
+    // Do Nothing\uff0c firstScreenTime is set by cellDidRendered:
+}
+
+- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset animated:(BOOL)animated
+{
+    [super scrollToComponent:component withOffset:offset animated:animated];
+}
+
+- (void)performUpdatesWithCompletion:(void (^)(BOOL finished))completion
+{
+    WXAssertMainThread();
+    
+    //TODO: support completion
+    
+    if (![self isViewLoaded]) {
+        completion(NO);
+    }
+    
+    NSArray *oldData = [self.dataController.sections copy];
+    NSArray *newData = [self _sectionArrayFromComponents:self.subcomponents];
+    
+    [_updateController performUpdatesWithNewData:newData oldData:oldData view:_collectionView];
+}
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    // TODO: refresh loading fixed
+    if ([subcomponent isKindOfClass:[WXCellComponent class]]) {
+        ((WXCellComponent *)subcomponent).delegate = self;
+    } else if ([subcomponent isKindOfClass:[WXHeaderComponent class]]) {
+        ((WXHeaderComponent *)subcomponent).delegate = self;
+    }
+    
+    [super _insertSubcomponent:subcomponent atIndex:index];
+    
+    if (![subcomponent isKindOfClass:[WXHeaderComponent class]]
+        && ![subcomponent isKindOfClass:[WXCellComponent class]]) {
+        return;
+    }
+    
+    WXPerformBlockOnMainThread(^{
+        [self performUpdatesWithCompletion:^(BOOL finished) {
+    
+        }];
+    });
+}
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    //Here will not insert cell/header/footer's view again
+    if (![subcomponent isKindOfClass:[WXCellComponent class]]
+        && ![subcomponent isKindOfClass:[WXHeaderComponent class]]
+        && ![subcomponent isKindOfClass:[WXFooterComponent class]]) {
+        [super insertSubview:subcomponent atIndex:index];
+    }
+}
+
+#pragma mark - WXRecyclerUpdateControllerDelegate
+
+- (void)updateController:(WXRecyclerUpdateController *)controller willPerformUpdateWithNewData:(NSArray<WXSectionDataController *> *)newData
+{
+    if (newData) {
+        [self.dataController updateData:newData];
+    }
+}
+
+- (void)updateController:(WXRecyclerUpdateController *)controller didPerformUpdateWithFinished:(BOOL)finished
+{
+    
+}
+
+#pragma mark - UICollectionViewDataSource
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
+{
+    WXLogDebug(@"section number:%zi", [self.dataController numberOfSections]);
+    return [self.dataController numberOfSections];
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
+{
+    NSInteger numberOfItems = [self.dataController numberOfItemsInSection:section];
+    
+    WXLogDebug(@"Number of items is %ld in section:%ld", numberOfItems, section);
+    
+    return numberOfItems;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"Getting cell at indexPath:%@", indexPath);
+    
+    WXCollectionViewCell *cellView = [_collectionView dequeueReusableCellWithReuseIdentifier:kCollectionCellReuseIdentifier forIndexPath:indexPath];
+    
+    UIView *contentView = [self.dataController cellForItemAtIndexPath:indexPath];
+    
+    cellView.wx_component = contentView.wx_component;
+    
+    if (contentView.superview == cellView.contentView) {
+        return cellView;
+    }
+    
+    for (UIView *view in cellView.contentView.subviews) {
+        [view removeFromSuperview];
+    }
+    
+    [cellView.contentView addSubview:contentView];
+    
+    return cellView;
+}
+
+- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
+{
+    UICollectionReusableView *reusableView = nil;
+    if ([kind isEqualToString:kCollectionSupplementaryViewKindHeader]) {
+        reusableView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kCollectionHeaderReuseIdentifier forIndexPath:indexPath];
+        UIView *contentView = [self.dataController viewForHeaderAtIndexPath:indexPath];
+        if (contentView.superview != reusableView) {
+            for (UIView *view in reusableView.subviews) {
+                [view removeFromSuperview];
+            }
+
+            [reusableView addSubview:contentView];
+        }
+    }
+    
+    return reusableView;
+}
+
+#pragma mark - UICollectionViewDelegate
+
+- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"will display cell:%@, at index path:%@", cell, indexPath);
+}
+
+- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXLogDebug(@"Did end displaying cell:%@, at index path:%@", cell, indexPath);
+}
+
+#pragma mark - WXMultiColumnLayoutDelegate
+
+- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView insetForLayout:(UICollectionViewLayout *)collectionViewLayout
+{
+    return _padding;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView contentWidthForLayout:(UICollectionViewLayout *)collectionViewLayout
+{
+    return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    CGSize itemSize = [self.dataController sizeForItemAtIndexPath:indexPath];
+    return itemSize.height;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForHeaderInSection:(NSInteger)section
+{
+    CGSize headerSize = [self.dataController sizeForHeaderAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
+    return headerSize.height;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout isNeedStickyForHeaderInSection:(NSInteger)section
+{
+    return [self.dataController isStickyForHeaderAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
+}
+
+#pragma mark - WXHeaderRenderDelegate
+
+- (float)headerWidthForLayout:(WXHeaderComponent *)header
+{
+    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
+        return ((WXMultiColumnLayout *)_collectionViewlayout).computedHeaderWidth;
+    }
+    
+    return 0.0;
+}
+
+- (void)headerDidLayout:(WXHeaderComponent *)header
+{
+    WXPerformBlockOnMainThread(^{
+        [self.collectionView.collectionViewLayout invalidateLayout];
+    });
+}
+
+- (void)headerDidRemove:(WXHeaderComponent *)header
+{
+    WXPerformBlockOnMainThread(^{
+        [self performUpdatesWithCompletion:^(BOOL finished) {
+            
+        }];
+    });
+}
+
+#pragma mark - WXCellRenderDelegate
+
+- (float)containerWidthForLayout:(WXCellComponent *)cell
+{
+    if (_layoutType == WXRecyclerLayoutTypeMultiColumn) {
+        return ((WXMultiColumnLayout *)_collectionViewlayout).computedColumnWidth;
+    }
+    
+    return 0.0;
+}
+
+- (void)cellDidLayout:(WXCellComponent *)cell
+{
+    BOOL previousLayoutComplete = cell.isLayoutComplete;
+    cell.isLayoutComplete = YES;
+    WXPerformBlockOnMainThread(^{
+        if (previousLayoutComplete) {
+            [self.updateController reloadItemsAtIndexPath:[self.dataController indexPathForCell:cell]];
+        } else {
+            [self performUpdatesWithCompletion:^(BOOL finished) {
+            }];
+        }
+    });
+}
+
+- (void)cellDidRendered:(WXCellComponent *)cell
+{
+    
+}
+
+- (void)cellDidRemove:(WXCellComponent *)cell
+{
+    if (cell.isLayoutComplete) {
+        WXPerformBlockOnMainThread(^{
+            [self performUpdatesWithCompletion:^(BOOL finished) {
+            }];
+        });
+    }
+}
+
+- (void)cell:(WXCellComponent *)cell didMoveToIndex:(NSUInteger)index
+{
+    if (cell.isLayoutComplete) {
+        WXPerformBlockOnMainThread(^{
+            [self performUpdatesWithCompletion:^(BOOL finished) {
+            }];
+        });
+    }
+}
+
+#pragma makrk - private
+
+- (float)_floatValueForColumnGap:(WXLength *)gap
+{
+    if (gap.isNormal) {
+        return kRecyclerNormalColumnGap * self.weexInstance.pixelScaleFactor;
+    } else {
+        return gap.floatValue;
+    }
+}
+
+- (void)_fillPadding
+{
+    UIEdgeInsets padding = {
+        WXFloorPixelValue(self.cssNode->style.padding[CSS_TOP] + self.cssNode->style.border[CSS_TOP]),
+        WXFloorPixelValue(self.cssNode->style.padding[CSS_LEFT] + self.cssNode->style.border[CSS_LEFT]),
+        WXFloorPixelValue(self.cssNode->style.padding[CSS_BOTTOM] + self.cssNode->style.border[CSS_BOTTOM]),
+        WXFloorPixelValue(self.cssNode->style.padding[CSS_RIGHT] + self.cssNode->style.border[CSS_RIGHT])
+    };
+    
+    if (!UIEdgeInsetsEqualToEdgeInsets(padding, _padding)) {
+        _padding = padding;
+        [self setNeedsLayout];
+        
+        for (WXComponent *component in self.subcomponents) {
+            [component setNeedsLayout];
+        }
+        
+        if (_collectionView) {
+            WXPerformBlockOnMainThread(^{
+                [_collectionView.collectionViewLayout invalidateLayout];
+            });
+        }
+    }
+}
+
+- (NSArray<WXSectionDataController *> *)_sectionArrayFromComponents:(NSArray<WXComponent *> *)components
+{
+    NSMutableArray<WXSectionDataController *> *sectionArray = [NSMutableArray array];
+    NSMutableArray<WXCellComponent *> *cellArray = [NSMutableArray array];
+    WXSectionDataController *currentSection;
+    
+    for (int i = 0; i < components.count; i++) {
+        if (!currentSection) {
+            currentSection = [WXSectionDataController new];
+        }
+        
+        WXComponent* component = components[i];
+        
+        if ([component isKindOfClass:[WXHeaderComponent class]]) {
+            if (i != 0) {
+                currentSection.cellComponents = [cellArray copy];
+                [sectionArray addObject:currentSection];
+                currentSection = [WXSectionDataController new];
+                [cellArray removeAllObjects];
+            }
+            currentSection.headerComponent = (WXHeaderComponent *)component;
+        } else if ([component isKindOfClass:[WXCellComponent class]]
+                   && ((WXCellComponent *)component).isLayoutComplete) {
+            [cellArray addObject:(WXCellComponent *)component];
+        } else if ([component isKindOfClass:[WXFooterComponent class]]) {
+            currentSection.footerComponent = component;
+        }
+        
+        if (i == components.count - 1 && cellArray.count > 0) {
+            currentSection.cellComponents = [cellArray copy];
+            [sectionArray addObject:currentSection];
+        }
+    }
+    
+    return sectionArray;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.h b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.h
new file mode 100644
index 0000000..3b85155
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.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 <Foundation/Foundation.h>
+#import "WXSectionDataController.h"
+
+@interface WXRecyclerDataController : NSObject
+
+@property (nonatomic, strong, readonly) NSArray<WXSectionDataController *> *sections;
+
+- (void)updateData:(NSArray<WXSectionDataController *> *)newData;
+
+- (NSInteger)numberOfSections;
+
+- (NSInteger)numberOfItemsInSection:(NSInteger)section;
+
+- (UIView *)cellForItemAtIndexPath:(NSIndexPath *)indexPath;
+
+- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
+
+- (UIView *)viewForHeaderAtIndexPath:(NSIndexPath *)indexPath;
+
+- (CGSize)sizeForHeaderAtIndexPath:(NSIndexPath *)indexPath;
+
+- (BOOL)isStickyForHeaderAtIndexPath:(NSIndexPath *)indexPath;
+
+- (NSIndexPath *)indexPathForCell:(WXCellComponent *)cell;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.m b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.m
new file mode 100644
index 0000000..aa5732d
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerDataController.m
@@ -0,0 +1,114 @@
+/**
+ * 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 "WXRecyclerDataController.h"
+#import "WXCellComponent.h"
+#import "NSArray+Weex.h"
+#import "WXAssert.h"
+
+@interface WXRecyclerDataController ()
+
+@property (nonatomic, strong, readwrite) NSArray<WXSectionDataController *> *sections;
+@property (nonatomic, strong, readonly) NSMapTable<WXCellComponent *, NSIndexPath*> *cellToIndexPathTable;
+
+@end
+
+@implementation WXRecyclerDataController
+
+- (instancetype)init
+{
+    if (self = [super init]) {
+        _sections = [NSArray new];
+        _cellToIndexPathTable = [NSMapTable weakToStrongObjectsMapTable];
+    }
+    
+    return self;
+}
+
+#pragma mark - Public
+
+- (void)updateData:(NSArray<WXSectionDataController *> *)newData
+{
+    WXAssertMainThread();
+    
+    [self cleanup];
+    _sections = [newData copy];
+    
+    [newData enumerateObjectsUsingBlock:^(WXSectionDataController * _Nonnull controller, NSUInteger idx, BOOL * _Nonnull stop) {
+        [controller.cellComponents enumerateObjectsUsingBlock:^(WXCellComponent * _Nonnull obj, NSUInteger idx2, BOOL * _Nonnull stop) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:idx2 inSection:idx];
+            [_cellToIndexPathTable setObject:indexPath forKey:obj];
+        }];
+    }];
+}
+
+- (NSInteger)numberOfSections
+{
+    WXAssertMainThread();
+    return self.sections.count;
+}
+
+- (NSInteger)numberOfItemsInSection:(NSInteger)section
+{
+    WXSectionDataController *sectionController = [self dataControllerForSection:section];
+    WXAssert(sectionController, @"No section controller found for section:%ld", section);
+    
+    return [sectionController numberOfItems];
+}
+
+- (UIView *)cellForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXSectionDataController *sectionController = [self dataControllerForSection:indexPath.section];
+    UIView *contentView = [sectionController cellForItemAtIndex:indexPath.item];
+    
+    return contentView;
+}
+
+- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXSectionDataController *sectionController = [self dataControllerForSection:indexPath.section];
+    return [sectionController sizeForItemAtIndex:indexPath.item];
+}
+
+- (UIView *)viewForHeaderAtIndexPath:(NSIndexPath *)indexPath;
+{
+    WXSectionDataController *sectionController = [self dataControllerForSection:indexPath.section];
+    return [sectionController viewForHeaderAtIndex:indexPath.item];
+}
+
+- (CGSize)sizeForHeaderAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXSectionDataController *sectionController = [self dataControllerForSection:indexPath.section];
+    return [sectionController sizeForHeaderAtIndex:indexPath.item];
+}
+
+- (BOOL)isStickyForHeaderAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXSectionDataController *sectionController = [self dataControllerForSection:indexPath.section];
+    return [sectionController isStickyForHeaderAtIndex:indexPath.item];
+}
+
+- (NSIndexPath *)indexPathForCell:(WXCellComponent *)cell
+{
+    return [_cellToIndexPathTable objectForKey:cell];
+}
+
+#pragma mark - Private
+
+- (WXSectionDataController *)dataControllerForSection:(NSInteger)section
+{
+    WXAssertMainThread();
+    return [self.sections wx_safeObjectAtIndex:section];
+}
+
+- (void)cleanup
+{
+    [_cellToIndexPathTable removeAllObjects];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.h b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.h
new file mode 100644
index 0000000..e376c19
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.h
@@ -0,0 +1,32 @@
+/**
+ * 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 "WXSectionDataController.h"
+@class WXRecyclerUpdateController;
+
+@protocol WXRecyclerUpdateControllerDelegate <NSObject>
+
+- (void)updateController:(WXRecyclerUpdateController *)controller willPerformUpdateWithNewData:(NSArray<WXSectionDataController *> *)newData;
+
+- (void)updateController:(WXRecyclerUpdateController *)controller didPerformUpdateWithFinished:(BOOL)finished;
+
+@end
+
+@interface WXRecyclerUpdateController : NSObject
+
+@property (nonatomic, weak) id<WXRecyclerUpdateControllerDelegate> delegate;
+
+- (void)performUpdatesWithNewData:(NSArray<WXSectionDataController *> *)newData
+                          oldData:(NSArray<WXSectionDataController *> *)oldData
+                             view:(UICollectionView *)collectionView;
+
+- (void)reloadItemsAtIndexPath:(NSIndexPath *)indexPath;
+
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.m b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.m
new file mode 100644
index 0000000..31c9dd0
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerUpdateController.m
@@ -0,0 +1,248 @@
+/**
+ * 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 "WXRecyclerUpdateController.h"
+#import "WXCellComponent.h"
+#import "WXAssert.h"
+#import "WXLog.h"
+#import "WXDiffUtil.h"
+#import "NSArray+Weex.h"
+
+@interface WXRecyclerDiffResult : NSObject
+
+@property (nonatomic, strong, readonly) NSIndexSet *insertSections;
+@property (nonatomic, strong, readonly) NSIndexSet *deleteSections;
+@property (nonatomic, strong, readonly) NSIndexSet *reloadSections;
+
+@property (nonatomic, strong, readonly) NSMutableSet<NSIndexPath *> *deleteIndexPaths;
+@property (nonatomic, strong, readonly) NSMutableSet<NSIndexPath *> *insertIndexPaths;
+@property (nonatomic, strong, readonly) NSMutableSet<NSIndexPath *> *reloadIndexPaths;
+
+- (BOOL)hasChanges;
+
+@end
+
+@implementation WXRecyclerDiffResult
+
+- (instancetype)initWithInsertSections:(NSIndexSet *)insertSections
+                        deleteSections:(NSIndexSet *)deletesSections
+                        reloadSections:(NSIndexSet *)reloadSections
+                      insertIndexPaths:(NSMutableSet<NSIndexPath *> *)insertIndexPaths
+                      deleteIndexPaths:(NSMutableSet<NSIndexPath *> *)deleteIndexPaths
+                      reloadIndexPaths:(NSMutableSet<NSIndexPath *> *)reloadIndexPaths
+{
+    if (self = [super init]) {
+        _insertSections = [insertSections copy];
+        _deleteSections = [deletesSections copy];
+        _reloadSections = [reloadSections copy];
+        _insertIndexPaths = [insertIndexPaths copy];
+        _deleteIndexPaths = [deleteIndexPaths copy];
+        _reloadIndexPaths = [reloadIndexPaths copy];
+    }
+    
+    return self;
+}
+
+- (BOOL)hasChanges
+{
+    return _insertSections.count > 0 || _deleteSections.count > 0 || _reloadSections.count > 0 || _insertIndexPaths.count > 0 || _deleteIndexPaths.count > 0 || _reloadIndexPaths.count > 0;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: %p; insert sections: %@; delete sections: %@; reload sections: %@; insert index paths: %@; delete index paths: %@; reload index paths: %@", NSStringFromClass([self class]), self,_insertSections, _deleteSections, _reloadSections, _insertIndexPaths, _deleteIndexPaths, _reloadIndexPaths];
+}
+
+@end
+
+@interface WXRecyclerUpdateController ()
+
+@property (nonatomic, copy) NSArray<WXSectionDataController *> *theNewData;
+@property (nonatomic, copy) NSArray<WXSectionDataController *> *theOldData;
+@property (nonatomic, weak) UICollectionView *collectionView;
+@property (nonatomic, strong) NSMutableSet<NSIndexPath *> *reloadIndexPaths;
+@property (nonatomic, assign) BOOL isUpdating;
+
+@end
+
+@implementation WXRecyclerUpdateController
+
+- (void)performUpdatesWithNewData:(NSArray<WXSectionDataController *> *)newData oldData:(NSArray<WXSectionDataController *> *)oldData view:(UICollectionView *)collectionView
+{
+    if (!collectionView) {
+        return;
+    }
+    
+    self.theNewData = newData;
+    self.theOldData = oldData;
+    self.collectionView = collectionView;
+    
+    [self checkUpdates];
+}
+
+- (void)reloadItemsAtIndexPath:(NSIndexPath *)indexPath
+{
+    if (!indexPath) {
+        return;
+    }
+    
+    if (!_reloadIndexPaths) {
+        _reloadIndexPaths = [NSMutableSet set];
+    }
+    
+    [_reloadIndexPaths addObject:indexPath];
+    
+    [self checkUpdates];
+}
+
+- (void)checkUpdates
+{
+    dispatch_async(dispatch_get_main_queue(), ^{
+        if (self.isUpdating) {
+            return ;
+        }
+        
+        [self performBatchUpdates];
+    });
+}
+
+- (void)performBatchUpdates
+{
+    WXAssertMainThread();
+    WXAssert(!self.isUpdating, @"Can not perform updates while an updating is being performed");
+    
+    UICollectionView *collectionView = self.collectionView;
+    if (!collectionView) {
+        return;
+    }
+    
+    NSArray<WXSectionDataController *> *newData = [self.theNewData copy];
+    NSArray<WXSectionDataController *> *oldData = [self.theOldData copy];
+
+    [self cleanup];
+    
+    WXRecyclerDiffResult *diffResult = [self diffWithNewData:newData oldData:oldData];
+    if (![diffResult hasChanges] && self.reloadIndexPaths.count == 0) {
+        return;
+    }
+    
+    void (^updates)() = ^{
+        [UIView setAnimationsEnabled:NO];
+        WXLogDebug(@"UICollectionView update:%@", diffResult);
+        [self applyUpdate:diffResult toCollectionView:self.collectionView];
+    };
+    
+    void (^completion)(BOOL) = ^(BOOL finished) {
+        [UIView setAnimationsEnabled:YES];
+        self.isUpdating = NO;
+        [self.delegate updateController:self didPerformUpdateWithFinished:finished];
+        [self.reloadIndexPaths removeAllObjects];
+        [self checkUpdates];
+    };
+    
+    self.isUpdating = YES;
+    
+    if (!self.delegate) {
+        return;
+    }
+    
+    [self.delegate updateController:self willPerformUpdateWithNewData:newData];
+    
+    NSLog(@"Diff result:%@", diffResult);
+    [collectionView performBatchUpdates:updates completion:completion];
+}
+
+- (void)cleanup
+{
+    self.theNewData = nil;
+    self.theOldData = nil;
+}
+
+- (WXRecyclerDiffResult *)diffWithNewData:(NSArray<WXSectionDataController *> *)newData
+                              oldData:(NSArray<WXSectionDataController *> *)oldData
+{
+    NSMutableIndexSet *reloadSections = [NSMutableIndexSet indexSet];
+    NSMutableSet<NSIndexPath *> *reloadIndexPaths = [NSMutableSet set];
+    NSMutableSet<NSIndexPath *> *deleteIndexPaths = [NSMutableSet set];
+    NSMutableSet<NSIndexPath *> *insertIndexPaths = [NSMutableSet set];
+    
+    WXDiffResult *sectionDiffResult = [WXDiffUtil diffWithMinimumDistance:newData oldArray:oldData];
+    
+    WXLogDebug(@"section diff result:%@", sectionDiffResult);
+    
+    [sectionDiffResult.inserts enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
+        WXSectionDataController *newSection = [newData wx_safeObjectAtIndex:idx];
+        [newSection.cellComponents enumerateObjectsUsingBlock:^(WXCellComponent * _Nonnull obj, NSUInteger idx2, BOOL * _Nonnull stop) {
+            if (obj.isLayoutComplete) {
+                NSIndexPath *insertIndexPath = [NSIndexPath indexPathForItem:idx2 inSection:idx];
+                [insertIndexPaths addObject:insertIndexPath];
+            }
+        }];
+        WXAssert(newSection, @"No section found in  new index:%ld");
+    }];
+    
+    for (WXDiffUpdateIndex *sectionUpdate in sectionDiffResult.updates) {
+        WXSectionDataController *oldSection = [oldData wx_safeObjectAtIndex:sectionUpdate.oldIndex];
+        WXSectionDataController *newSection = [newData wx_safeObjectAtIndex:sectionUpdate.newIndex];
+        WXAssert(newSection && oldSection, @"No section found in old index:%ld, new index:%ld", sectionUpdate.oldIndex, sectionUpdate.newIndex);
+        
+        WXDiffResult *itemDiffResult = [WXDiffUtil diffWithMinimumDistance:newSection.cellComponents oldArray:oldSection.cellComponents];
+        if (![itemDiffResult hasChanges]) {
+            // header or footer need to be updated
+            [reloadSections addIndex:sectionUpdate.oldIndex];
+        } else {
+            for (WXDiffUpdateIndex *update in itemDiffResult.updates) {
+                NSIndexPath *reloadIndexPath = [NSIndexPath indexPathForItem:update.oldIndex inSection:sectionUpdate.oldIndex];
+                [reloadIndexPaths addObject:reloadIndexPath];
+            }
+            
+            [itemDiffResult.inserts enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
+                WXCellComponent *cell = [newSection.cellComponents wx_safeObjectAtIndex:idx];
+                if (cell.isLayoutComplete) {
+                    NSIndexPath *insertIndexPath = [NSIndexPath indexPathForItem:idx inSection:sectionUpdate.oldIndex];
+                    [insertIndexPaths addObject:insertIndexPath];
+                }
+            }];
+            
+            [itemDiffResult.deletes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
+                NSIndexPath *deleteIndexPath = [NSIndexPath indexPathForItem:idx inSection:sectionUpdate.oldIndex];
+                [deleteIndexPaths addObject:deleteIndexPath];
+            }];
+        }
+        
+    }
+    
+    WXRecyclerDiffResult *result = [[WXRecyclerDiffResult alloc] initWithInsertSections:sectionDiffResult.inserts
+                                                                 deleteSections:sectionDiffResult.deletes
+                                                                 reloadSections:reloadSections
+                                                               insertIndexPaths:insertIndexPaths
+                                                               deleteIndexPaths:deleteIndexPaths
+                                                               reloadIndexPaths:reloadIndexPaths];
+    
+    return result;
+}
+
+- (void)applyUpdate:(WXRecyclerDiffResult *)diffResult toCollectionView:(UICollectionView *)collectionView
+{
+    if (!collectionView) {
+        return;
+    }
+    
+    [collectionView deleteItemsAtIndexPaths:[diffResult.deleteIndexPaths allObjects]];
+    [collectionView insertItemsAtIndexPaths:[diffResult.insertIndexPaths allObjects]];
+    
+    NSSet *reloadIndexPaths = self.reloadIndexPaths ? [diffResult.reloadIndexPaths setByAddingObjectsFromSet:self.reloadIndexPaths] : diffResult.reloadIndexPaths;
+    
+    [collectionView reloadItemsAtIndexPaths:[reloadIndexPaths allObjects]];
+    
+    [collectionView deleteSections:diffResult.deleteSections];
+    [collectionView insertSections:diffResult.insertSections];
+    [collectionView reloadSections:diffResult.reloadSections];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXSectionDataController.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXSectionDataController.h b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXSectionDataController.h
new file mode 100644
index 0000000..ae257b3
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXSectionDataController.h
@@ -0,0 +1,33 @@
+/**
+ * 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 "WXDiffUtil.h"
+@class WXComponent;
+@class WXCellComponent;
+@class WXHeaderComponent;
+
+@interface WXSectionDataController : NSObject <WXDiffable>
+
+@property (nonatomic, strong) NSArray<WXCellComponent *> *cellComponents;
+@property (nonatomic, strong) WXHeaderComponent *headerComponent;
+@property (nonatomic, strong) WXComponent *footerComponent;
+
+- (NSInteger)numberOfItems;
+
+- (UIView *)cellForItemAtIndex:(NSInteger)index;
+
+- (CGSize)sizeForItemAtIndex:(NSInteger)index;
+
+- (UIView *)viewForHeaderAtIndex:(NSInteger)index;
+
+- (CGSize)sizeForHeaderAtIndex:(NSInteger)index;
+
+- (BOOL)isStickyForHeaderAtIndex:(NSInteger)index;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/Recycler/WXSectionDataController.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXSectionDataController.m b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXSectionDataController.m
new file mode 100644
index 0000000..8aaa031
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXSectionDataController.m
@@ -0,0 +1,81 @@
+/**
+ * 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 "WXSectionDataController.h"
+#import "WXCellComponent.h"
+#import "WXHeaderComponent.h"
+#import "WXAssert.h"
+
+@implementation WXSectionDataController
+
+- (NSInteger)numberOfItems
+{
+    return self.cellComponents.count;
+}
+
+- (UIView *)cellForItemAtIndex:(NSInteger)index
+{
+    WXAssertMainThread();
+    
+    WXCellComponent *cellComponent = self.cellComponents[index];
+    return cellComponent.view;
+}
+
+- (CGSize)sizeForItemAtIndex:(NSInteger)index
+{
+    WXAssertMainThread();
+    
+    WXCellComponent *cellComponent = self.cellComponents[index];
+    return cellComponent.calculatedFrame.size;
+}
+
+- (UIView *)viewForHeaderAtIndex:(NSInteger)index;
+{
+    return self.headerComponent.view;
+}
+
+- (CGSize)sizeForHeaderAtIndex:(NSInteger)index
+{
+    return self.headerComponent.calculatedFrame.size;
+}
+
+- (BOOL)isStickyForHeaderAtIndex:(NSInteger)index
+{
+    return self.headerComponent.isSticky;
+}
+
+- (NSUInteger)hash
+{
+    return [super hash];
+}
+
+- (BOOL)isEqualToWXObject:(id<WXDiffable>)object
+{
+    if ([object isKindOfClass:[WXSectionDataController class]]) {
+        WXSectionDataController *controller = (WXSectionDataController *)object;
+        BOOL headerEqual = (self.headerComponent && controller.headerComponent && self.headerComponent == controller.headerComponent) || (!self.headerComponent && !controller.headerComponent);
+        BOOL footerEqual = (self.footerComponent && controller.footerComponent && self.footerComponent == controller.footerComponent) || (!self.footerComponent && !controller.footerComponent);
+        BOOL cellEqual = self.cellComponents && controller.cellComponents && self.cellComponents.count == controller.cellComponents.count;
+        if (cellEqual) {
+            for (int i = 0; i < self.cellComponents.count; i ++) {
+                if (self.cellComponents[i] != controller.cellComponents[i]) {
+                    cellEqual = NO;
+                    break;
+                }
+            }
+        } else {
+            cellEqual = !self.cellComponents && controller.cellComponents;
+        }
+        
+        return headerEqual && footerEqual && cellEqual;
+    } else {
+        return NO;
+    }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
index 2c40cd8..aff5ab1 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
@@ -7,15 +7,31 @@
  */
 
 #import "WXComponent.h"
-@class WXListComponent;
+#import "WXDiffUtil.h"
+@class WXCellComponent;
 
-@interface WXCellComponent : WXComponent
+@protocol WXCellRenderDelegate <NSObject>
+
+- (float)containerWidthForLayout:(WXCellComponent *)cell;
+
+- (void)cellDidLayout:(WXCellComponent *)cell;
+
+- (void)cellDidRendered:(WXCellComponent *)cell;
+
+- (void)cellDidRemove:(WXCellComponent *)cell;
+
+- (void)cell:(WXCellComponent *)cell didMoveToIndex:(NSUInteger)index;
+
+@end
+
+@interface WXCellComponent : WXComponent <WXDiffable>
 
 @property (nonatomic, strong) NSString *scope;
 @property (nonatomic, assign) BOOL isRecycle;
+@property (nonatomic, assign) BOOL isLayoutComplete;
 @property (nonatomic, assign) UITableViewRowAnimation insertAnimation;
 @property (nonatomic, assign) UITableViewRowAnimation deleteAnimation;
-@property (nonatomic, weak) WXListComponent *list;
 @property (nonatomic, assign) BOOL keepScrollPosition;
+@property (nonatomic, weak) id<WXCellRenderDelegate> delegate;
 
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
index 3c35a0b..24a5a1d 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
@@ -11,10 +11,16 @@
 #import "WXCellComponent.h"
 #import "WXListComponent.h"
 #import "WXComponent_internal.h"
+#import "WXDiffUtil.h"
+
+@interface WXCellComponent ()
+
+@end
 
 @implementation WXCellComponent
 {
     NSIndexPath *_indexPathBeforeMove;
+    BOOL _isUseContainerWidth;
 }
 
 - (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
@@ -39,12 +45,17 @@
     
 }
 
+- (BOOL)isEqualToWXObject:(id<WXDiffable>)object
+{
+    return self == object;
+}
+
 - (void)_frameDidCalculated:(BOOL)isChanged
 {
     [super _frameDidCalculated:isChanged];
     
     if (isChanged) {
-        [self.list cellDidLayout:self];
+        [self.delegate cellDidLayout:self];
     }
 }
 
@@ -55,7 +66,7 @@
             [super displayCompletionBlock](layer, finished);
         }
         
-        [self.list cellDidRendered:self];
+        [self.delegate cellDidRendered:self];
     };
 }
 
@@ -84,8 +95,8 @@
 
 - (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
 {
-    if (self.list == newSupercomponent) {
-        [self.list cell:self didMoveToIndex:index];
+    if (self.delegate == newSupercomponent) {
+        [self.delegate cell:self didMoveToIndex:index];
         [super _removeFromSupercomponent];
         [newSupercomponent _insertSubcomponent:self atIndex:index];
     } else {
@@ -97,7 +108,7 @@
 {
     [super _removeFromSupercomponent];
     
-    [self.list cellDidRemove:self];
+    [self.delegate cellDidRemove:self];
 }
 
 - (void)removeFromSuperview
@@ -107,8 +118,10 @@
 
 - (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
 {
-    if (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) && self.list) {
-        self.cssNode->style.dimensions[CSS_WIDTH] = self.list.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+    if (self.delegate && (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) || _isUseContainerWidth)) {
+        self.cssNode->style.dimensions[CSS_WIDTH] = [self.delegate containerWidthForLayout:self];
+        //TODO: set _isUseContainerWidth to NO if updateStyles have width
+        _isUseContainerWidth = YES;
     }
     
     if ([self needsLayout]) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.h b/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.h
index 0706eed..92b7596 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.h
+++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.h
@@ -1,10 +1,11 @@
-//
-//  WXComponent+GradientColor.h
-//  Pods
-//
-//  Created by bobning on 16/12/23.
-//
-//
+/**
+ * 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>

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.m b/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.m
index e710ed0..86c3379 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent+GradientColor.m
@@ -1,10 +1,11 @@
-//
-//  WXComponent+GradientColor.m
-//  Pods
-//
-//  Created by bobning on 16/12/23.
-//
-//
+/**
+ * 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+GradientColor.h"
 #import "WXComponent_internal.h"

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXFooterComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXFooterComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXFooterComponent.h
new file mode 100644
index 0000000..e9c801c
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXFooterComponent.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 <WeexSDK/WeexSDK.h>
+
+@interface WXFooterComponent : WXComponent
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXFooterComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXFooterComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXFooterComponent.m
new file mode 100644
index 0000000..f139eaf
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXFooterComponent.m
@@ -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 "WXFooterComponent.h"
+
+@implementation WXFooterComponent
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.h
new file mode 100644
index 0000000..1ac21cc
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXHeaderComponent.h
@@ -0,0 +1,27 @@
+/**
+ * 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 <WeexSDK/WeexSDK.h>
+@class WXHeaderComponent;
+
+@protocol WXHeaderRenderDelegate <NSObject>
+
+- (float)headerWidthForLayout:(WXHeaderComponent *)header;
+
+- (void)headerDidLayout:(WXHeaderComponent *)header;
+
+- (void)headerDidRemove:(WXHeaderComponent *)header;
+
+@end
+
+@interface WXHeaderComponent : WXComponent
+
+@property (nonatomic, weak) id<WXHeaderRenderDelegate> delegate;
+@property (nonatomic, assign, readonly) BOOL isSticky;
+
+@end

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

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
index 007f502..2497c3b 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
+++ b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
@@ -8,18 +8,6 @@
 
 #import "WXScrollerComponent.h"
 
-@class WXCellComponent;
-@class WXHeaderComponent;
 @interface WXListComponent : WXScrollerComponent
 
-- (void)cellDidRemove:(WXCellComponent *)cell;
-
-- (void)cellDidLayout:(WXCellComponent *)cell;
-
-- (void)headerDidLayout:(WXHeaderComponent *)header;
-
-- (void)cellDidRendered:(WXCellComponent *)cell;
-
-- (void)cell:(WXCellComponent *)cell didMoveToIndex:(NSUInteger)index;
-
 @end