From 22855c9ca1a5409c737c5c815c934bfdd5016538 Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Thu, 27 Nov 2014 12:27:42 +1030 Subject: [PATCH 01/31] deleted tests target to make the project build --- .../project.pbxproj | 122 ------------------ 1 file changed, 122 deletions(-) diff --git a/WKPagesCollectionView.xcodeproj/project.pbxproj b/WKPagesCollectionView.xcodeproj/project.pbxproj index 22f2173..956188e 100644 --- a/WKPagesCollectionView.xcodeproj/project.pbxproj +++ b/WKPagesCollectionView.xcodeproj/project.pbxproj @@ -20,22 +20,9 @@ 68D7C1E618347A08006B418C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 68D7C1E418347A08006B418C /* Main.storyboard */; }; 68D7C1E918347A08006B418C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68D7C1E818347A08006B418C /* ViewController.m */; }; 68D7C1EB18347A08006B418C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 68D7C1EA18347A08006B418C /* Images.xcassets */; }; - 68D7C1F218347A08006B418C /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68D7C1F118347A08006B418C /* XCTest.framework */; }; - 68D7C1F318347A08006B418C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68D7C1D218347A08006B418C /* Foundation.framework */; }; - 68D7C1F418347A08006B418C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68D7C1D618347A08006B418C /* UIKit.framework */; }; 68D7C20E18349B4C006B418C /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68D7C20D18349B4C006B418C /* QuartzCore.framework */; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - 68D7C1F518347A08006B418C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 68D7C1C718347A08006B418C /* Project object */; - proxyType = 1; - remoteGlobalIDString = 68D7C1CE18347A08006B418C; - remoteInfo = WKPagesScrollView; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXFileReference section */ 68A1CF26184CD0DB00346DF8 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = SOURCE_ROOT; }; 68BDCE7518432CCA00DB81A2 /* WK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WK.h; sourceTree = ""; }; @@ -59,7 +46,6 @@ 68D7C1E718347A08006B418C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 68D7C1E818347A08006B418C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 68D7C1EA18347A08006B418C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 68D7C1F018347A08006B418C /* WKPagesCollectionViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WKPagesCollectionViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68D7C1F118347A08006B418C /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 68D7C20D18349B4C006B418C /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ @@ -76,16 +62,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 68D7C1ED18347A08006B418C /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 68D7C1F218347A08006B418C /* XCTest.framework in Frameworks */, - 68D7C1F418347A08006B418C /* UIKit.framework in Frameworks */, - 68D7C1F318347A08006B418C /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -116,7 +92,6 @@ isa = PBXGroup; children = ( 68D7C1CF18347A08006B418C /* WKPagesCollectionView.app */, - 68D7C1F018347A08006B418C /* WKPagesCollectionViewTests.xctest */, ); name = Products; sourceTree = ""; @@ -181,24 +156,6 @@ productReference = 68D7C1CF18347A08006B418C /* WKPagesCollectionView.app */; productType = "com.apple.product-type.application"; }; - 68D7C1EF18347A08006B418C /* WKPagesCollectionViewTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 68D7C20418347A08006B418C /* Build configuration list for PBXNativeTarget "WKPagesCollectionViewTests" */; - buildPhases = ( - 68D7C1EC18347A08006B418C /* Sources */, - 68D7C1ED18347A08006B418C /* Frameworks */, - 68D7C1EE18347A08006B418C /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 68D7C1F618347A08006B418C /* PBXTargetDependency */, - ); - name = WKPagesCollectionViewTests; - productName = WKPagesScrollViewTests; - productReference = 68D7C1F018347A08006B418C /* WKPagesCollectionViewTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -207,11 +164,6 @@ attributes = { LastUpgradeCheck = 0500; ORGANIZATIONNAME = "秦 道平"; - TargetAttributes = { - 68D7C1EF18347A08006B418C = { - TestTargetID = 68D7C1CE18347A08006B418C; - }; - }; }; buildConfigurationList = 68D7C1CA18347A08006B418C /* Build configuration list for PBXProject "WKPagesCollectionView" */; compatibilityVersion = "Xcode 3.2"; @@ -227,7 +179,6 @@ projectRoot = ""; targets = ( 68D7C1CE18347A08006B418C /* WKPagesCollectionView */, - 68D7C1EF18347A08006B418C /* WKPagesCollectionViewTests */, ); }; /* End PBXProject section */ @@ -244,13 +195,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 68D7C1EE18347A08006B418C /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -267,23 +211,8 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 68D7C1EC18347A08006B418C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - 68D7C1F618347A08006B418C /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 68D7C1CE18347A08006B418C /* WKPagesCollectionView */; - targetProxy = 68D7C1F518347A08006B418C /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin PBXVariantGroup section */ 68D7C1DB18347A08006B418C /* InfoPlist.strings */ = { isa = PBXVariantGroup; @@ -404,48 +333,6 @@ }; name = Release; }; - 68D7C20518347A08006B418C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/WKPagesScrollView.app/WKPagesScrollView"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - "$(DEVELOPER_FRAMEWORKS_DIR)", - ); - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "WKPagesScrollView/WKPagesScrollView-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = "WKPagesScrollViewTests/WKPagesScrollViewTests-Info.plist"; - PRODUCT_NAME = WKPagesCollectionViewTests; - TEST_HOST = "$(BUNDLE_LOADER)"; - WRAPPER_EXTENSION = xctest; - }; - name = Debug; - }; - 68D7C20618347A08006B418C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/WKPagesScrollView.app/WKPagesScrollView"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - "$(DEVELOPER_FRAMEWORKS_DIR)", - ); - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "WKPagesScrollView/WKPagesScrollView-Prefix.pch"; - INFOPLIST_FILE = "WKPagesScrollViewTests/WKPagesScrollViewTests-Info.plist"; - PRODUCT_NAME = WKPagesCollectionViewTests; - TEST_HOST = "$(BUNDLE_LOADER)"; - WRAPPER_EXTENSION = xctest; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -467,15 +354,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 68D7C20418347A08006B418C /* Build configuration list for PBXNativeTarget "WKPagesCollectionViewTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 68D7C20518347A08006B418C /* Debug */, - 68D7C20618347A08006B418C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 68D7C1C718347A08006B418C /* Project object */; From 8571c9dd202c51e5ebaa99c9e12ef68bcdc980c6 Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Thu, 27 Nov 2014 12:42:38 +1030 Subject: [PATCH 02/31] silenced compiler warnings with some changes to int types --- .../WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m index df1ccdc..18b2082 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m @@ -36,7 +36,7 @@ -(CGFloat)pageHeight{ } -(CGSize)collectionViewContentSize{ - int numberOfItems=[self.collectionView numberOfItemsInSection:0]; + NSInteger numberOfItems=[self.collectionView numberOfItemsInSection:0]; // CGFloat topMargin=[(WKPagesCollectionView*)self.collectionView topOffScreenMargin]; CGFloat contentHeight=numberOfItems*self.pageHeight+self.self.minimumLineSpacing*(numberOfItems-1); contentHeight=fmaxf(contentHeight, self.collectionView.frame.size.height); @@ -96,7 +96,7 @@ -(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtInd return attributes; } -(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ - NSLog(@"finalLayoutAttributesForDisappearingItemAtIndexPath:%d",itemIndexPath.row); + NSLog(@"finalLayoutAttributesForDisappearingItemAtIndexPath:%ld",(long)itemIndexPath.row); UICollectionViewLayoutAttributes* attributes=[super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath]; if ([self.deleteIndexPaths containsObject:itemIndexPath]){ if (!attributes){ From d46d91a1055646ca1171c0ede10af8ab027bd4a8 Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Thu, 27 Nov 2014 13:03:36 +1030 Subject: [PATCH 03/31] updated Xcode project settings --- WKPagesCollectionView.xcodeproj/project.pbxproj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WKPagesCollectionView.xcodeproj/project.pbxproj b/WKPagesCollectionView.xcodeproj/project.pbxproj index 956188e..644fa51 100644 --- a/WKPagesCollectionView.xcodeproj/project.pbxproj +++ b/WKPagesCollectionView.xcodeproj/project.pbxproj @@ -162,7 +162,7 @@ 68D7C1C718347A08006B418C /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0610; ORGANIZATIONNAME = "秦 道平"; }; buildConfigurationList = 68D7C1CA18347A08006B418C /* Build configuration list for PBXProject "WKPagesCollectionView" */; @@ -237,7 +237,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -276,7 +275,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; From 09425d01e25f1561b88c70863ad55b53ad2da0d8 Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Thu, 27 Nov 2014 13:05:46 +1030 Subject: [PATCH 04/31] silenced compiler warnings with some changes to int types --- .../WKPagesCollectionView/WKPagesCollectionView.m | 8 ++++---- .../WKPagesCollectionView/WKPagesCollectionViewCell.m | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index 119a9f2..d0cb800 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -100,7 +100,7 @@ -(UIImage*)makeGradientImage{ #pragma mark - Actions ///Display status -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void (^)(BOOL))completion{ - NSLog(@"row:%d",indexPath.row); + NSLog(@"row:%ld",(long)indexPath.row); if (_isHighLight){ return; } @@ -130,7 +130,7 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void cell.showingState=WKPagesCollectionViewCellShowingStateBackToTop; } else if (visibleIndexPath.row>indexPath.row){ - NSLog(@"indexPath:%d,visibleIndexPath:%d",indexPath.row,visibleIndexPath.row); + NSLog(@"indexPath:%ld,visibleIndexPath:%ld",(long)indexPath.row,(long)visibleIndexPath.row); cell.showingState=WKPagesCollectionViewCellShowingStateBackToBottom; } else{ @@ -207,7 +207,7 @@ -(void)appendItem{ } ///Adding a -(void)_addNewPage{ - int total=[self numberOfItemsInSection:0]; + NSInteger total=[self numberOfItemsInSection:0]; if (total > 0) { [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; } @@ -217,7 +217,7 @@ -(void)_addNewPage{ dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ ///Add Data [(id)self.dataSource willAppendItemInCollectionView:self]; - int lastRow=total; + NSInteger lastRow=total; NSIndexPath* insertIndexPath=[NSIndexPath indexPathForItem:lastRow inSection:0]; [self performBatchUpdates:^{ [self insertItemsAtIndexPaths:@[insertIndexPath]]; diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m index 0b15da8..7b3945d 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m @@ -135,7 +135,7 @@ -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL) if (self.showingState==WKPagesCollectionViewCellShowingStateNormal){ if (scrollView.contentOffset.x>=90.0f){ NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; - NSLog(@"delete cell at %d",indexPath.row); + NSLog(@"delete cell at %ld",(long)indexPath.row); //self.alpha=0.0f; ///Delete data id pagesDataSource=(id)self.collectionView.dataSource; From 7187d024b366fd033015f7358fb25da7e6798145 Mon Sep 17 00:00:00 2001 From: Ric Santos Date: Fri, 28 Nov 2014 11:53:19 +1030 Subject: [PATCH 05/31] added CocoaPods podspec --- WKPagesCollectionView.podspec | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 WKPagesCollectionView.podspec diff --git a/WKPagesCollectionView.podspec b/WKPagesCollectionView.podspec new file mode 100644 index 0000000..45627f8 --- /dev/null +++ b/WKPagesCollectionView.podspec @@ -0,0 +1,15 @@ +Pod::Spec.new do |s| + s.name = 'WKPagesCollectionView' + s.version = '0.1.0' + s.summary = 'A collection view that mimics the tab switcher in Safari for iOS 7.' + s.description = 'WKPagesCollectionView mimics the transformed list of tabs as seen in Safari for iOS 7. It has support for animating in and out the tabs, as well as adding and deleting tabs.' + s.homepage = 'http://EXAMPLE/WKPagesCollectionView' + s.screenshots = 'https://camo.githubusercontent.com/1fe6654948c6aa9a68d80c65ba3019344e25e071/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333832392f31313137313833313831345f396335393732626265365f7a2e6a7067' + s.license = 'unknown' + s.author = { 'adow' => 'reynoldqin@gmail.com' } + s.platform = :ios, '7.0' + s.source = :git => 'git@github.com:NextFaze/WKPagesCollectionView.git' + s.source_files = 'WKPagesScrollView/WKPagesCollectionView/*.{h,m}' + s.frameworks = 'QuartzCore', 'CoreGraphics' + s.requires_arc = true +end From 24c47c7618b0d4933f9a031f977b960db3f42844 Mon Sep 17 00:00:00 2001 From: Ric Santos Date: Fri, 28 Nov 2014 12:04:04 +1030 Subject: [PATCH 06/31] syntax fix on podspec --- WKPagesCollectionView.podspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WKPagesCollectionView.podspec b/WKPagesCollectionView.podspec index 45627f8..dbe885a 100644 --- a/WKPagesCollectionView.podspec +++ b/WKPagesCollectionView.podspec @@ -3,13 +3,13 @@ Pod::Spec.new do |s| s.version = '0.1.0' s.summary = 'A collection view that mimics the tab switcher in Safari for iOS 7.' s.description = 'WKPagesCollectionView mimics the transformed list of tabs as seen in Safari for iOS 7. It has support for animating in and out the tabs, as well as adding and deleting tabs.' - s.homepage = 'http://EXAMPLE/WKPagesCollectionView' + s.homepage = 'https://github.com/adow/WKPagesCollectionView' s.screenshots = 'https://camo.githubusercontent.com/1fe6654948c6aa9a68d80c65ba3019344e25e071/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333832392f31313137313833313831345f396335393732626265365f7a2e6a7067' s.license = 'unknown' s.author = { 'adow' => 'reynoldqin@gmail.com' } s.platform = :ios, '7.0' - s.source = :git => 'git@github.com:NextFaze/WKPagesCollectionView.git' + s.source = { :git => 'https://github.com/NextFaze/WKPagesCollectionView.git' } s.source_files = 'WKPagesScrollView/WKPagesCollectionView/*.{h,m}' s.frameworks = 'QuartzCore', 'CoreGraphics' - s.requires_arc = true + s.requires_arc = false end From c29e0011e55ada584fcbb8f3b5101dd3164d9378 Mon Sep 17 00:00:00 2001 From: Ric Santos Date: Fri, 28 Nov 2014 12:18:46 +1030 Subject: [PATCH 07/31] changed source to original repo --- WKPagesCollectionView.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WKPagesCollectionView.podspec b/WKPagesCollectionView.podspec index dbe885a..77cc84f 100644 --- a/WKPagesCollectionView.podspec +++ b/WKPagesCollectionView.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.license = 'unknown' s.author = { 'adow' => 'reynoldqin@gmail.com' } s.platform = :ios, '7.0' - s.source = { :git => 'https://github.com/NextFaze/WKPagesCollectionView.git' } + s.source = { :git => 'https://github.com/adow/WKPagesCollectionView.git' } s.source_files = 'WKPagesScrollView/WKPagesCollectionView/*.{h,m}' s.frameworks = 'QuartzCore', 'CoreGraphics' s.requires_arc = false From 8f35d8de29034bf5f5699bbe67b157e969b4e0f6 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Tue, 2 Dec 2014 13:49:45 +0800 Subject: [PATCH 08/31] Add english version of README --- README_en.md | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 README_en.md diff --git a/README_en.md b/README_en.md new file mode 100644 index 0000000..2b3220b --- /dev/null +++ b/README_en.md @@ -0,0 +1,249 @@ +# WKPagesCollectionView + +I wanted to implement an UI effect like iOS7 Safari tabs pages. + +* Page-flipping effect; +* Click on a page then can put it into a normal display state; +* Scratch to left can delete the cell; +* You can add a new cell at the bottom; + +[See video](http://v.youku.com/v_show/id_XNzAzNDg4OTQ4.html) + +![Effect video](http://farm4.staticflickr.com/3829/11171831814_9c5972bbe6_z.jpg)] + + + +##Usage +* Add `WKPagesCollectionView` folder and the following files inside it to project :`WK.h`, `WKPagesCollectionView.h`, `WKPagesCollectionView.m`, `WKPagesCollectionViewCell.h`, `WKPagesCollectionViewCell.m`, `WKPagesCollectionViewFlowLayout.h`, `WKPagesCollectionViewFlowLayout.m`; +* Import `WKPagesCollectionView`; +* Prepare data + + _array=[[NSMutableArray alloc]init]; + for (int a=0; a<=30; a++) { + [_array addObject:[NSString stringWithFormat:@"button %d",a]]; + } + +* Create `collectionView` + + _collectionView=[[[WKPagesCollectionView alloc]initWithPagesFlowLayoutAndFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height)] autorelease]; + _collectionView.dataSource=self; + _collectionView.delegate=self; + [_collectionView registerClass:[WKPagesCollectionViewCell class] forCellWithReuseIdentifier:@"cell"]; + [self.view addSubview:_collectionView]; + _collectionView.maskShow=YES; + + +* Implement WKPagesCollectionViewDataSource(inherited from UICollectionViewDataSource) and WKPagesCollectionViewDelegate(inherited from UICollectionViewDelegate), in addition of these, also need to provide methods of append item and remove item : `-(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView` and +`-(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath` + + #pragma mark - UICollectionViewDataSource and UICollectionViewDelegate + -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ + return _array.count; + } + -(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ + // NSLog(@"cellForItemAtIndexPath:%d",indexPath.row); + static NSString* identity=@"cell"; + WKPagesCollectionViewCell* cell=(WKPagesCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:identity forIndexPath:indexPath]; + cell.collectionView=collectionView; + UIImageView* imageView=[[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image-0"]] autorelease]; + imageView.frame=self.view.bounds; + [cell.cellContentView addSubview:imageView]; + UIButton* button=[UIButton buttonWithType:UIButtonTypeCustom]; + button.frame=CGRectMake(0, (indexPath.row+1)*10+100, 320, 50.0f); + button.backgroundColor=[UIColor whiteColor]; + [button setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal]; + [button setTitle:_array[indexPath.row] forState:UIControlStateNormal]; + [button addTarget:self action:@selector(onButtonTitle:) forControlEvents:UIControlEventTouchUpInside]; + [cell.cellContentView addSubview:button]; + return cell; + } + #pragma mark WKPagesCollectionViewDataSource + ///append item + -(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView{ + [_array addObject:@"new button"]; + } + ///remove item + -(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath{ + [_array removeObjectAtIndex:indexPath.row]; + } + +* Append a page by press button + + -(IBAction)onButtonAdd:(id)sender{ + [_collectionView appendItem]; + } + +* Expand to display a specific page. this will be triggered when clicking the page, the code be invoked as follows; + + [_collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { + NSLog(@"highlight completed"); + }]; + +* Stop expand the page and back to normal mode(tab mode) + + -(IBAction)onButtonTitle:(id)sender{ + NSLog(@"button"); + [_collectionView dismissFromHightLightWithCompletion:^(BOOL finished) { + NSLog(@"dismiss completed"); + }]; + } + +##TODO +* `bug` ~~When roll the tab several times, the top page will be first invisible and then suddenly appeared, did not found the reason~~ This problem has been solved by @ Nikolay Abelyashev. The root cause is due to the too small height of WKPagesCollectionView, and the UICollectionView will not display cells outside the device screen. In WKPagesCollectionView the three cells outside the screen will not be displayed. The solution is to modify the frame of WKPagesCollectionView , so that the height will higher than the device window (here add topOfScreen: 120.0f), then the frame.origin.y also adds up that distance, so in fact the WKPagesCollectionView is larger than the window. + + +##Way to implement +###Implement scroll + +I used UICollectionView to implement the scroll, this is essentially a vertical list, and the main part is a CollectionViewLayout. (I define it as WKPagesCollectionViewFlowLayout) each cell have the same size of device screen, that is actually a pile of screen size cells stagger folded together, and the space between them is `self.minimumLineSpacing = -1 * (self.itemSize.height-160.0f);`. +![When not flip cell](http://farm6.staticflickr.com/5521/11171968153_7a7aeb5893_z.jpg) + +In order to achieve the flipping effect, in the function +`-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect` of WKPagesCollectionViewFlowLayout, I modify the transform3D. + +Looks simple, but if all the pages have fixed angle, then its ok, but I imagine that like safari when scroll the page, there have a little parallax effect, so I set up a different flip angles for each page. In fact, is in layoutAttributesForElementsInRect function, base on the position of each cell calculate the angle so that when they scroll there have a little different perspective. the following is the code to set the angle: + + -(void)makeRotateTransformForAttributes:(UICollectionViewLayoutAttributes*)attributes{ + attributes.zIndex=attributes.indexPath.row;///Set the zIndex, to implement sequential occlusion + CGFloat distance=attributes.frame.origin.y-self.collectionView.contentOffset.y; + CGFloat normalizedDistance = distance / self.collectionView.frame.size.height; + normalizedDistance=fmaxf(normalizedDistance, 0.0f); + CGFloat rotate=RotateDegree+20.0f*normalizedDistance; + //CGFloat rotate=RotateDegree; + NSLog(@"makeRotateTransformForAttributes:row:%d,normalizedDistance:%f,rotate:%f", + attributes.indexPath.row,normalizedDistance,rotate); + ///Bigger angle cell will have cross with smaller angle cell, even set the zIndex. Here set the lower cell have the bigger angle. + CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(rotate); + attributes.transform3D=rotateTransform; + + } + +``` +-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path +{ + NSLog(@"layoutAttributesForItemAtIndexPath:%d",path.row); + UICollectionViewLayoutAttributes* attributes=[super layoutAttributesForItemAtIndexPath:path]; + [self makeRotateTransformForAttributes:attributes]; + return attributes; +} +-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect +{ + NSLog(@"layoutAttributesForElementsInRect:%@",NSStringFromCGRect(rect)); + NSArray* array = [super layoutAttributesForElementsInRect:rect]; + for (UICollectionViewLayoutAttributes* attributes in array) { + [self makeRotateTransformForAttributes:attributes]; + } + return array; +} +``` + +Now have the desired effect, although not so perfect like Safari's. + +##Implement delete item + +Later I want to implement the delete item effect which like Safari's: hold on one of the cell and slide left then can remove it. I add a scrollView in every cell, in function of scrollViewDidEndDragging, when slide to left reach a certain distance then trigger the delete function. The animation effect of removing was implemented in UICollectionView's performBatchUpdates function. +![The UI effect of deletion.](http://farm4.staticflickr.com/3831/11171811316_c681d80cc2_z.jpg) + + -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ + if (self.showingState==WKPagesCollectionViewCellShowingStateNormal){ + if (scrollView.contentOffset.x>=90.0f){ + NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; + NSLog(@"delete cell at %d",indexPath.row); + //self.alpha=0.0f; + ///Remove item + id pagesDataSource=(id)self.collectionView.dataSource; + [pagesDataSource collectionView:(WKPagesCollectionView*)self.collectionView willRemoveCellAtNSIndexPath:indexPath]; + ///Animation + [self.collectionView performBatchUpdates:^{ + [self.collectionView deleteItemsAtIndexPaths:@[indexPath,]]; + } completion:^(BOOL finished) { + + }]; + } + } + } + +To make the animation effect of add and delete item look better, we have to modify +`(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` and `-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` + +I add insertIndexPaths and deleteIndexPaths functions in WKPagesCollectionViewFlowLayout, to record the position when add and remove item. The two callback functions will be called not just for being added or deleted NSIndexPath, and will be called at another place. + + -(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ + UICollectionViewLayoutAttributes* attributes=[super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; + NSLog(@"initialLayoutAttributesForAppearingItemAtIndexPath:%d",itemIndexPath.row); + if ([self.insertIndexPaths containsObject:itemIndexPath]){ + if (!attributes) + attributes=[self layoutAttributesForItemAtIndexPath:itemIndexPath]; + CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(-90.0f); + attributes.transform3D=rotateTransform; + } + return attributes; + } + -(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ + NSLog(@"finalLayoutAttributesForDisappearingItemAtIndexPath:%d",itemIndexPath.row); + UICollectionViewLayoutAttributes* attributes=[super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath]; + if ([self.deleteIndexPaths containsObject:itemIndexPath]){ + if (!attributes){ + attributes=[self layoutAttributesForItemAtIndexPath:itemIndexPath]; + } + CATransform3D moveTransform=CATransform3DMakeTranslation(-320.0f, 0.0f, 0.0f); + attributes.transform3D=CATransform3DConcat(attributes.transform3D, moveTransform); + } + return attributes; + + } + + +Beginning will be some unexpected animation, scrolling to the end, and then press command + t to open slow animations in simulator can see very clearly. When slide left to remove the last two cell, at the beginning of remove effect it works normal, but when almost complete the remove effect, will see one flash happened at a very strange position between two cells, and then slowly return to the normal animation. + +Now the question is, if I remove the cell of button-0, button-1, button-2, button-3, the animation is OK, but if I delete the last several cell of button-6, button -7, button-8, it will appear unexpected animation. + +And I found that if the flip angle is all fixed, then when delete cell, there will not have strange animation, my makeRotateTransformForAttributes2 is assigned a fixed angle. +####Fixed + +Then finally know where the problem lies, just because the miscalculation of contentSize leading to the lack of content area, so when the cell is deleted and then rolling will produce this behaviour. so the height which be set in `- (CGSize) collectionViewContentSize` must be correct. + +###Implement add page + +Now the WKPagesCollectionView have two states, one is `normal` state, another is `highlight` state. At normal state, one can scroll the pages. When tap on one page, it will trigger to transfer to `highlight` state. In highlight state the page be tapped will be displayed in full screen. + +When you go to add a new page, you need to press `+` which at the bottom of screen to add a page, then the last page which be added will be displayed in full screen(`highlight` state). If currently is in `highlight` state, it will back to `normal` state and then transfer to `highlight` state to display the last page in full screen. + +Here is add page method in WKPagesCollectionView: + + ///Append an item + -(void)appendItem{ + if (self.isHighLight){ + [self dismissFromHightLightWithCompletion:^(BOOL finished) { + [self _addNewPage]; + }]; + } + else{ + [self _addNewPage]; + } + } + ///Add a new page + -(void)_addNewPage{ + int total=[self numberOfItemsInSection:0]; + [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; + double delayInSeconds = 0.3f; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + ///Add an item + [(id)self.dataSource willAppendItemInCollectionView:self]; + int lastRow=total; + NSIndexPath* insertIndexPath=[NSIndexPath indexPathForItem:lastRow inSection:0]; + [self performBatchUpdates:^{ + [self insertItemsAtIndexPaths:@[insertIndexPath]]; + } completion:^(BOOL finished) { + double delayInSeconds = 0.3f; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + [self showCellToHighLightAtIndexPath:insertIndexPath completion:^(BOOL finished) { + + }]; + }); + + }]; + }); + } From e765f7620c701c554dd9efdf2586571566bdbcde Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Tue, 2 Dec 2014 14:12:07 +0800 Subject: [PATCH 09/31] Update READEM_en.md --- README_en.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/README_en.md b/README_en.md index 2b3220b..f172763 100644 --- a/README_en.md +++ b/README_en.md @@ -33,8 +33,9 @@ I wanted to implement an UI effect like iOS7 Safari tabs pages. _collectionView.maskShow=YES; -* Implement WKPagesCollectionViewDataSource(inherited from UICollectionViewDataSource) and WKPagesCollectionViewDelegate(inherited from UICollectionViewDelegate), in addition of these, also need to provide methods of append item and remove item : `-(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView` and -`-(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath` +* Implement `WKPagesCollectionViewDataSource`(inherited from `UICollectionViewDataSource`) and `WKPagesCollectionViewDelegate`(inherited from `UICollectionViewDelegate`), in addition of these, also need to provide methods of append item and remove item : +`-(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView` +and `-(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath` #pragma mark - UICollectionViewDataSource and UICollectionViewDelegate -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ @@ -89,19 +90,20 @@ I wanted to implement an UI effect like iOS7 Safari tabs pages. } ##TODO -* `bug` ~~When roll the tab several times, the top page will be first invisible and then suddenly appeared, did not found the reason~~ This problem has been solved by @ Nikolay Abelyashev. The root cause is due to the too small height of WKPagesCollectionView, and the UICollectionView will not display cells outside the device screen. In WKPagesCollectionView the three cells outside the screen will not be displayed. The solution is to modify the frame of WKPagesCollectionView , so that the height will higher than the device window (here add topOfScreen: 120.0f), then the frame.origin.y also adds up that distance, so in fact the WKPagesCollectionView is larger than the window. +* `bug` ~~When roll the tab several times, the top page will be first invisible and then suddenly appeared, did not found the reason~~ This problem has been solved by @ Nikolay Abelyashev. The root cause is due to the too small height of WKPagesCollectionView, and the `UICollectionView` will not display cells outside the device screen. In `WKPagesCollectionView` the three cells outside the screen will not be displayed. The solution is to modify the frame of `WKPagesCollectionView` , so that the height will higher than the device window (here add `topOfScreen: 120.0f`), then the `frame.origin.y` also adds up that distance, so in fact the `WKPagesCollectionView` is larger than the window. ##Way to implement ###Implement scroll -I used UICollectionView to implement the scroll, this is essentially a vertical list, and the main part is a CollectionViewLayout. (I define it as WKPagesCollectionViewFlowLayout) each cell have the same size of device screen, that is actually a pile of screen size cells stagger folded together, and the space between them is `self.minimumLineSpacing = -1 * (self.itemSize.height-160.0f);`. +I used `UICollectionView` to implement the scroll, this is essentially a vertical list, and the main part is a `CollectionViewLayout`. (I define it as `WKPagesCollectionViewFlowLayout`) each cell have the same size of device screen, that is actually a pile of screen size cells stagger folded together, and the space between them is `self.minimumLineSpacing = -1 * (self.itemSize.height-160.0f);`. + ![When not flip cell](http://farm6.staticflickr.com/5521/11171968153_7a7aeb5893_z.jpg) In order to achieve the flipping effect, in the function `-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect` of WKPagesCollectionViewFlowLayout, I modify the transform3D. -Looks simple, but if all the pages have fixed angle, then its ok, but I imagine that like safari when scroll the page, there have a little parallax effect, so I set up a different flip angles for each page. In fact, is in layoutAttributesForElementsInRect function, base on the position of each cell calculate the angle so that when they scroll there have a little different perspective. the following is the code to set the angle: +Looks simple, but if all the pages have fixed angle, then its ok, but I imagine that like safari when scroll the page, there have a little parallax effect, so I set up a different flip angles for each page. In fact, is in `layoutAttributesForElementsInRect` function, base on the position of each cell calculate the angle so that when they scroll there have a little different perspective. the following is the code to set the angle: -(void)makeRotateTransformForAttributes:(UICollectionViewLayoutAttributes*)attributes{ attributes.zIndex=attributes.indexPath.row;///Set the zIndex, to implement sequential occlusion @@ -141,7 +143,8 @@ Now have the desired effect, although not so perfect like Safari's. ##Implement delete item -Later I want to implement the delete item effect which like Safari's: hold on one of the cell and slide left then can remove it. I add a scrollView in every cell, in function of scrollViewDidEndDragging, when slide to left reach a certain distance then trigger the delete function. The animation effect of removing was implemented in UICollectionView's performBatchUpdates function. +Later I want to implement the delete item effect which like Safari's: hold on one of the cell and slide left then can remove it. I add a scrollView in every cell, in function of `scrollViewDidEndDragging`, when slide to left reach a certain distance then trigger the delete function. The animation effect of removing was implemented in UICollectionView's `performBatchUpdates` function. + ![The UI effect of deletion.](http://farm4.staticflickr.com/3831/11171811316_c681d80cc2_z.jpg) -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ @@ -164,7 +167,8 @@ Later I want to implement the delete item effect which like Safari's: hold on on } To make the animation effect of add and delete item look better, we have to modify -`(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` and `-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` +`(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` +and `-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` I add insertIndexPaths and deleteIndexPaths functions in WKPagesCollectionViewFlowLayout, to record the position when add and remove item. The two callback functions will be called not just for being added or deleted NSIndexPath, and will be called at another place. @@ -198,18 +202,18 @@ Beginning will be some unexpected animation, scrolling to the end, and then pres Now the question is, if I remove the cell of button-0, button-1, button-2, button-3, the animation is OK, but if I delete the last several cell of button-6, button -7, button-8, it will appear unexpected animation. -And I found that if the flip angle is all fixed, then when delete cell, there will not have strange animation, my makeRotateTransformForAttributes2 is assigned a fixed angle. +And I found that if the flip angle is all fixed, then when delete cell, there will not have strange animation, my `makeRotateTransformForAttributes2` is assigned a fixed angle. ####Fixed Then finally know where the problem lies, just because the miscalculation of contentSize leading to the lack of content area, so when the cell is deleted and then rolling will produce this behaviour. so the height which be set in `- (CGSize) collectionViewContentSize` must be correct. ###Implement add page -Now the WKPagesCollectionView have two states, one is `normal` state, another is `highlight` state. At normal state, one can scroll the pages. When tap on one page, it will trigger to transfer to `highlight` state. In highlight state the page be tapped will be displayed in full screen. +Now the `WKPagesCollectionView` have two states, one is `normal` state, another is `highlight` state. At normal state, one can scroll the pages. When tap on one page, it will trigger to transfer to `highlight` state. In highlight state the page be tapped will be displayed in full screen. When you go to add a new page, you need to press `+` which at the bottom of screen to add a page, then the last page which be added will be displayed in full screen(`highlight` state). If currently is in `highlight` state, it will back to `normal` state and then transfer to `highlight` state to display the last page in full screen. -Here is add page method in WKPagesCollectionView: +Here is add page method in `WKPagesCollectionView`: ///Append an item -(void)appendItem{ From f9f0385f14c07e4edacc0cabd43564eb76a7c7b1 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Tue, 2 Dec 2014 14:15:25 +0800 Subject: [PATCH 10/31] Update READEM.en.md --- README_en.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README_en.md b/README_en.md index f172763..500ac7b 100644 --- a/README_en.md +++ b/README_en.md @@ -168,9 +168,12 @@ Later I want to implement the delete item effect which like Safari's: hold on on To make the animation effect of add and delete item look better, we have to modify `(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` -and `-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` -I add insertIndexPaths and deleteIndexPaths functions in WKPagesCollectionViewFlowLayout, to record the position when add and remove item. The two callback functions will be called not just for being added or deleted NSIndexPath, and will be called at another place. +and + +`-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` + +I add `insertIndexPaths` and `deleteIndexPaths` functions in `WKPagesCollectionViewFlowLayout`, to record the position when add and remove item. The two callback functions will be called not just for being added or deleted `NSIndexPath`, and will be called at another place. -(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ UICollectionViewLayoutAttributes* attributes=[super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; From d5e8b3af93b5f51f069bddbb02e50d958b270812 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Tue, 2 Dec 2014 14:38:42 +0800 Subject: [PATCH 11/31] dismissFromHightLightWithCompletion crashes with nil block --- .../WKPagesCollectionView/WKPagesCollectionView.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index d0cb800..775033f 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -188,7 +188,9 @@ -(void)dismissFromHightLightWithCompletion:(void (^)(BOOL))completion{ } completion:^(BOOL finished) { self.scrollEnabled=YES; _isHighLight=NO; - completion(finished); + if (completion != nil) { + completion(finished); + } if ([self.delegate respondsToSelector:@selector(didDismissFromHightlightOnCollectionView:)]){ [(id)self.delegate didDismissFromHightlightOnCollectionView:self]; } From f8a87fd02b0a7b892ec928b3ff327ce2f1ba4aae Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Tue, 2 Dec 2014 20:05:39 +0800 Subject: [PATCH 12/31] Button area have no response when the views in "stack" status --- WKPagesScrollView/ViewController.m | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/WKPagesScrollView/ViewController.m b/WKPagesScrollView/ViewController.m index 27c1768..e0a1bb2 100644 --- a/WKPagesScrollView/ViewController.m +++ b/WKPagesScrollView/ViewController.m @@ -58,10 +58,25 @@ -(void)dealloc{ [super dealloc]; } -(IBAction)onButtonTitle:(id)sender{ - NSLog(@"button"); + UIView *thisButton = (UIView *)sender; + if (!_collectionView.isHighLight) { + NSArray* visibleIndexPaths=[_collectionView indexPathsForVisibleItems]; + for (NSIndexPath* indexPath in visibleIndexPaths) { + WKPagesCollectionViewCell* cell = (WKPagesCollectionViewCell *)[_collectionView cellForItemAtIndexPath:indexPath]; + + BOOL doesContain = [cell.cellContentView.subviews containsObject:thisButton]; + if (doesContain ) { + [(WKPagesCollectionView*)_collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { + NSLog(@"highlight completed"); + }]; + break; + } + } + } else { [_collectionView dismissFromHightLightWithCompletion:^(BOOL finished) { NSLog(@"dismiss completed"); }]; + } } -(IBAction)onButtonAdd:(id)sender{ [_collectionView appendItem]; From 5beb00ecd6d2ead85d819a7bae5f957f6f0d8c9d Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Wed, 3 Dec 2014 10:42:11 +1030 Subject: [PATCH 13/31] replaced Chinese README with English version --- README.md | 106 +++++++++++---------- README_en.md | 256 --------------------------------------------------- 2 files changed, 55 insertions(+), 307 deletions(-) delete mode 100644 README_en.md diff --git a/README.md b/README.md index 72eb3aa..500ac7b 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,29 @@ # WKPagesCollectionView -我尝试想做一个类似 iOS7 下的 safari tabs 页面那样的效果。 +I wanted to implement an UI effect like iOS7 Safari tabs pages. -* 有页面翻转的效果; -* 点击一个页面变成正常的显示状态; -* 往左划动会删除这个cell; -* 可以在底部添加新的cell; +* Page-flipping effect; +* Click on a page then can put it into a normal display state; +* Scratch to left can delete the cell; +* You can add a new cell at the bottom; -[点击查看效果视频](http://v.youku.com/v_show/id_XNzAzNDg4OTQ4.html) +[See video](http://v.youku.com/v_show/id_XNzAzNDg4OTQ4.html) -![效果视频](http://farm4.staticflickr.com/3829/11171831814_9c5972bbe6_z.jpg)] +![Effect video](http://farm4.staticflickr.com/3829/11171831814_9c5972bbe6_z.jpg)] -##使用 -* 项目中添加 WKPagesCollectionView目录以及下面的`WK.h`, `WKPagesCollectionView.h`, `WKPagesCollectionView.m`, `WKPagesCollectionViewCell.h`, `WKPagesCollectionViewCell.m`, `WKPagesCollectionViewFlowLayout.h`, `WKPagesCollectionViewFlowLayout.m`; -* 引用 `WKPagesCollectionView`; -* 准备数据 +##Usage +* Add `WKPagesCollectionView` folder and the following files inside it to project :`WK.h`, `WKPagesCollectionView.h`, `WKPagesCollectionView.m`, `WKPagesCollectionViewCell.h`, `WKPagesCollectionViewCell.m`, `WKPagesCollectionViewFlowLayout.h`, `WKPagesCollectionViewFlowLayout.m`; +* Import `WKPagesCollectionView`; +* Prepare data _array=[[NSMutableArray alloc]init]; for (int a=0; a<=30; a++) { [_array addObject:[NSString stringWithFormat:@"button %d",a]]; } -* 创建collectionView +* Create `collectionView` _collectionView=[[[WKPagesCollectionView alloc]initWithPagesFlowLayoutAndFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height)] autorelease]; _collectionView.dataSource=self; @@ -33,9 +33,9 @@ _collectionView.maskShow=YES; -* 完成WKPagesCollectionViewDataSource(继承自UICollectionViewDataSource) 和 WKPagesCollectionViewDelegate(继承自UICollectionViewDelegate), 除了要完成UICollectionViewDataSource中提供数据的方法外,还要完成追加数据的方法`-(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView` -和删除数据的方法` --(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath` +* Implement `WKPagesCollectionViewDataSource`(inherited from `UICollectionViewDataSource`) and `WKPagesCollectionViewDelegate`(inherited from `UICollectionViewDelegate`), in addition of these, also need to provide methods of append item and remove item : +`-(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView` +and `-(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath` #pragma mark - UICollectionViewDataSource and UICollectionViewDelegate -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ @@ -59,28 +59,28 @@ return cell; } #pragma mark WKPagesCollectionViewDataSource - ///追加数据 + ///append item -(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView{ [_array addObject:@"new button"]; } - ///删除数据 + ///remove item -(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath{ [_array removeObjectAtIndex:indexPath.row]; } -* 添加一个页面时的操作 +* Append a page by press button -(IBAction)onButtonAdd:(id)sender{ [_collectionView appendItem]; } -* 展开显示一个具体的页面,这个在点击页面的时候会自动实现,也可以像下面这样代码调用; +* Expand to display a specific page. this will be triggered when clicking the page, the code be invoked as follows; [_collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { NSLog(@"highlight completed"); }]; -* 停止展开,回到普通的滚动模式 +* Stop expand the page and back to normal mode(tab mode) -(IBAction)onButtonTitle:(id)sender{ NSLog(@"button"); @@ -90,24 +90,23 @@ } ##TODO -* `bug` ~~每滚动几个时候顶上的那一个就会先看不见然后又突然出现了,还没想到原因~~ 这个问题已经解决,@Nikolay Abelyashev 修复了这个bug,原因是由于WKPagesCollectionView的高度太小,而UICollectionView会把屏幕外的cell不在显示,在WKPagesCollectionView中,屏幕外的3个cell会被取消显示,解决的办法是修改WKPagesCollectionView的frame,使他高出window(这里添加了 topOfScreen:120.0f),然后把frame.origin.y也往上移动了那么多距离,这样WKPagesCollectionView其实就更大; +* `bug` ~~When roll the tab several times, the top page will be first invisible and then suddenly appeared, did not found the reason~~ This problem has been solved by @ Nikolay Abelyashev. The root cause is due to the too small height of WKPagesCollectionView, and the `UICollectionView` will not display cells outside the device screen. In `WKPagesCollectionView` the three cells outside the screen will not be displayed. The solution is to modify the frame of `WKPagesCollectionView` , so that the height will higher than the device window (here add `topOfScreen: 120.0f`), then the `frame.origin.y` also adds up that distance, so in fact the `WKPagesCollectionView` is larger than the window. +##Way to implement +###Implement scroll -##实现的方式 -###实现滚动 +I used `UICollectionView` to implement the scroll, this is essentially a vertical list, and the main part is a `CollectionViewLayout`. (I define it as `WKPagesCollectionViewFlowLayout`) each cell have the same size of device screen, that is actually a pile of screen size cells stagger folded together, and the space between them is `self.minimumLineSpacing = -1 * (self.itemSize.height-160.0f);`. -我使用了UICollectionView来实现,本质上是一个垂直的列表,而主要的工作是来创造一个CollectionViewLayout, (我定义为WKPagesCollectionViewFlowLayout)每一个cell其实是和当前屏幕一样大小的,也就是说其实就是有一堆和屏幕一样大的cell错开折叠在一起,他们之间的间隔设置为`self.minimumLineSpacing=-1*(self.itemSize.height-160.0f);`。 -![不翻转cell时](http://farm6.staticflickr.com/5521/11171968153_7a7aeb5893_z.jpg) +![When not flip cell](http://farm6.staticflickr.com/5521/11171968153_7a7aeb5893_z.jpg) -为了实现翻转的效果,我在WKPagesCollectionViewFlowLayout中的 -`-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect` 中修改了transform3D。 - -看上去貌似比较简单,而如果所有的页面都是固定的角度的话,的确也没问题,但是我想像safari里那样在滚动时有点视差的效果,所以就为每个页面设置了不同的翻转角度了,其实就是在layoutAttributesForElementsInRect 中根据每个cell的位置来计算角度使得他们在滚动条滚动时有点不同的角度,下面这个是设置角度的方法: +In order to achieve the flipping effect, in the function +`-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect` of WKPagesCollectionViewFlowLayout, I modify the transform3D. +Looks simple, but if all the pages have fixed angle, then its ok, but I imagine that like safari when scroll the page, there have a little parallax effect, so I set up a different flip angles for each page. In fact, is in `layoutAttributesForElementsInRect` function, base on the position of each cell calculate the angle so that when they scroll there have a little different perspective. the following is the code to set the angle: -(void)makeRotateTransformForAttributes:(UICollectionViewLayoutAttributes*)attributes{ - attributes.zIndex=attributes.indexPath.row;///要设置zIndex,否则遮挡顺序会有编号 + attributes.zIndex=attributes.indexPath.row;///Set the zIndex, to implement sequential occlusion CGFloat distance=attributes.frame.origin.y-self.collectionView.contentOffset.y; CGFloat normalizedDistance = distance / self.collectionView.frame.size.height; normalizedDistance=fmaxf(normalizedDistance, 0.0f); @@ -115,7 +114,7 @@ //CGFloat rotate=RotateDegree; NSLog(@"makeRotateTransformForAttributes:row:%d,normalizedDistance:%f,rotate:%f", attributes.indexPath.row,normalizedDistance,rotate); - ///角度大的会和角度小的cell交叉,即使设置zIndex也没有用,这里设置底部的cell角度越来越大 + ///Bigger angle cell will have cross with smaller angle cell, even set the zIndex. Here set the lower cell have the bigger angle. CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(rotate); attributes.transform3D=rotateTransform; @@ -140,13 +139,13 @@ } ``` -现在运行的时候,滚动起来就和想要的效果差不多了,虽然不如safari那么细节完美,大概的意思是达到了。 +Now have the desired effect, although not so perfect like Safari's. -##实现删除 +##Implement delete item -后面我想做出safari那样按住其中一个cell往左滑动就删除的效果,在每个cell里面添加一个scrollView,然后scrollViewDidEndDragging 中达到一定距离的时候就触发删除好了,而UICollectionView中的performBatchUpdates就可以很好的完成删除的动画了。 +Later I want to implement the delete item effect which like Safari's: hold on one of the cell and slide left then can remove it. I add a scrollView in every cell, in function of `scrollViewDidEndDragging`, when slide to left reach a certain distance then trigger the delete function. The animation effect of removing was implemented in UICollectionView's `performBatchUpdates` function. -![删除时的效果](http://farm4.staticflickr.com/3831/11171811316_c681d80cc2_z.jpg) +![The UI effect of deletion.](http://farm4.staticflickr.com/3831/11171811316_c681d80cc2_z.jpg) -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ if (self.showingState==WKPagesCollectionViewCellShowingStateNormal){ @@ -154,10 +153,10 @@ NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; NSLog(@"delete cell at %d",indexPath.row); //self.alpha=0.0f; - ///删除数据 + ///Remove item id pagesDataSource=(id)self.collectionView.dataSource; [pagesDataSource collectionView:(WKPagesCollectionView*)self.collectionView willRemoveCellAtNSIndexPath:indexPath]; - ///动画 + ///Animation [self.collectionView performBatchUpdates:^{ [self.collectionView deleteItemsAtIndexPaths:@[indexPath,]]; } completion:^(BOOL finished) { @@ -167,10 +166,14 @@ } } -为了添加和删除的时候动画的好看一点,我们还得修改 -`(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` 和 `-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` +To make the animation effect of add and delete item look better, we have to modify +`(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` + +and + +`-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` -我在WKPagesCollectionViewFlowLayout 中添加了insertIndexPaths 和 deleteIndexPaths 来记录用来添加和删除的位置,因为这个两个回调在添加和删除时会被调用,而且不仅仅是针对正在添加或者删除的NSIndexPath,其他行也会被调用,而我们这里只要处理正在添加和删除的NSIndexPath; +I add `insertIndexPaths` and `deleteIndexPaths` functions in `WKPagesCollectionViewFlowLayout`, to record the position when add and remove item. The two callback functions will be called not just for being added or deleted `NSIndexPath`, and will be called at another place. -(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ UICollectionViewLayoutAttributes* attributes=[super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; @@ -198,23 +201,24 @@ } -开始的时候会发生一些意想不到的动画效果,滚动到底部,然后在模拟器下按下command+t打开慢速动画的时候就看的很清楚了,往左滑动来删除最后两个cell,在删除时一开始的效果是正常的,而几乎在完成之后,会看到一闪,出现了两个cell在很奇怪的位置,然后又动画慢慢回到预订的位置。 +Beginning will be some unexpected animation, scrolling to the end, and then press command + t to open slow animations in simulator can see very clearly. When slide left to remove the last two cell, at the beginning of remove effect it works normal, but when almost complete the remove effect, will see one flash happened at a very strange position between two cells, and then slowly return to the normal animation. -现在的问题就是,如果我删除带有button-0,button-1,button-2,button-3这样的cell,动画是正常的,但是如果我删除最后几个cell,带有button-6,button-7,button-8的,就会出现意想不到的动画。 - -而且我发现如果我的cell的翻转角度如果是全部固定的,那在删除cell时是不会发生奇怪的动画的,我的makeRotateTransformForAttributes2中是指定了一个固定的角度。 +Now the question is, if I remove the cell of button-0, button-1, button-2, button-3, the animation is OK, but if I delete the last several cell of button-6, button -7, button-8, it will appear unexpected animation. +And I found that if the flip angle is all fixed, then when delete cell, there will not have strange animation, my `makeRotateTransformForAttributes2` is assigned a fixed angle. ####Fixed -后来终于知道问题在哪里了,只是由于contentSize计算错误导致内容区域不够所以在删除cell后又自动滚动时产生了奇怪的行为,所以`-(CGSize)collectionViewContentSize`中的高度一定要正确。 +Then finally know where the problem lies, just because the miscalculation of contentSize leading to the lack of content area, so when the cell is deleted and then rolling will produce this behaviour. so the height which be set in `- (CGSize) collectionViewContentSize` must be correct. + +###Implement add page -###实现添加页面 +Now the `WKPagesCollectionView` have two states, one is `normal` state, another is `highlight` state. At normal state, one can scroll the pages. When tap on one page, it will trigger to transfer to `highlight` state. In highlight state the page be tapped will be displayed in full screen. -现在页面有两种状态,一种就是这种普通的滚动页面的状态,当点击某一个页面的时候,他会翻转到全屏显示,这时我称作是`highlight`。如果只是在普通的滚动状态下,会先滚动到屏幕地步,然后添加一个页面,之后又会把这个页面展开到highLight显示状态。而如果现在整个collectionView本身就已经有一个页面在hightLight了,那应该先退回到普通状态,再重复之前的添加页面过程。 +When you go to add a new page, you need to press `+` which at the bottom of screen to add a page, then the last page which be added will be displayed in full screen(`highlight` state). If currently is in `highlight` state, it will back to `normal` state and then transfer to `highlight` state to display the last page in full screen. -下面是在WKPagesCollectionView中的添加页面的方法; +Here is add page method in `WKPagesCollectionView`: - ///追加一个页面 + ///Append an item -(void)appendItem{ if (self.isHighLight){ [self dismissFromHightLightWithCompletion:^(BOOL finished) { @@ -225,14 +229,14 @@ [self _addNewPage]; } } - ///添加一页 + ///Add a new page -(void)_addNewPage{ int total=[self numberOfItemsInSection:0]; [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; double delayInSeconds = 0.3f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - ///添加数据 + ///Add an item [(id)self.dataSource willAppendItemInCollectionView:self]; int lastRow=total; NSIndexPath* insertIndexPath=[NSIndexPath indexPathForItem:lastRow inSection:0]; diff --git a/README_en.md b/README_en.md deleted file mode 100644 index 500ac7b..0000000 --- a/README_en.md +++ /dev/null @@ -1,256 +0,0 @@ -# WKPagesCollectionView - -I wanted to implement an UI effect like iOS7 Safari tabs pages. - -* Page-flipping effect; -* Click on a page then can put it into a normal display state; -* Scratch to left can delete the cell; -* You can add a new cell at the bottom; - -[See video](http://v.youku.com/v_show/id_XNzAzNDg4OTQ4.html) - -![Effect video](http://farm4.staticflickr.com/3829/11171831814_9c5972bbe6_z.jpg)] - - - -##Usage -* Add `WKPagesCollectionView` folder and the following files inside it to project :`WK.h`, `WKPagesCollectionView.h`, `WKPagesCollectionView.m`, `WKPagesCollectionViewCell.h`, `WKPagesCollectionViewCell.m`, `WKPagesCollectionViewFlowLayout.h`, `WKPagesCollectionViewFlowLayout.m`; -* Import `WKPagesCollectionView`; -* Prepare data - - _array=[[NSMutableArray alloc]init]; - for (int a=0; a<=30; a++) { - [_array addObject:[NSString stringWithFormat:@"button %d",a]]; - } - -* Create `collectionView` - - _collectionView=[[[WKPagesCollectionView alloc]initWithPagesFlowLayoutAndFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height)] autorelease]; - _collectionView.dataSource=self; - _collectionView.delegate=self; - [_collectionView registerClass:[WKPagesCollectionViewCell class] forCellWithReuseIdentifier:@"cell"]; - [self.view addSubview:_collectionView]; - _collectionView.maskShow=YES; - - -* Implement `WKPagesCollectionViewDataSource`(inherited from `UICollectionViewDataSource`) and `WKPagesCollectionViewDelegate`(inherited from `UICollectionViewDelegate`), in addition of these, also need to provide methods of append item and remove item : -`-(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView` -and `-(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath` - - #pragma mark - UICollectionViewDataSource and UICollectionViewDelegate - -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ - return _array.count; - } - -(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ - // NSLog(@"cellForItemAtIndexPath:%d",indexPath.row); - static NSString* identity=@"cell"; - WKPagesCollectionViewCell* cell=(WKPagesCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:identity forIndexPath:indexPath]; - cell.collectionView=collectionView; - UIImageView* imageView=[[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image-0"]] autorelease]; - imageView.frame=self.view.bounds; - [cell.cellContentView addSubview:imageView]; - UIButton* button=[UIButton buttonWithType:UIButtonTypeCustom]; - button.frame=CGRectMake(0, (indexPath.row+1)*10+100, 320, 50.0f); - button.backgroundColor=[UIColor whiteColor]; - [button setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal]; - [button setTitle:_array[indexPath.row] forState:UIControlStateNormal]; - [button addTarget:self action:@selector(onButtonTitle:) forControlEvents:UIControlEventTouchUpInside]; - [cell.cellContentView addSubview:button]; - return cell; - } - #pragma mark WKPagesCollectionViewDataSource - ///append item - -(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView{ - [_array addObject:@"new button"]; - } - ///remove item - -(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath{ - [_array removeObjectAtIndex:indexPath.row]; - } - -* Append a page by press button - - -(IBAction)onButtonAdd:(id)sender{ - [_collectionView appendItem]; - } - -* Expand to display a specific page. this will be triggered when clicking the page, the code be invoked as follows; - - [_collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { - NSLog(@"highlight completed"); - }]; - -* Stop expand the page and back to normal mode(tab mode) - - -(IBAction)onButtonTitle:(id)sender{ - NSLog(@"button"); - [_collectionView dismissFromHightLightWithCompletion:^(BOOL finished) { - NSLog(@"dismiss completed"); - }]; - } - -##TODO -* `bug` ~~When roll the tab several times, the top page will be first invisible and then suddenly appeared, did not found the reason~~ This problem has been solved by @ Nikolay Abelyashev. The root cause is due to the too small height of WKPagesCollectionView, and the `UICollectionView` will not display cells outside the device screen. In `WKPagesCollectionView` the three cells outside the screen will not be displayed. The solution is to modify the frame of `WKPagesCollectionView` , so that the height will higher than the device window (here add `topOfScreen: 120.0f`), then the `frame.origin.y` also adds up that distance, so in fact the `WKPagesCollectionView` is larger than the window. - - -##Way to implement -###Implement scroll - -I used `UICollectionView` to implement the scroll, this is essentially a vertical list, and the main part is a `CollectionViewLayout`. (I define it as `WKPagesCollectionViewFlowLayout`) each cell have the same size of device screen, that is actually a pile of screen size cells stagger folded together, and the space between them is `self.minimumLineSpacing = -1 * (self.itemSize.height-160.0f);`. - -![When not flip cell](http://farm6.staticflickr.com/5521/11171968153_7a7aeb5893_z.jpg) - -In order to achieve the flipping effect, in the function -`-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect` of WKPagesCollectionViewFlowLayout, I modify the transform3D. - -Looks simple, but if all the pages have fixed angle, then its ok, but I imagine that like safari when scroll the page, there have a little parallax effect, so I set up a different flip angles for each page. In fact, is in `layoutAttributesForElementsInRect` function, base on the position of each cell calculate the angle so that when they scroll there have a little different perspective. the following is the code to set the angle: - - -(void)makeRotateTransformForAttributes:(UICollectionViewLayoutAttributes*)attributes{ - attributes.zIndex=attributes.indexPath.row;///Set the zIndex, to implement sequential occlusion - CGFloat distance=attributes.frame.origin.y-self.collectionView.contentOffset.y; - CGFloat normalizedDistance = distance / self.collectionView.frame.size.height; - normalizedDistance=fmaxf(normalizedDistance, 0.0f); - CGFloat rotate=RotateDegree+20.0f*normalizedDistance; - //CGFloat rotate=RotateDegree; - NSLog(@"makeRotateTransformForAttributes:row:%d,normalizedDistance:%f,rotate:%f", - attributes.indexPath.row,normalizedDistance,rotate); - ///Bigger angle cell will have cross with smaller angle cell, even set the zIndex. Here set the lower cell have the bigger angle. - CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(rotate); - attributes.transform3D=rotateTransform; - - } - -``` --(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path -{ - NSLog(@"layoutAttributesForItemAtIndexPath:%d",path.row); - UICollectionViewLayoutAttributes* attributes=[super layoutAttributesForItemAtIndexPath:path]; - [self makeRotateTransformForAttributes:attributes]; - return attributes; -} --(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect -{ - NSLog(@"layoutAttributesForElementsInRect:%@",NSStringFromCGRect(rect)); - NSArray* array = [super layoutAttributesForElementsInRect:rect]; - for (UICollectionViewLayoutAttributes* attributes in array) { - [self makeRotateTransformForAttributes:attributes]; - } - return array; -} -``` - -Now have the desired effect, although not so perfect like Safari's. - -##Implement delete item - -Later I want to implement the delete item effect which like Safari's: hold on one of the cell and slide left then can remove it. I add a scrollView in every cell, in function of `scrollViewDidEndDragging`, when slide to left reach a certain distance then trigger the delete function. The animation effect of removing was implemented in UICollectionView's `performBatchUpdates` function. - -![The UI effect of deletion.](http://farm4.staticflickr.com/3831/11171811316_c681d80cc2_z.jpg) - - -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ - if (self.showingState==WKPagesCollectionViewCellShowingStateNormal){ - if (scrollView.contentOffset.x>=90.0f){ - NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; - NSLog(@"delete cell at %d",indexPath.row); - //self.alpha=0.0f; - ///Remove item - id pagesDataSource=(id)self.collectionView.dataSource; - [pagesDataSource collectionView:(WKPagesCollectionView*)self.collectionView willRemoveCellAtNSIndexPath:indexPath]; - ///Animation - [self.collectionView performBatchUpdates:^{ - [self.collectionView deleteItemsAtIndexPaths:@[indexPath,]]; - } completion:^(BOOL finished) { - - }]; - } - } - } - -To make the animation effect of add and delete item look better, we have to modify -`(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` - -and - -`-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` - -I add `insertIndexPaths` and `deleteIndexPaths` functions in `WKPagesCollectionViewFlowLayout`, to record the position when add and remove item. The two callback functions will be called not just for being added or deleted `NSIndexPath`, and will be called at another place. - - -(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ - UICollectionViewLayoutAttributes* attributes=[super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; - NSLog(@"initialLayoutAttributesForAppearingItemAtIndexPath:%d",itemIndexPath.row); - if ([self.insertIndexPaths containsObject:itemIndexPath]){ - if (!attributes) - attributes=[self layoutAttributesForItemAtIndexPath:itemIndexPath]; - CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(-90.0f); - attributes.transform3D=rotateTransform; - } - return attributes; - } - -(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ - NSLog(@"finalLayoutAttributesForDisappearingItemAtIndexPath:%d",itemIndexPath.row); - UICollectionViewLayoutAttributes* attributes=[super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath]; - if ([self.deleteIndexPaths containsObject:itemIndexPath]){ - if (!attributes){ - attributes=[self layoutAttributesForItemAtIndexPath:itemIndexPath]; - } - CATransform3D moveTransform=CATransform3DMakeTranslation(-320.0f, 0.0f, 0.0f); - attributes.transform3D=CATransform3DConcat(attributes.transform3D, moveTransform); - } - return attributes; - - } - - -Beginning will be some unexpected animation, scrolling to the end, and then press command + t to open slow animations in simulator can see very clearly. When slide left to remove the last two cell, at the beginning of remove effect it works normal, but when almost complete the remove effect, will see one flash happened at a very strange position between two cells, and then slowly return to the normal animation. - -Now the question is, if I remove the cell of button-0, button-1, button-2, button-3, the animation is OK, but if I delete the last several cell of button-6, button -7, button-8, it will appear unexpected animation. - -And I found that if the flip angle is all fixed, then when delete cell, there will not have strange animation, my `makeRotateTransformForAttributes2` is assigned a fixed angle. -####Fixed - -Then finally know where the problem lies, just because the miscalculation of contentSize leading to the lack of content area, so when the cell is deleted and then rolling will produce this behaviour. so the height which be set in `- (CGSize) collectionViewContentSize` must be correct. - -###Implement add page - -Now the `WKPagesCollectionView` have two states, one is `normal` state, another is `highlight` state. At normal state, one can scroll the pages. When tap on one page, it will trigger to transfer to `highlight` state. In highlight state the page be tapped will be displayed in full screen. - -When you go to add a new page, you need to press `+` which at the bottom of screen to add a page, then the last page which be added will be displayed in full screen(`highlight` state). If currently is in `highlight` state, it will back to `normal` state and then transfer to `highlight` state to display the last page in full screen. - -Here is add page method in `WKPagesCollectionView`: - - ///Append an item - -(void)appendItem{ - if (self.isHighLight){ - [self dismissFromHightLightWithCompletion:^(BOOL finished) { - [self _addNewPage]; - }]; - } - else{ - [self _addNewPage]; - } - } - ///Add a new page - -(void)_addNewPage{ - int total=[self numberOfItemsInSection:0]; - [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; - double delayInSeconds = 0.3f; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - ///Add an item - [(id)self.dataSource willAppendItemInCollectionView:self]; - int lastRow=total; - NSIndexPath* insertIndexPath=[NSIndexPath indexPathForItem:lastRow inSection:0]; - [self performBatchUpdates:^{ - [self insertItemsAtIndexPaths:@[insertIndexPath]]; - } completion:^(BOOL finished) { - double delayInSeconds = 0.3f; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - [self showCellToHighLightAtIndexPath:insertIndexPath completion:^(BOOL finished) { - - }]; - }); - - }]; - }); - } From f14c481905ddcb1b6a87daf6267f614762cdc84f Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Wed, 3 Dec 2014 10:06:40 +0800 Subject: [PATCH 14/31] Swipe to delete is not sensitive enough --- .../WKPagesCollectionView/WKPagesCollectionViewCell.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m index 7b3945d..6fd66ef 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m @@ -133,7 +133,8 @@ -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ } -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ if (self.showingState==WKPagesCollectionViewCellShowingStateNormal){ - if (scrollView.contentOffset.x>=90.0f){ + CGFloat slideDistance = scrollView.frame.size.width / 6; + if (scrollView.contentOffset.x >= slideDistance){ NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; NSLog(@"delete cell at %ld",(long)indexPath.row); //self.alpha=0.0f; From 13defcf529bbe82bfa721b8ab8db94682590ecef Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Wed, 3 Dec 2014 19:07:39 +0800 Subject: [PATCH 15/31] Add a close button --- .../project.pbxproj | 6 +++ .../WKPagesCollectionView/WKCloseButton.h | 13 +++++ .../WKPagesCollectionView/WKCloseButton.m | 46 ++++++++++++++++ .../WKPagesCollectionViewCell.h | 2 + .../WKPagesCollectionViewCell.m | 54 ++++++++++++++----- 5 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h create mode 100644 WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m diff --git a/WKPagesCollectionView.xcodeproj/project.pbxproj b/WKPagesCollectionView.xcodeproj/project.pbxproj index 644fa51..881f837 100644 --- a/WKPagesCollectionView.xcodeproj/project.pbxproj +++ b/WKPagesCollectionView.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 58C2EC3E1A2F223100583CDE /* WKCloseButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C2EC3D1A2F223100583CDE /* WKCloseButton.m */; }; 68A1CF27184CD0DB00346DF8 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 68A1CF26184CD0DB00346DF8 /* README.md */; }; 68BDCE7C18432CCA00DB81A2 /* WKPagesCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 68BDCE7718432CCA00DB81A2 /* WKPagesCollectionView.m */; }; 68BDCE7D18432CCA00DB81A2 /* WKPagesCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 68BDCE7918432CCA00DB81A2 /* WKPagesCollectionViewCell.m */; }; @@ -24,6 +25,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 58C2EC3C1A2F223100583CDE /* WKCloseButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKCloseButton.h; sourceTree = ""; }; + 58C2EC3D1A2F223100583CDE /* WKCloseButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKCloseButton.m; sourceTree = ""; }; 68A1CF26184CD0DB00346DF8 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = SOURCE_ROOT; }; 68BDCE7518432CCA00DB81A2 /* WK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WK.h; sourceTree = ""; }; 68BDCE7618432CCA00DB81A2 /* WKPagesCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKPagesCollectionView.h; sourceTree = ""; }; @@ -75,6 +78,8 @@ 68BDCE7918432CCA00DB81A2 /* WKPagesCollectionViewCell.m */, 68BDCE7A18432CCA00DB81A2 /* WKPagesCollectionViewFlowLayout.h */, 68BDCE7B18432CCA00DB81A2 /* WKPagesCollectionViewFlowLayout.m */, + 58C2EC3C1A2F223100583CDE /* WKCloseButton.h */, + 58C2EC3D1A2F223100583CDE /* WKCloseButton.m */, ); path = WKPagesCollectionView; sourceTree = ""; @@ -205,6 +210,7 @@ 68D7C1E918347A08006B418C /* ViewController.m in Sources */, 68D7C1E318347A08006B418C /* AppDelegate.m in Sources */, 68BDCE7C18432CCA00DB81A2 /* WKPagesCollectionView.m in Sources */, + 58C2EC3E1A2F223100583CDE /* WKCloseButton.m in Sources */, 68D7C1DF18347A08006B418C /* main.m in Sources */, 68BDCE7E18432CCA00DB81A2 /* WKPagesCollectionViewFlowLayout.m in Sources */, 68BDCE7D18432CCA00DB81A2 /* WKPagesCollectionViewCell.m in Sources */, diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h new file mode 100644 index 0000000..8051441 --- /dev/null +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h @@ -0,0 +1,13 @@ +// +// WKCloseButton.h +// WKPagesCollectionView +// +// Created by Xu Zhao on 3/12/14. +// Copyright (c) 2014 秦 道平. All rights reserved. +// + +#import + +@interface WKCloseButton : UIButton + +@end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m new file mode 100644 index 0000000..77642c6 --- /dev/null +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m @@ -0,0 +1,46 @@ +// +// WKCloseButton.m +// WKPagesCollectionView +// +// Created by Xu Zhao on 3/12/14. +// Copyright (c) 2014 秦 道平. All rights reserved. +// + +#import "WKCloseButton.h" +#import +@implementation WKCloseButton + + +-(id) initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + self.backgroundColor = [UIColor clearColor]; + if (self){ + [self drawCloseButton]; + } + return self; + +} +#pragma mark - DrawButton +-(void) drawCloseButton +{ + + CGFloat xOffset = self.bounds.size.width / 7; + CGFloat yOffset = self.bounds.size.width / 7; + CGFloat width = self.frame.size.width * 0.3; + CGFloat height = self.frame.size.height * 0.3; + UIBezierPath *path = [UIBezierPath bezierPath]; + [path moveToPoint:CGPointMake(xOffset, yOffset)]; + [path addLineToPoint:CGPointMake(width + xOffset, height + yOffset)]; + [path moveToPoint:CGPointMake(width + xOffset, yOffset)]; + [path addLineToPoint:CGPointMake(xOffset, height + yOffset)]; + + CAShapeLayer *shapeLayer = [CAShapeLayer layer]; + [shapeLayer setPath:[path CGPath]]; + [shapeLayer setStrokeColor:[[UIColor blackColor] CGColor]]; + [shapeLayer setLineWidth:1.0f]; + + [[self layer] addSublayer:shapeLayer]; +} + +@end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h index 22db0d1..c23c553 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h @@ -7,6 +7,7 @@ // #import +@class WKCloseButton; typedef enum WKPagesCollectionViewCellShowingState:NSUInteger{ WKPagesCollectionViewCellShowingStateNormal=0, WKPagesCollectionViewCellShowingStateHightlight=1, @@ -17,6 +18,7 @@ typedef enum WKPagesCollectionViewCellShowingState:NSUInteger{ WKPagesCollectionViewCellShowingState _showingState; UITapGestureRecognizer* _tapGesture; UIScrollView* _scrollView; + WKCloseButton* _closeButton; // UIImageView* _maskImageView; } ///Position the normal state diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m index 6fd66ef..26fa51f 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m @@ -8,6 +8,9 @@ #import "WKPagesCollectionViewCell.h" #import "WKPagesCollectionView.h" +#import "WKCloseButton.h" +#define CLOSE_BUTTON_WIDTH 35 +#define CLOSE_BUTTON_HEIGHT CLOSE_BUTTON_WIDTH * 1.5 @implementation WKPagesCollectionViewCell @dynamic showingState; - (id)initWithFrame:(CGRect)frame @@ -44,6 +47,13 @@ - (id)initWithFrame:(CGRect)frame _tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(onTapGesture:)]; [_scrollView addGestureRecognizer:_tapGesture]; } + + if (!_closeButton) { + _closeButton = [[WKCloseButton alloc] initWithFrame:CGRectMake(0, 0, CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_HEIGHT)]; + [_closeButton addTarget:self action:@selector(closeButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + [_scrollView addSubview:_closeButton]; + } + } return self; } @@ -77,6 +87,12 @@ -(IBAction)onTapGesture:(UITapGestureRecognizer*)tapGesture{ NSLog(@"highlight completed"); }]; } + +-(IBAction) closeButtonPressed:(id)sender +{ + [self removeCurrentCell]; + +} #pragma mark - Properties -(void)setShowingState:(WKPagesCollectionViewCellShowingState)showingState{ if (_showingState==showingState) @@ -89,6 +105,7 @@ -(void)setShowingState:(WKPagesCollectionViewCellShowingState)showingState{ case WKPagesCollectionViewCellShowingStateHightlight:{ self.normalTransform=self.layer.transform;///The original location of the first record _scrollView.scrollEnabled=NO; + _closeButton.hidden = YES; NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; CGFloat moveY=self.collectionView.contentOffset.y-(WKPagesCollectionViewPageSpacing)*indexPath.row +topMargin; CATransform3D moveTransform=CATransform3DMakeTranslation(0.0f, moveY, 0.0f); @@ -98,6 +115,7 @@ -(void)setShowingState:(WKPagesCollectionViewCellShowingState)showingState{ case WKPagesCollectionViewCellShowingStateBackToTop:{ self.normalTransform=self.layer.transform;///The original location of the first record _scrollView.scrollEnabled=NO; + _closeButton.hidden = NO; CATransform3D moveTransform=CATransform3DMakeTranslation(0, -1*pageHeight-topMargin, 0); self.layer.transform=CATransform3DConcat(CATransform3DIdentity, moveTransform); } @@ -105,6 +123,7 @@ -(void)setShowingState:(WKPagesCollectionViewCellShowingState)showingState{ case WKPagesCollectionViewCellShowingStateBackToBottom:{ self.normalTransform=self.layer.transform;///The original location of the first record _scrollView.scrollEnabled=NO; + _closeButton.hidden = NO; CATransform3D moveTransform=CATransform3DMakeTranslation(0, pageHeight+topMargin, 0); self.layer.transform=CATransform3DConcat(CATransform3DIdentity, moveTransform); } @@ -112,6 +131,7 @@ -(void)setShowingState:(WKPagesCollectionViewCellShowingState)showingState{ case WKPagesCollectionViewCellShowingStateNormal:{ self.layer.transform=self.normalTransform; _scrollView.scrollEnabled=YES; + _closeButton.hidden = NO; } break; default: @@ -124,6 +144,27 @@ -(void)setShowingState:(WKPagesCollectionViewCellShowingState)showingState{ -(WKPagesCollectionViewCellShowingState)showingState{ return _showingState; } + + +#pragma mark - Remove cell + +-(void) removeCurrentCell +{ + NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; + NSLog(@"delete cell at %ld",(long)indexPath.row); + //self.alpha=0.0f; + ///Delete data + id pagesDataSource=(id)self.collectionView.dataSource; + [pagesDataSource collectionView:(WKPagesCollectionView*)self.collectionView willRemoveCellAtIndexPath:indexPath]; + ///Animation + [self.collectionView performBatchUpdates:^{ + [self.collectionView deleteItemsAtIndexPaths:@[indexPath,]]; + } completion:^(BOOL finished) { + + }]; + +} + #pragma mark - UIScrollViewDelegate -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ @@ -135,18 +176,7 @@ -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL) if (self.showingState==WKPagesCollectionViewCellShowingStateNormal){ CGFloat slideDistance = scrollView.frame.size.width / 6; if (scrollView.contentOffset.x >= slideDistance){ - NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; - NSLog(@"delete cell at %ld",(long)indexPath.row); - //self.alpha=0.0f; - ///Delete data - id pagesDataSource=(id)self.collectionView.dataSource; - [pagesDataSource collectionView:(WKPagesCollectionView*)self.collectionView willRemoveCellAtIndexPath:indexPath]; - ///Animation - [self.collectionView performBatchUpdates:^{ - [self.collectionView deleteItemsAtIndexPaths:@[indexPath,]]; - } completion:^(BOOL finished) { - - }]; + [self removeCurrentCell]; } } } From 2c442c4ab514b30da66a32048530a46cb8f527b5 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Thu, 4 Dec 2014 09:54:19 +0800 Subject: [PATCH 16/31] Code formatting and refactoring --- .../WKPagesCollectionView/WKCloseButton.m | 3 +-- .../WKPagesCollectionViewCell.h | 2 +- .../WKPagesCollectionViewCell.m | 14 ++++++-------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m index 77642c6..d0bf50f 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m @@ -14,7 +14,6 @@ @implementation WKCloseButton -(id) initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; - self.backgroundColor = [UIColor clearColor]; if (self){ [self drawCloseButton]; } @@ -24,7 +23,7 @@ -(id) initWithFrame:(CGRect)frame #pragma mark - DrawButton -(void) drawCloseButton { - + self.backgroundColor = [UIColor clearColor]; CGFloat xOffset = self.bounds.size.width / 7; CGFloat yOffset = self.bounds.size.width / 7; CGFloat width = self.frame.size.width * 0.3; diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h index c23c553..8adf184 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h @@ -7,7 +7,7 @@ // #import -@class WKCloseButton; +#import "WKCloseButton.h" typedef enum WKPagesCollectionViewCellShowingState:NSUInteger{ WKPagesCollectionViewCellShowingStateNormal=0, WKPagesCollectionViewCellShowingStateHightlight=1, diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m index 26fa51f..668f8dc 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m @@ -9,8 +9,8 @@ #import "WKPagesCollectionViewCell.h" #import "WKPagesCollectionView.h" #import "WKCloseButton.h" -#define CLOSE_BUTTON_WIDTH 35 -#define CLOSE_BUTTON_HEIGHT CLOSE_BUTTON_WIDTH * 1.5 +#define CloseButtonWidth 35 +#define CloseButtonHeight CloseButtonWidth * 1.5 @implementation WKPagesCollectionViewCell @dynamic showingState; - (id)initWithFrame:(CGRect)frame @@ -49,7 +49,7 @@ - (id)initWithFrame:(CGRect)frame } if (!_closeButton) { - _closeButton = [[WKCloseButton alloc] initWithFrame:CGRectMake(0, 0, CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_HEIGHT)]; + _closeButton = [[WKCloseButton alloc] initWithFrame:CGRectMake(0, 0, CloseButtonWidth, CloseButtonHeight)]; [_closeButton addTarget:self action:@selector(closeButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; [_scrollView addSubview:_closeButton]; } @@ -88,7 +88,7 @@ -(IBAction)onTapGesture:(UITapGestureRecognizer*)tapGesture{ }]; } --(IBAction) closeButtonPressed:(id)sender +-(void) closeButtonPressed:(id)sender { [self removeCurrentCell]; @@ -146,17 +146,15 @@ -(WKPagesCollectionViewCellShowingState)showingState{ } -#pragma mark - Remove cell - -(void) removeCurrentCell { NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; NSLog(@"delete cell at %ld",(long)indexPath.row); //self.alpha=0.0f; - ///Delete data + //Delete data id pagesDataSource=(id)self.collectionView.dataSource; [pagesDataSource collectionView:(WKPagesCollectionView*)self.collectionView willRemoveCellAtIndexPath:indexPath]; - ///Animation + //Animation [self.collectionView performBatchUpdates:^{ [self.collectionView deleteItemsAtIndexPaths:@[indexPath,]]; } completion:^(BOOL finished) { From 6f286375cafe4ce24b082d58766bfc6f64562b25 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Thu, 4 Dec 2014 18:11:51 +0800 Subject: [PATCH 17/31] Fix merge conflict --- .../WKPagesCollectionView/WKPagesCollectionViewCell.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m index 668f8dc..41f09ba 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m @@ -11,6 +11,7 @@ #import "WKCloseButton.h" #define CloseButtonWidth 35 #define CloseButtonHeight CloseButtonWidth * 1.5 +#define HighLightRotateAngle -10.0f @implementation WKPagesCollectionViewCell @dynamic showingState; - (id)initWithFrame:(CGRect)frame @@ -116,16 +117,18 @@ -(void)setShowingState:(WKPagesCollectionViewCellShowingState)showingState{ self.normalTransform=self.layer.transform;///The original location of the first record _scrollView.scrollEnabled=NO; _closeButton.hidden = NO; + CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(HighLightRotateAngle); CATransform3D moveTransform=CATransform3DMakeTranslation(0, -1*pageHeight-topMargin, 0); - self.layer.transform=CATransform3DConcat(CATransform3DIdentity, moveTransform); + self.layer.transform=CATransform3DConcat(rotateTransform, moveTransform); } break; case WKPagesCollectionViewCellShowingStateBackToBottom:{ self.normalTransform=self.layer.transform;///The original location of the first record _scrollView.scrollEnabled=NO; _closeButton.hidden = NO; + CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(HighLightRotateAngle); CATransform3D moveTransform=CATransform3DMakeTranslation(0, pageHeight+topMargin, 0); - self.layer.transform=CATransform3DConcat(CATransform3DIdentity, moveTransform); + self.layer.transform=CATransform3DConcat(rotateTransform, moveTransform); } break; case WKPagesCollectionViewCellShowingStateNormal:{ From 06bcf0c0bd0a484ff3f115d213ffb1fdd0f9e289 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Thu, 4 Dec 2014 19:11:03 +0800 Subject: [PATCH 18/31] Increasing the animation speed --- .../WKPagesCollectionView/WKPagesCollectionView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index 775033f..65d5751 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -28,8 +28,8 @@ -(id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:realFrame collectionViewLayout:flowLayout]; if (self){ self.contentInset=UIEdgeInsetsMake(20.0f, 0.0f, 0.0f, 0.0f); - self.highLightAnimationDuration=0.5f; - self.dismisalAnimationDuration=0.5f; + self.highLightAnimationDuration=0.3f; + self.dismisalAnimationDuration=0.3f; } return self; } From f2432d869f4a07fe5b88333b05068bbd0f2ca748 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Mon, 8 Dec 2014 15:09:29 +0800 Subject: [PATCH 19/31] For fix a crashing issue --- WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m | 1 - 1 file changed, 1 deletion(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index 65d5751..b1115f8 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -151,7 +151,6 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath{ if (_isHighLight){ return; } - [self scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO]; double delayInSeconds = 0.01f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ From 65f69ef6f42b16e93c13771c018f0bb03571de05 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Mon, 8 Dec 2014 15:35:58 +0800 Subject: [PATCH 20/31] Add mask view gradually UI effect --- .../WKPagesCollectionView/WKPagesCollectionView.m | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index b1115f8..9f4b59a 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -118,7 +118,9 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void double delayInSeconds = 0.3f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - self.maskShow=NO; + self.maskShow=YES; + _maskImageView.hidden = NO; + _maskImageView.alpha = 1.0; self.scrollEnabled=NO; [UIView animateWithDuration:self.highLightAnimationDuration delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ [self.visibleCells enumerateObjectsUsingBlock:^(WKPagesCollectionViewCell* cell, NSUInteger idx, BOOL *stop) { @@ -136,9 +138,11 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void else{ cell.showingState=WKPagesCollectionViewCellShowingStateNormal; } + _maskImageView.alpha = 0.0; }]; } completion:^(BOOL finished) { _isHighLight=YES; + self.maskShow=NO; completion(finished); if ([self.delegate respondsToSelector:@selector(collectionView:didShownToHightlightAtIndexPath:)]){ [(id)self.delegate collectionView:self didShownToHightlightAtIndexPath:indexPath]; @@ -178,11 +182,13 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath{ ///Back to the original state -(void)dismissFromHightLightWithCompletion:(void (^)(BOOL))completion{ self.maskShow=YES; + _maskImageView.alpha = 0.0; if (!_isHighLight) return; [UIView animateWithDuration:self.dismisalAnimationDuration delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ [self.visibleCells enumerateObjectsUsingBlock:^(WKPagesCollectionViewCell* cell, NSUInteger idx, BOOL *stop) { cell.showingState=WKPagesCollectionViewCellShowingStateNormal; + _maskImageView.alpha = 1.0; }]; } completion:^(BOOL finished) { self.scrollEnabled=YES; From 865171def77c1a74568ef29c4c02198f6379d9b9 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Mon, 8 Dec 2014 16:29:14 +0800 Subject: [PATCH 21/31] Adjust close button size --- WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h | 8 +++++++- WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m | 8 ++++---- .../WKPagesCollectionView/WKPagesCollectionViewCell.m | 3 --- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h index 8051441..29c53fc 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h @@ -7,7 +7,13 @@ // #import - +#define HighLightRotateAngle -10.0f +#define CrossXOffset 12 +#define CrossYOffset 15 +#define CrossWidth 10.5 +#define CrossHeight 15.75 +#define CloseButtonWidth 120 +#define CloseButtonHeight 120 @interface WKCloseButton : UIButton @end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m index d0bf50f..0cb600c 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m @@ -24,10 +24,10 @@ -(id) initWithFrame:(CGRect)frame -(void) drawCloseButton { self.backgroundColor = [UIColor clearColor]; - CGFloat xOffset = self.bounds.size.width / 7; - CGFloat yOffset = self.bounds.size.width / 7; - CGFloat width = self.frame.size.width * 0.3; - CGFloat height = self.frame.size.height * 0.3; + CGFloat xOffset = CrossXOffset; + CGFloat yOffset = CrossYOffset; + CGFloat width = CrossWidth; + CGFloat height = CrossHeight; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(xOffset, yOffset)]; [path addLineToPoint:CGPointMake(width + xOffset, height + yOffset)]; diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m index 41f09ba..f0653f1 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m @@ -9,9 +9,6 @@ #import "WKPagesCollectionViewCell.h" #import "WKPagesCollectionView.h" #import "WKCloseButton.h" -#define CloseButtonWidth 35 -#define CloseButtonHeight CloseButtonWidth * 1.5 -#define HighLightRotateAngle -10.0f @implementation WKPagesCollectionViewCell @dynamic showingState; - (id)initWithFrame:(CGRect)frame From 1e82df8668836d4e696d61f23561fdf06d5a9252 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Mon, 8 Dec 2014 16:34:09 +0800 Subject: [PATCH 22/31] Increase add page speed --- .../WKPagesCollectionView/WKPagesCollectionView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index 9f4b59a..fc3c8c4 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -219,7 +219,7 @@ -(void)_addNewPage{ [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; } - double delayInSeconds = 0.3f; + double delayInSeconds = 0.001f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ ///Add Data @@ -229,7 +229,7 @@ -(void)_addNewPage{ [self performBatchUpdates:^{ [self insertItemsAtIndexPaths:@[insertIndexPath]]; } completion:^(BOOL finished) { - double delayInSeconds = 0.3f; + double delayInSeconds = 0.001f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [self showCellToHighLightAtIndexPath:insertIndexPath completion:^(BOOL finished) { From 3ac1c1be04ce6953dfef356fffe18cc52b49f13e Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Mon, 8 Dec 2014 17:37:49 +0800 Subject: [PATCH 23/31] Adjust animation when add new page --- WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index fc3c8c4..4523ae5 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -216,7 +216,7 @@ -(void)appendItem{ -(void)_addNewPage{ NSInteger total=[self numberOfItemsInSection:0]; if (total > 0) { - [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; + [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; } double delayInSeconds = 0.001f; From 7592e028f366817cbe0b5751b30ce8fc41150d4d Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Tue, 9 Dec 2014 14:24:19 +0800 Subject: [PATCH 24/31] Code formatting --- WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h | 4 ---- WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m | 8 ++++---- .../WKPagesCollectionView/WKPagesCollectionView.m | 8 ++++---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h index 29c53fc..4c763d3 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h @@ -8,10 +8,6 @@ #import #define HighLightRotateAngle -10.0f -#define CrossXOffset 12 -#define CrossYOffset 15 -#define CrossWidth 10.5 -#define CrossHeight 15.75 #define CloseButtonWidth 120 #define CloseButtonHeight 120 @interface WKCloseButton : UIButton diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m index 0cb600c..55887d0 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m @@ -24,10 +24,10 @@ -(id) initWithFrame:(CGRect)frame -(void) drawCloseButton { self.backgroundColor = [UIColor clearColor]; - CGFloat xOffset = CrossXOffset; - CGFloat yOffset = CrossYOffset; - CGFloat width = CrossWidth; - CGFloat height = CrossHeight; + CGFloat xOffset = 12; + CGFloat yOffset = 15; + CGFloat width = 11; + CGFloat height = 16; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(xOffset, yOffset)]; [path addLineToPoint:CGPointMake(width + xOffset, height + yOffset)]; diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index 4523ae5..50e3d8f 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -118,10 +118,10 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void double delayInSeconds = 0.3f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - self.maskShow=YES; + self.maskShow = YES; _maskImageView.hidden = NO; _maskImageView.alpha = 1.0; - self.scrollEnabled=NO; + self.scrollEnabled = NO; [UIView animateWithDuration:self.highLightAnimationDuration delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ [self.visibleCells enumerateObjectsUsingBlock:^(WKPagesCollectionViewCell* cell, NSUInteger idx, BOOL *stop) { NSIndexPath* visibleIndexPath=[self indexPathForCell:cell]; @@ -141,8 +141,8 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void _maskImageView.alpha = 0.0; }]; } completion:^(BOOL finished) { - _isHighLight=YES; - self.maskShow=NO; + _isHighLight = YES; + self.maskShow = NO; completion(finished); if ([self.delegate respondsToSelector:@selector(collectionView:didShownToHightlightAtIndexPath:)]){ [(id)self.delegate collectionView:self didShownToHightlightAtIndexPath:indexPath]; From ade9f71027e5495bf76c2f8d5c473ecb2eac5ba7 Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Tue, 16 Dec 2014 11:38:30 +1030 Subject: [PATCH 25/31] add index checking to prevent crash when highlighting cells --- .../WKPagesCollectionView/WKPagesCollectionView.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index 50e3d8f..dda37e9 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -101,6 +101,11 @@ -(UIImage*)makeGradientImage{ ///Display status -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void (^)(BOOL))completion{ NSLog(@"row:%ld",(long)indexPath.row); + + if (indexPath.row >= [self numberOfItemsInSection:indexPath.section]){ + return; + } + if (_isHighLight){ return; } @@ -152,9 +157,14 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void } -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath{ + if (indexPath.row >= [self numberOfItemsInSection:indexPath.section]) { + return; + } + if (_isHighLight){ return; } + double delayInSeconds = 0.01f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ From 621da3d11e75bb4eea55fa080da59575aaa625a2 Mon Sep 17 00:00:00 2001 From: nick-iqnect Date: Tue, 16 Dec 2014 10:54:12 +0800 Subject: [PATCH 26/31] fix issue of graphical glitch when adding several tabs quickly --- .../WKPagesCollectionView/WKPagesCollectionView.h | 2 +- .../WKPagesCollectionView/WKPagesCollectionView.m | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.h b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.h index 537683a..df899c8 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.h @@ -35,7 +35,7 @@ @property (nonatomic,assign) BOOL maskShow; ///are showing @property (readonly,nonatomic,assign) BOOL isHighLight; - +@property (nonatomic, assign) BOOL isAddingNewPage; ///top offscreen margin @property (nonatomic,assign) CGFloat topOffScreenMargin; ///duration from normal to highlight state,default is 0.5 second diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index dda37e9..048822a 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -213,6 +213,10 @@ -(void)dismissFromHightLightWithCompletion:(void (^)(BOOL))completion{ } ///Append a page -(void)appendItem{ + if (self.isAddingNewPage) { + return; + } + self.isAddingNewPage = YES; if (self.isHighLight){ [self dismissFromHightLightWithCompletion:^(BOOL finished) { [self _addNewPage]; @@ -243,7 +247,7 @@ -(void)_addNewPage{ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [self showCellToHighLightAtIndexPath:insertIndexPath completion:^(BOOL finished) { - + self.isAddingNewPage = NO; }]; }); From 36176061d8e298eec2cff18fa49ee292b9d7cd2b Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Mon, 20 Apr 2015 12:41:50 +0930 Subject: [PATCH 27/31] converted project to ARC --- .../project.pbxproj | 4 ++-- WKPagesScrollView/ViewController.m | 23 ++++++------------- .../WKPagesCollectionView.m | 6 +---- .../WKPagesCollectionViewCell.h | 4 ++-- .../WKPagesCollectionViewCell.m | 6 ----- .../WKPagesCollectionViewFlowLayout.m | 4 ++-- 6 files changed, 14 insertions(+), 33 deletions(-) diff --git a/WKPagesCollectionView.xcodeproj/project.pbxproj b/WKPagesCollectionView.xcodeproj/project.pbxproj index 881f837..ef7f5ab 100644 --- a/WKPagesCollectionView.xcodeproj/project.pbxproj +++ b/WKPagesCollectionView.xcodeproj/project.pbxproj @@ -314,7 +314,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_ARC = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "WKPagesScrollView/WKPagesCollectionView-Prefix.pch"; INFOPLIST_FILE = "WKPagesScrollView/WKPagesCollectionView-Info.plist"; @@ -328,7 +328,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_ARC = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "WKPagesScrollView/WKPagesCollectionView-Prefix.pch"; INFOPLIST_FILE = "WKPagesScrollView/WKPagesCollectionView-Info.plist"; diff --git a/WKPagesScrollView/ViewController.m b/WKPagesScrollView/ViewController.m index e0a1bb2..c041d6b 100644 --- a/WKPagesScrollView/ViewController.m +++ b/WKPagesScrollView/ViewController.m @@ -25,7 +25,7 @@ - (void)viewDidLoad for (int a=0; a<=30; a++) { [_array addObject:[NSString stringWithFormat:@"button %d",a]]; } - _collectionView=[[[WKPagesCollectionView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height)] autorelease]; + _collectionView=[[WKPagesCollectionView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height)]; _collectionView.dataSource=self; _collectionView.delegate=self; [_collectionView registerClass:[WKPagesCollectionViewCell class] forCellWithReuseIdentifier:@"cell"]; @@ -33,30 +33,21 @@ - (void)viewDidLoad _collectionView.maskShow=YES; - UIToolbar* toolBar=[[[UIToolbar alloc]initWithFrame:CGRectMake(0.0f, self.view.frame.size.height-50.0f, self.view.frame.size.width, 50.0f)] autorelease]; + UIToolbar* toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0.0f, self.view.frame.size.height-50.0f, self.view.frame.size.width, 50.0f)]; toolBar.barStyle=UIBarStyleBlackTranslucent; toolBar.translucent=YES; toolBar.tintColor=[UIColor whiteColor]; [self.view addSubview:toolBar]; - UIBarButtonItem* addButtonItem=[[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(onButtonAdd:)] autorelease]; + UIBarButtonItem* addButtonItem=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(onButtonAdd:)]; toolBar.items=@[ - [[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], addButtonItem, - [[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease],]; + [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],]; } -- (void)didReceiveMemoryWarning -{ - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} --(void)dealloc{ - [_array release]; - [_collectionView release]; - [super dealloc]; -} + -(IBAction)onButtonTitle:(id)sender{ UIView *thisButton = (UIView *)sender; if (!_collectionView.isHighLight) { @@ -90,7 +81,7 @@ -(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellFo static NSString* identity=@"cell"; WKPagesCollectionViewCell* cell=(WKPagesCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:identity forIndexPath:indexPath]; cell.collectionView=collectionView; - UIImageView* imageView=[[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image-0"]] autorelease]; + UIImageView* imageView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image-0"]]; imageView.frame=self.view.bounds; [cell.cellContentView addSubview:imageView]; UIButton* button=[UIButton buttonWithType:UIButtonTypeCustom]; diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index 048822a..669e096 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -22,7 +22,7 @@ - (CGFloat)topOffScreenMargin return _topOffScreenMargin; } -(id)initWithFrame:(CGRect)frame{ - WKPagesCollectionViewFlowLayout* flowLayout=[[[WKPagesCollectionViewFlowLayout alloc ] init] autorelease]; + WKPagesCollectionViewFlowLayout* flowLayout=[[WKPagesCollectionViewFlowLayout alloc ] init]; CGRect realFrame = CGRectMake(frame.origin.x, frame.origin.y-self.topOffScreenMargin, frame.size.width, frame.size.height + self.topOffScreenMargin); self = [super initWithFrame:realFrame collectionViewLayout:flowLayout]; @@ -33,10 +33,6 @@ -(id)initWithFrame:(CGRect)frame{ } return self; } --(void)dealloc{ - [_maskImageView release]; - [super dealloc]; -} -(void)setHidden:(BOOL)hidden{ [super setHidden:hidden]; if (hidden){ diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h index 8adf184..2cbe4f5 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h @@ -28,7 +28,7 @@ typedef enum WKPagesCollectionViewCellShowingState:NSUInteger{ ///Display status @property (nonatomic,assign) WKPagesCollectionViewCellShowingState showingState; ///Quote collectionView -@property (nonatomic,assign) UICollectionView* collectionView; -@property (nonatomic,retain) UIView* cellContentView; +@property (nonatomic,weak) UICollectionView* collectionView; +@property (nonatomic,strong) UIView* cellContentView; -(UIImage*)makeGradientImage; @end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m index f0653f1..d1558d0 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m @@ -64,12 +64,6 @@ - (void)drawRect:(CGRect)rect // Drawing code } */ --(void)dealloc{ - [_tapGesture release]; - [_cellContentView release]; - [_scrollView release]; - [super dealloc]; -} -(void)prepareForReuse{ [super prepareForReuse]; for (UIView* view in _cellContentView.subviews) { diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m index 18b2082..36f9179 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m @@ -11,8 +11,8 @@ #import "WKPagesCollectionView.h" #define RotateDegree -60.0f @interface WKPagesCollectionViewFlowLayout() -@property (nonatomic,retain) NSMutableArray* deleteIndexPaths; -@property (nonatomic,retain) NSMutableArray* insertIndexPaths; +@property (nonatomic,strong) NSMutableArray* deleteIndexPaths; +@property (nonatomic,strong) NSMutableArray* insertIndexPaths; @end @implementation WKPagesCollectionViewFlowLayout{ From c07a2972c193fc172d3bf65581fe59059503ff9a Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Mon, 20 Apr 2015 14:45:04 +0930 Subject: [PATCH 28/31] clean up code styling, formatting and organization --- README.md | 10 +- .../project.pbxproj | 2 +- WKPagesScrollView/AppDelegate.h | 1 - WKPagesScrollView/ViewController.h | 5 +- WKPagesScrollView/ViewController.m | 133 ++++++------ WKPagesScrollView/WKPagesCollectionView/WK.h | 17 +- .../WKPagesCollectionView/WKCloseButton.h | 2 + .../WKPagesCollectionView/WKCloseButton.m | 9 +- .../WKPagesCollectionView.h | 47 ++-- .../WKPagesCollectionView.m | 197 ++++++++++------- .../WKPagesCollectionViewCell.h | 39 ++-- .../WKPagesCollectionViewCell.m | 203 ++++++++---------- .../WKPagesCollectionViewFlowLayout.h | 5 +- .../WKPagesCollectionViewFlowLayout.m | 159 +++++++------- 14 files changed, 420 insertions(+), 409 deletions(-) diff --git a/README.md b/README.md index 500ac7b..0b5041e 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,7 @@ I wanted to implement an UI effect like iOS7 Safari tabs pages. ![Effect video](http://farm4.staticflickr.com/3829/11171831814_9c5972bbe6_z.jpg)] - - -##Usage +## Usage * Add `WKPagesCollectionView` folder and the following files inside it to project :`WK.h`, `WKPagesCollectionView.h`, `WKPagesCollectionView.m`, `WKPagesCollectionViewCell.h`, `WKPagesCollectionViewCell.m`, `WKPagesCollectionViewFlowLayout.h`, `WKPagesCollectionViewFlowLayout.m`; * Import `WKPagesCollectionView`; * Prepare data @@ -222,15 +220,15 @@ Here is add page method in `WKPagesCollectionView`: -(void)appendItem{ if (self.isHighLight){ [self dismissFromHightLightWithCompletion:^(BOOL finished) { - [self _addNewPage]; + [self addNewPage]; }]; } else{ - [self _addNewPage]; + [self addNewPage]; } } ///Add a new page - -(void)_addNewPage{ + -(void)addNewPage{ int total=[self numberOfItemsInSection:0]; [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; double delayInSeconds = 0.3f; diff --git a/WKPagesCollectionView.xcodeproj/project.pbxproj b/WKPagesCollectionView.xcodeproj/project.pbxproj index ef7f5ab..3b8640a 100644 --- a/WKPagesCollectionView.xcodeproj/project.pbxproj +++ b/WKPagesCollectionView.xcodeproj/project.pbxproj @@ -87,6 +87,7 @@ 68D7C1C618347A08006B418C = { isa = PBXGroup; children = ( + 68A1CF26184CD0DB00346DF8 /* README.md */, 68D7C1D818347A08006B418C /* WKPagesCollectionView */, 68D7C1D118347A08006B418C /* Frameworks */, 68D7C1D018347A08006B418C /* Products */, @@ -116,7 +117,6 @@ 68D7C1D818347A08006B418C /* WKPagesCollectionView */ = { isa = PBXGroup; children = ( - 68A1CF26184CD0DB00346DF8 /* README.md */, 68D7C1E118347A08006B418C /* AppDelegate.h */, 68D7C1E218347A08006B418C /* AppDelegate.m */, 68D7C1E418347A08006B418C /* Main.storyboard */, diff --git a/WKPagesScrollView/AppDelegate.h b/WKPagesScrollView/AppDelegate.h index 6dde7d4..cd3115f 100644 --- a/WKPagesScrollView/AppDelegate.h +++ b/WKPagesScrollView/AppDelegate.h @@ -8,7 +8,6 @@ #import - @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; diff --git a/WKPagesScrollView/ViewController.h b/WKPagesScrollView/ViewController.h index bffa093..3422918 100644 --- a/WKPagesScrollView/ViewController.h +++ b/WKPagesScrollView/ViewController.h @@ -8,8 +8,7 @@ #import #import "WKPagesCollectionView.h" -@interface ViewController : UIViewController{ - -} + +@interface ViewController : UIViewController @end diff --git a/WKPagesScrollView/ViewController.m b/WKPagesScrollView/ViewController.m index c041d6b..f446c2c 100644 --- a/WKPagesScrollView/ViewController.m +++ b/WKPagesScrollView/ViewController.m @@ -8,10 +8,12 @@ #import "ViewController.h" -@interface ViewController (){ - WKPagesCollectionView* _collectionView; - NSMutableArray* _array; -} +static NSString *CellReuseIdentifier = @"CellReuseIdentifier"; + +@interface ViewController () + +@property (nonatomic, strong) WKPagesCollectionView *collectionView; +@property (nonatomic, strong) NSMutableArray *items; @end @@ -20,86 +22,97 @@ @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; - // Do any additional setup after loading the view, typically from a nib. - _array=[[NSMutableArray alloc]init]; - for (int a=0; a<=30; a++) { - [_array addObject:[NSString stringWithFormat:@"button %d",a]]; + + self.items = [[NSMutableArray alloc] init]; + + for (NSUInteger a = 0; a <= 30; a++) { + [self.items addObject:[NSString stringWithFormat:@"button %lu",(unsigned long)a]]; } - _collectionView=[[WKPagesCollectionView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height)]; - _collectionView.dataSource=self; - _collectionView.delegate=self; - [_collectionView registerClass:[WKPagesCollectionViewCell class] forCellWithReuseIdentifier:@"cell"]; - [self.view addSubview:_collectionView]; - _collectionView.maskShow=YES; + self.collectionView = [[WKPagesCollectionView alloc] initWithFrame:self.view.bounds]; + self.collectionView.dataSource=self; + self.collectionView.delegate=self; + [self.collectionView registerClass:[WKPagesCollectionViewCell class] forCellWithReuseIdentifier:CellReuseIdentifier]; + [self.view addSubview:self.collectionView]; + self.collectionView.maskShow = YES; - UIToolbar* toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0.0f, self.view.frame.size.height-50.0f, self.view.frame.size.width, 50.0f)]; - toolBar.barStyle=UIBarStyleBlackTranslucent; - toolBar.translucent=YES; - toolBar.tintColor=[UIColor whiteColor]; + UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, self.view.frame.size.height - 50.0, self.view.frame.size.width, 50.0)]; + toolBar.barStyle = UIBarStyleBlackTranslucent; + toolBar.translucent = YES; + toolBar.tintColor = [UIColor whiteColor]; [self.view addSubview:toolBar]; - - UIBarButtonItem* addButtonItem=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(onButtonAdd:)]; - toolBar.items=@[ - [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], - addButtonItem, - [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],]; + UIBarButtonItem *addButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(onButtonAdd:)]; + UIBarButtonItem *flexibleSpaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + toolBar.items = @[flexibleSpaceItem, + addButtonItem, + flexibleSpaceItem]; } - --(IBAction)onButtonTitle:(id)sender{ +- (IBAction)onButtonTitle:(id)sender +{ UIView *thisButton = (UIView *)sender; - if (!_collectionView.isHighLight) { - NSArray* visibleIndexPaths=[_collectionView indexPathsForVisibleItems]; - for (NSIndexPath* indexPath in visibleIndexPaths) { - WKPagesCollectionViewCell* cell = (WKPagesCollectionViewCell *)[_collectionView cellForItemAtIndexPath:indexPath]; - + if (!self.collectionView.isHighLight) { + NSArray *visibleIndexPaths = [self.collectionView indexPathsForVisibleItems]; + for (NSIndexPath *indexPath in visibleIndexPaths) { + WKPagesCollectionViewCell *cell = (WKPagesCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; BOOL doesContain = [cell.cellContentView.subviews containsObject:thisButton]; - if (doesContain ) { - [(WKPagesCollectionView*)_collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { + if (doesContain) { + [self.collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { NSLog(@"highlight completed"); }]; break; } } } else { - [_collectionView dismissFromHightLightWithCompletion:^(BOOL finished) { - NSLog(@"dismiss completed"); - }]; + [self.collectionView dismissFromHightLightWithCompletion:^(BOOL finished) { + NSLog(@"dismiss completed"); + }]; } } --(IBAction)onButtonAdd:(id)sender{ - [_collectionView appendItem]; + +- (IBAction)onButtonAdd:(id)sender +{ + [self.collectionView appendItem]; } -#pragma mark - UICollectionViewDataSource and UICollectionViewDelegate --(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ - return _array.count; + +#pragma mark - UICollectionViewDataSource + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return self.items.count; } --(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ -// NSLog(@"cellForItemAtIndexPath:%d",indexPath.row); - static NSString* identity=@"cell"; - WKPagesCollectionViewCell* cell=(WKPagesCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:identity forIndexPath:indexPath]; - cell.collectionView=collectionView; - UIImageView* imageView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image-0"]]; - imageView.frame=self.view.bounds; + +- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + WKPagesCollectionViewCell *cell = (WKPagesCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellReuseIdentifier forIndexPath:indexPath]; + cell.collectionView = collectionView; + + UIImageView* imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image-0"]]; + imageView.frame = self.view.bounds; [cell.cellContentView addSubview:imageView]; - UIButton* button=[UIButton buttonWithType:UIButtonTypeCustom]; - button.frame=CGRectMake(0, (indexPath.row+1)*10+100, 320, 50.0f); - button.backgroundColor=[UIColor whiteColor]; + + UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.frame = CGRectMake(0.0, 100.0, self.view.bounds.size.width, 50.0); + button.backgroundColor = [UIColor whiteColor]; [button setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal]; - [button setTitle:_array[indexPath.row] forState:UIControlStateNormal]; + [button setTitle:self.items[indexPath.row] forState:UIControlStateNormal]; [button addTarget:self action:@selector(onButtonTitle:) forControlEvents:UIControlEventTouchUpInside]; [cell.cellContentView addSubview:button]; + return cell; } -#pragma mark WKPagesCollectionViewDataSource -///追加数据 --(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView{ - [_array addObject:@"new button"]; + +#pragma mark - WKPagesCollectionViewDataSource + +- (void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView +{ + [self.items addObject:@"new button"]; } -///删除数据 --(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtIndexPath:(NSIndexPath *)indexPath{ - [_array removeObjectAtIndex:indexPath.row]; + +- (void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtIndexPath:(NSIndexPath *)indexPath +{ + [self.items removeObjectAtIndex:indexPath.row]; } -@end + +@end \ No newline at end of file diff --git a/WKPagesScrollView/WKPagesCollectionView/WK.h b/WKPagesScrollView/WKPagesCollectionView/WK.h index 9f3dba5..139d35d 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WK.h +++ b/WKPagesScrollView/WKPagesCollectionView/WK.h @@ -19,27 +19,18 @@ static inline CATransform3D WKFlipCATransform3DMakePerspective(CGPoint center, f scale.m34 = -1.0f/disZ; return CATransform3DConcat(CATransform3DConcat(transToCenter, scale), transBack); } + static inline CATransform3D WKFlipCATransform3DPerspect(CATransform3D t, CGPoint center, float disZ) { return CATransform3DConcat(t, WKFlipCATransform3DMakePerspective(center, disZ)); } + static inline CATransform3D WKFlipCATransform3DPerspectSimple(CATransform3D t){ return WKFlipCATransform3DPerspect(t, CGPointMake(0, 0), 1500.0f); } + static inline CATransform3D WKFlipCATransform3DPerspectSimpleWithRotate(CGFloat degree){ return WKFlipCATransform3DPerspectSimple(CATransform3DMakeRotation((M_PI*degree/180.0f), 1.0, 0.0, 0.0)); } -static inline UIImage* makeImageForView(UIView*view){ - double startTime=CFAbsoluteTimeGetCurrent(); - if(UIGraphicsBeginImageContextWithOptions != NULL){ - UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0); - } else { - UIGraphicsBeginImageContext(view.frame.size); - } - [view.layer renderInContext:UIGraphicsGetCurrentContext()]; - UIImage* image=UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - NSLog(@"makeImage duration:%f", CFAbsoluteTimeGetCurrent()-startTime); - return image; -} + #endif diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h index 4c763d3..ec8440d 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.h @@ -7,9 +7,11 @@ // #import + #define HighLightRotateAngle -10.0f #define CloseButtonWidth 120 #define CloseButtonHeight 120 + @interface WKCloseButton : UIButton @end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m index 55887d0..b0aa147 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKCloseButton.m @@ -8,20 +8,19 @@ #import "WKCloseButton.h" #import -@implementation WKCloseButton +@implementation WKCloseButton --(id) initWithFrame:(CGRect)frame +- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self){ [self drawCloseButton]; } return self; - } -#pragma mark - DrawButton --(void) drawCloseButton + +- (void)drawCloseButton { self.backgroundColor = [UIColor clearColor]; CGFloat xOffset = 12; diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.h b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.h index df899c8..a1ad728 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.h @@ -6,44 +6,40 @@ // Copyright (c) 2013年 秦 道平. All rights reserved. // - - #import #import "WKPagesCollectionViewFlowLayout.h" #import "WKPagesCollectionViewCell.h" + @class WKPagesCollectionView; -@protocol WKPagesCollectionViewDataSource + +@protocol WKPagesCollectionViewDataSource ///When you delete a cell is used to delete data --(void)collectionView:(WKPagesCollectionView*)collectionView willRemoveCellAtIndexPath:(NSIndexPath*)indexPath; +-(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtIndexPath:(NSIndexPath *)indexPath; ///Called when additional data --(void)willAppendItemInCollectionView:(WKPagesCollectionView*)collectionView; +-(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView; + @end + @protocol WKPagesCollectionViewDelegate + @optional ///When displaying a callback --(void)collectionView:(WKPagesCollectionView*)collectionView didShownToHightlightAtIndexPath:(NSIndexPath*)indexPath; +-(void)collectionView:(WKPagesCollectionView *)collectionView didShownToHightlightAtIndexPath:(NSIndexPath *)indexPath; ///Return to the original state when the callback --(void)didDismissFromHightlightOnCollectionView:(WKPagesCollectionView*)collectionView; +-(void)didDismissFromHightlightOnCollectionView:(WKPagesCollectionView *)collectionView; + @end -@interface WKPagesCollectionView : UICollectionView{ - UIImageView* _maskImageView; - BOOL _maskShow; -} -///Can I delete? -@property (nonatomic,assign) BOOL canRemove; -///show mask -@property (nonatomic,assign) BOOL maskShow; -///are showing -@property (readonly,nonatomic,assign) BOOL isHighLight; + +@interface WKPagesCollectionView : UICollectionView + +@property (nonatomic, assign) BOOL canRemove; +@property (nonatomic, assign) BOOL maskShow; +@property (readonly, nonatomic, assign) BOOL isHighLight; @property (nonatomic, assign) BOOL isAddingNewPage; -///top offscreen margin -@property (nonatomic,assign) CGFloat topOffScreenMargin; -///duration from normal to highlight state,default is 0.5 second -@property (nonatomic,assign) CGFloat highLightAnimationDuration; -///duration from highlight to nomral state, default is 0.5 second -@property (nonatomic,assign) CGFloat dismisalAnimationDuration; -#pragma mark - Action -///show +@property (nonatomic, assign) CGFloat topOffScreenMargin; +@property (nonatomic, assign) CGFloat highLightAnimationDuration; +@property (nonatomic, assign) CGFloat dismisalAnimationDuration; + -(void)showCellToHighLightAtIndexPath:(NSIndexPath*)indexPath completion:(void(^)(BOOL finished))completion; ///No animation display state, there will be didShowCellToHightLight callback -(void)showCellToHighLightAtIndexPath:(NSIndexPath*)indexPath; @@ -51,4 +47,5 @@ -(void)dismissFromHightLightWithCompletion:(void(^)(BOOL finished))completion; ///Additional content -(void)appendItem; + @end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m index 669e096..69a6eb1 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionView.m @@ -10,9 +10,31 @@ CGFloat const TOP_OFFSCREEN_MARGIN = 120; +@interface WKPagesCollectionView () + +@property (nonatomic, strong) UIImageView *maskImageView; + +@end + @implementation WKPagesCollectionView -@dynamic maskShow; +- (id)initWithFrame:(CGRect)frame +{ + WKPagesCollectionViewFlowLayout *flowLayout=[[WKPagesCollectionViewFlowLayout alloc ] init]; + flowLayout.itemSize = [UIScreen mainScreen].bounds.size; + + CGRect realFrame = CGRectMake(frame.origin.x, frame.origin.y-self.topOffScreenMargin, + frame.size.width, frame.size.height + self.topOffScreenMargin); + + self = [super initWithFrame:realFrame collectionViewLayout:flowLayout]; + if (self) { + self.contentInset = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0); + self.highLightAnimationDuration = 0.3; + self.dismisalAnimationDuration = 0.3; + } + + return self; +} - (CGFloat)topOffScreenMargin { @@ -21,48 +43,40 @@ - (CGFloat)topOffScreenMargin } return _topOffScreenMargin; } --(id)initWithFrame:(CGRect)frame{ - WKPagesCollectionViewFlowLayout* flowLayout=[[WKPagesCollectionViewFlowLayout alloc ] init]; - CGRect realFrame = CGRectMake(frame.origin.x, frame.origin.y-self.topOffScreenMargin, - frame.size.width, frame.size.height + self.topOffScreenMargin); - self = [super initWithFrame:realFrame collectionViewLayout:flowLayout]; - if (self){ - self.contentInset=UIEdgeInsetsMake(20.0f, 0.0f, 0.0f, 0.0f); - self.highLightAnimationDuration=0.3f; - self.dismisalAnimationDuration=0.3f; - } - return self; -} --(void)setHidden:(BOOL)hidden{ + +- (void)setHidden:(BOOL)hidden +{ [super setHidden:hidden]; + if (hidden){ - if (_maskImageView){ + if (_maskImageView) { [_maskImageView removeFromSuperview]; - _maskImageView=nil; + _maskImageView = nil; } } - else{ - [self setMaskShow:_maskShow]; + else { + [self setMaskShow:self.maskShow]; } } -#pragma mark - Mask --(void)setMaskShow:(BOOL)maskShow{ - _maskShow=maskShow; + +- (void)setMaskShow:(BOOL)maskShow +{ + _maskShow = maskShow; + if (maskShow){ if (!_maskImageView){ - _maskImageView=[[UIImageView alloc]initWithImage:[self makeGradientImage]]; + _maskImageView = [[UIImageView alloc]initWithImage:[self makeGradientImage]]; [self.superview addSubview:_maskImageView]; } - _maskImageView.hidden=NO; - } - else{ - _maskImageView.hidden=YES; + _maskImageView.hidden = NO; + + } else { + _maskImageView.hidden = YES; } } --(BOOL)maskShow{ - return _maskShow; -} --(UIImage*)makeGradientImage{ + +- (UIImage *)makeGradientImage +{ UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 1.0f); CGContextRef context=UIGraphicsGetCurrentContext(); CGContextSaveGState(context); @@ -93,9 +107,11 @@ -(UIImage*)makeGradientImage{ UIGraphicsEndImageContext(); return image; } + #pragma mark - Actions -///Display status --(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void (^)(BOOL))completion{ + +- (void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void (^)(BOOL))completion +{ NSLog(@"row:%ld",(long)indexPath.row); if (indexPath.row >= [self numberOfItemsInSection:indexPath.section]){ @@ -105,17 +121,18 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void if (_isHighLight){ return; } - ///如果在可视范围内就不要滚动了 - BOOL no_scroll=NO; + + BOOL noScroll = NO; NSArray* visibleIndexPaths=[self indexPathsForVisibleItems]; for (NSIndexPath* indexPath in visibleIndexPaths) { if (indexPath.row==indexPath.row){ - no_scroll=YES; + noScroll = YES; } } - if (!no_scroll){ + if (!noScroll){ [self scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; } + double delayInSeconds = 0.3f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ @@ -127,32 +144,37 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath completion:(void [self.visibleCells enumerateObjectsUsingBlock:^(WKPagesCollectionViewCell* cell, NSUInteger idx, BOOL *stop) { NSIndexPath* visibleIndexPath=[self indexPathForCell:cell]; if (visibleIndexPath.row==indexPath.row){ - cell.showingState=WKPagesCollectionViewCellShowingStateHightlight; - } - else if (visibleIndexPath.rowindexPath.row){ + cell.state=WKPagesCollectionViewCellStateHightlight; + + } else if (visibleIndexPath.rowindexPath.row) { NSLog(@"indexPath:%ld,visibleIndexPath:%ld",(long)indexPath.row,(long)visibleIndexPath.row); - cell.showingState=WKPagesCollectionViewCellShowingStateBackToBottom; - } - else{ - cell.showingState=WKPagesCollectionViewCellShowingStateNormal; + cell.state=WKPagesCollectionViewCellStateBackToBottom; + + } else { + cell.state = WKPagesCollectionViewCellStateNormal; } _maskImageView.alpha = 0.0; }]; + } completion:^(BOOL finished) { _isHighLight = YES; self.maskShow = NO; - completion(finished); + if (completion) { + completion(finished); + } + if ([self.delegate respondsToSelector:@selector(collectionView:didShownToHightlightAtIndexPath:)]){ [(id)self.delegate collectionView:self didShownToHightlightAtIndexPath:indexPath]; } }]; }); - } --(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath{ + +- (void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath +{ if (indexPath.row >= [self numberOfItemsInSection:indexPath.section]) { return; } @@ -164,67 +186,76 @@ -(void)showCellToHighLightAtIndexPath:(NSIndexPath *)indexPath{ double delayInSeconds = 0.01f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - self.maskShow=NO; - self.scrollEnabled=NO; + self.maskShow = NO; + self.scrollEnabled = NO; [self.visibleCells enumerateObjectsUsingBlock:^(WKPagesCollectionViewCell* cell, NSUInteger idx, BOOL *stop) { - NSIndexPath* visibleIndexPath=[self indexPathForCell:cell]; - if (visibleIndexPath.row==indexPath.row){ - cell.showingState=WKPagesCollectionViewCellShowingStateHightlight; + NSIndexPath* visibleIndexPath = [self indexPathForCell:cell]; + if (visibleIndexPath.row == indexPath.row){ + cell.state = WKPagesCollectionViewCellStateHightlight; } else if (visibleIndexPath.rowindexPath.row){ - cell.showingState=WKPagesCollectionViewCellShowingStateBackToBottom; + cell.state = WKPagesCollectionViewCellStateBackToBottom; } else{ - cell.showingState=WKPagesCollectionViewCellShowingStateNormal; + cell.state = WKPagesCollectionViewCellStateNormal; } }]; _isHighLight=YES; }); } -///Back to the original state --(void)dismissFromHightLightWithCompletion:(void (^)(BOOL))completion{ - self.maskShow=YES; + +- (void)dismissFromHightLightWithCompletion:(void (^)(BOOL))completion +{ + self.maskShow = YES; _maskImageView.alpha = 0.0; + if (!_isHighLight) return; - [UIView animateWithDuration:self.dismisalAnimationDuration delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ - [self.visibleCells enumerateObjectsUsingBlock:^(WKPagesCollectionViewCell* cell, NSUInteger idx, BOOL *stop) { - cell.showingState=WKPagesCollectionViewCellShowingStateNormal; + + [UIView animateWithDuration:self.dismisalAnimationDuration delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + [self.visibleCells enumerateObjectsUsingBlock:^(WKPagesCollectionViewCell *cell, NSUInteger idx, BOOL *stop) { + cell.state = WKPagesCollectionViewCellStateNormal; _maskImageView.alpha = 1.0; }]; + } completion:^(BOOL finished) { - self.scrollEnabled=YES; - _isHighLight=NO; + self.scrollEnabled = YES; + _isHighLight = NO; + if (completion != nil) { completion(finished); } + if ([self.delegate respondsToSelector:@selector(didDismissFromHightlightOnCollectionView:)]){ [(id)self.delegate didDismissFromHightlightOnCollectionView:self]; } }]; } -///Append a page --(void)appendItem{ + +- (void)appendItem +{ if (self.isAddingNewPage) { return; } + self.isAddingNewPage = YES; if (self.isHighLight){ [self dismissFromHightLightWithCompletion:^(BOOL finished) { - [self _addNewPage]; + [self addNewPage]; }]; } else{ - [self _addNewPage]; + [self addNewPage]; } } -///Adding a --(void)_addNewPage{ - NSInteger total=[self numberOfItemsInSection:0]; + +- (void)addNewPage +{ + NSInteger total = [self numberOfItemsInSection:0]; if (total > 0) { [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; } @@ -234,8 +265,8 @@ -(void)_addNewPage{ dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ ///Add Data [(id)self.dataSource willAppendItemInCollectionView:self]; - NSInteger lastRow=total; - NSIndexPath* insertIndexPath=[NSIndexPath indexPathForItem:lastRow inSection:0]; + NSInteger lastRow = total; + NSIndexPath *insertIndexPath=[NSIndexPath indexPathForItem:lastRow inSection:0]; [self performBatchUpdates:^{ [self insertItemsAtIndexPaths:@[insertIndexPath]]; } completion:^(BOOL finished) { @@ -250,22 +281,22 @@ -(void)_addNewPage{ }]; }); } -#pragma mark - UIView and UICollectionView --(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ - UIView* view=[super hitTest:point withEvent:event]; + +#pragma mark - + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ + UIView *view = [super hitTest:point withEvent:event]; if (!view){ return nil; } - if (view==self){ - for (WKPagesCollectionViewCell* cell in self.visibleCells) { - if (cell.showingState==WKPagesCollectionViewCellShowingStateHightlight){ + if (view == self){ + for (WKPagesCollectionViewCell *cell in self.visibleCells) { + if (cell.state == WKPagesCollectionViewCellStateHightlight){ return cell.cellContentView;///Events should only be passed to this layer } } } return view; -// UIView* view=[super hitTest:point withEvent:event]; -// NSLog(@"%@,%d",NSStringFromClass([view class]),view.tag); -// return view; } + @end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h index 2cbe4f5..18d841b 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.h @@ -8,27 +8,20 @@ #import #import "WKCloseButton.h" -typedef enum WKPagesCollectionViewCellShowingState:NSUInteger{ - WKPagesCollectionViewCellShowingStateNormal=0, - WKPagesCollectionViewCellShowingStateHightlight=1, - WKPagesCollectionViewCellShowingStateBackToTop=2, - WKPagesCollectionViewCellShowingStateBackToBottom=3, -} WKPagesCollectionViewCellShowingState; -@interface WKPagesCollectionViewCell : UICollectionViewCell{ - WKPagesCollectionViewCellShowingState _showingState; - UITapGestureRecognizer* _tapGesture; - UIScrollView* _scrollView; - WKCloseButton* _closeButton; -// UIImageView* _maskImageView; -} -///Position the normal state -@property (nonatomic,assign) CATransform3D normalTransform; -///Position the normal state -@property (nonatomic,assign) CGRect normalFrame; -///Display status -@property (nonatomic,assign) WKPagesCollectionViewCellShowingState showingState; -///Quote collectionView -@property (nonatomic,weak) UICollectionView* collectionView; -@property (nonatomic,strong) UIView* cellContentView; --(UIImage*)makeGradientImage; + +typedef NS_ENUM(NSUInteger, WKPagesCollectionViewCellState) { + WKPagesCollectionViewCellStateNormal, + WKPagesCollectionViewCellStateHightlight, + WKPagesCollectionViewCellStateBackToTop, + WKPagesCollectionViewCellStateBackToBottom, +}; + +@interface WKPagesCollectionViewCell : UICollectionViewCell + +@property (nonatomic, assign) CATransform3D normalTransform; +@property (nonatomic, assign) CGRect normalFrame; +@property (nonatomic, assign) WKPagesCollectionViewCellState state; +@property (nonatomic, assign) UICollectionView *collectionView; // cell should not need a reference to the collection view (its parent) +@property (nonatomic, strong) UIView *cellContentView; + @end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m index d1558d0..f1f5912 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewCell.m @@ -9,73 +9,68 @@ #import "WKPagesCollectionViewCell.h" #import "WKPagesCollectionView.h" #import "WKCloseButton.h" + +@interface WKPagesCollectionViewCell () + +@property (nonatomic, strong) UITapGestureRecognizer *tapGestureRecognizer; +@property (nonatomic, strong) UIScrollView *scrollView; +@property (nonatomic, strong) WKCloseButton *closeButton; + +@end + @implementation WKPagesCollectionViewCell -@dynamic showingState; + - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { - // Initialization code - self.clipsToBounds=NO; - self.backgroundColor=[UIColor clearColor]; - self.contentView.tag=100; + self.clipsToBounds = NO; + self.backgroundColor = [UIColor clearColor]; + self.contentView.tag = 100; + CGRect rect=CGRectMake(0.0f, 0.0f, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height); - if (!_scrollView){ - _scrollView=[[UIScrollView alloc]initWithFrame:rect]; - _scrollView.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; - _scrollView.clipsToBounds=NO; - _scrollView.backgroundColor=[UIColor clearColor]; - _scrollView.showsVerticalScrollIndicator=NO; - _scrollView.showsHorizontalScrollIndicator=YES; - _scrollView.contentSize=CGSizeMake(_scrollView.frame.size.width+1, _scrollView.frame.size.height); - _scrollView.delegate=self; - [self.contentView addSubview:_scrollView]; - _scrollView.tag=101; - } - if (!_cellContentView){ - _cellContentView=[[UIView alloc]initWithFrame:rect]; - _cellContentView.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; - [_scrollView addSubview:_cellContentView]; - _cellContentView.tag=102; - } - if (!_tapGesture){ - _tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(onTapGesture:)]; - [_scrollView addGestureRecognizer:_tapGesture]; - } + self.scrollView = [[UIScrollView alloc] initWithFrame:rect]; + self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + self.scrollView.clipsToBounds = NO; + self.scrollView.backgroundColor = [UIColor clearColor]; + self.scrollView.showsVerticalScrollIndicator = NO; + self.scrollView.showsHorizontalScrollIndicator = YES; + self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width + 1.0, self.scrollView.frame.size.height); + self.scrollView.delegate=self; + [self.contentView addSubview:_scrollView]; + self.scrollView.tag = 101; - if (!_closeButton) { - _closeButton = [[WKCloseButton alloc] initWithFrame:CGRectMake(0, 0, CloseButtonWidth, CloseButtonHeight)]; - [_closeButton addTarget:self action:@selector(closeButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - [_scrollView addSubview:_closeButton]; - } + self.cellContentView = [[UIView alloc] initWithFrame:rect]; + self.cellContentView.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + [self.scrollView addSubview:self.cellContentView]; + self.cellContentView.tag=102; + + self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognized:)]; + [self.scrollView addGestureRecognizer:self.tapGestureRecognizer]; + self.closeButton = [[WKCloseButton alloc] initWithFrame:CGRectMake(0.0, 0.0, CloseButtonWidth, CloseButtonHeight)]; + [self.closeButton addTarget:self action:@selector(closeButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self.scrollView addSubview:self.closeButton]; } + return self; } -/* -// Only override drawRect: if you perform custom drawing. -// An empty implementation adversely affects performance during animation. -- (void)drawRect:(CGRect)rect +- (void)prepareForReuse { - // Drawing code -} -*/ --(void)prepareForReuse{ [super prepareForReuse]; - for (UIView* view in _cellContentView.subviews) { + for (UIView *view in self.cellContentView.subviews) { [view removeFromSuperview]; } - } --(IBAction)onTapGesture:(UITapGestureRecognizer*)tapGesture{ - NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; -// NSLog(@"row:%d",indexPath.row); -// [self.collectionView.delegate collectionView:self.collectionView didSelectItemAtIndexPath:indexPath]; - [(WKPagesCollectionView*)self.collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { + +- (void)tapGestureRecognized:(UITapGestureRecognizer*)tapGesture +{ + NSIndexPath *indexPath = [self.collectionView indexPathForCell:self]; + [(WKPagesCollectionView *)self.collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { NSLog(@"highlight completed"); }]; } @@ -85,66 +80,64 @@ -(void) closeButtonPressed:(id)sender [self removeCurrentCell]; } -#pragma mark - Properties --(void)setShowingState:(WKPagesCollectionViewCellShowingState)showingState{ - if (_showingState==showingState) + +#pragma mark - + +- (void)setState:(WKPagesCollectionViewCellState)state +{ + if (_state == state) return; - _showingState=showingState; - WKPagesCollectionViewFlowLayout* collectionLayout=(WKPagesCollectionViewFlowLayout*)self.collectionView.collectionViewLayout; + + _state = state; + + WKPagesCollectionViewFlowLayout *collectionLayout = (WKPagesCollectionViewFlowLayout*)self.collectionView.collectionViewLayout; CGFloat pageHeight=collectionLayout.pageHeight; CGFloat topMargin=[(WKPagesCollectionView*)self.collectionView topOffScreenMargin]; - switch (showingState) { - case WKPagesCollectionViewCellShowingStateHightlight:{ - self.normalTransform=self.layer.transform;///The original location of the first record - _scrollView.scrollEnabled=NO; + + switch (state) { + case WKPagesCollectionViewCellStateHightlight: { + self.normalTransform = self.layer.transform; + _scrollView.scrollEnabled = NO; _closeButton.hidden = YES; - NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; - CGFloat moveY=self.collectionView.contentOffset.y-(WKPagesCollectionViewPageSpacing)*indexPath.row +topMargin; - CATransform3D moveTransform=CATransform3DMakeTranslation(0.0f, moveY, 0.0f); - self.layer.transform=moveTransform; + NSIndexPath* indexPath = [self.collectionView indexPathForCell:self]; + CGFloat moveY = self.collectionView.contentOffset.y - (WKPagesCollectionViewPageSpacing)*indexPath.row + topMargin; + CATransform3D moveTransform = CATransform3DMakeTranslation(0.0, moveY, 0.0); + self.layer.transform = moveTransform; } break; - case WKPagesCollectionViewCellShowingStateBackToTop:{ - self.normalTransform=self.layer.transform;///The original location of the first record - _scrollView.scrollEnabled=NO; + case WKPagesCollectionViewCellStateBackToTop: { + self.normalTransform = self.layer.transform; + _scrollView.scrollEnabled = NO; _closeButton.hidden = NO; - CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(HighLightRotateAngle); - CATransform3D moveTransform=CATransform3DMakeTranslation(0, -1*pageHeight-topMargin, 0); + CATransform3D rotateTransform = WKFlipCATransform3DPerspectSimpleWithRotate(HighLightRotateAngle); + CATransform3D moveTransform = CATransform3DMakeTranslation(0, -1*pageHeight - topMargin, 0.0); self.layer.transform=CATransform3DConcat(rotateTransform, moveTransform); } break; - case WKPagesCollectionViewCellShowingStateBackToBottom:{ - self.normalTransform=self.layer.transform;///The original location of the first record - _scrollView.scrollEnabled=NO; + case WKPagesCollectionViewCellStateBackToBottom: { + self.normalTransform = self.layer.transform; + _scrollView.scrollEnabled = NO; _closeButton.hidden = NO; - CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(HighLightRotateAngle); - CATransform3D moveTransform=CATransform3DMakeTranslation(0, pageHeight+topMargin, 0); - self.layer.transform=CATransform3DConcat(rotateTransform, moveTransform); + CATransform3D rotateTransform = WKFlipCATransform3DPerspectSimpleWithRotate(HighLightRotateAngle); + CATransform3D moveTransform = CATransform3DMakeTranslation(0.0, pageHeight + topMargin, 0.0); + self.layer.transform = CATransform3DConcat(rotateTransform, moveTransform); } break; - case WKPagesCollectionViewCellShowingStateNormal:{ - self.layer.transform=self.normalTransform; - _scrollView.scrollEnabled=YES; + case WKPagesCollectionViewCellStateNormal: { + self.layer.transform = self.normalTransform; + _scrollView.scrollEnabled = YES; _closeButton.hidden = NO; } break; default: break; } - - - -} --(WKPagesCollectionViewCellShowingState)showingState{ - return _showingState; } - --(void) removeCurrentCell +- (void)removeCurrentCell { - NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; + NSIndexPath* indexPath = [self.collectionView indexPathForCell:self]; NSLog(@"delete cell at %ld",(long)indexPath.row); - //self.alpha=0.0f; //Delete data id pagesDataSource=(id)self.collectionView.dataSource; [pagesDataSource collectionView:(WKPagesCollectionView*)self.collectionView willRemoveCellAtIndexPath:indexPath]; @@ -154,46 +147,28 @@ -(void) removeCurrentCell } completion:^(BOOL finished) { }]; - } #pragma mark - UIScrollViewDelegate --(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView +{ } --(void)scrollViewDidScroll:(UIScrollView *)scrollView{ + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView +{ } --(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ - if (self.showingState==WKPagesCollectionViewCellShowingStateNormal){ + +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate +{ + if (self.state == WKPagesCollectionViewCellStateNormal) { CGFloat slideDistance = scrollView.frame.size.width / 6; - if (scrollView.contentOffset.x >= slideDistance){ + if (scrollView.contentOffset.x >= slideDistance) { [self removeCurrentCell]; } } } -#pragma mark - Image --(UIImage*)makeGradientImage{ - UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 1.0f); - CGContextRef context=UIGraphicsGetCurrentContext(); - CGContextSaveGState(context); - - CGGradientRef myGradient; - CGColorSpaceRef myColorspace; - size_t num_locations = 2; - CGFloat locations[2] = { 0.0, 1.0 }; - CGFloat components[8] = { 0.0,0.0,0.0, 0.0, // Start color - 0.0,0.0,0.0,1.0}; // End color - myColorspace = CGColorSpaceCreateDeviceRGB(); - myGradient = CGGradientCreateWithColorComponents (myColorspace, components, - locations, num_locations); - CGContextDrawLinearGradient(context, myGradient, CGPointMake(self.bounds.size.width/2, 100.0f), CGPointMake(self.bounds.size.width/2, self.bounds.size.height-100.0f), kCGGradientDrawsAfterEndLocation); - - UIImage* image=UIGraphicsGetImageFromCurrentImageContext(); - CGContextRestoreGState(context); - CGColorSpaceRelease(myColorspace); - CGGradientRelease(myGradient); - UIGraphicsEndImageContext(); - return image; -} + @end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.h b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.h index 42518bc..b3d1e1b 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.h +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.h @@ -9,9 +9,8 @@ #import #import "WK.h" -@interface WKPagesCollectionViewFlowLayout : UICollectionViewFlowLayout{ - -} +@interface WKPagesCollectionViewFlowLayout : UICollectionViewFlowLayout + @property (nonatomic,readonly) CGFloat pageHeight; @end diff --git a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m index 36f9179..be8209b 100644 --- a/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m +++ b/WKPagesScrollView/WKPagesCollectionView/WKPagesCollectionViewFlowLayout.m @@ -6,40 +6,28 @@ // Copyright (c) 2013年 秦 道平. All rights reserved. // - #import "WKPagesCollectionViewFlowLayout.h" #import "WKPagesCollectionView.h" + #define RotateDegree -60.0f + @interface WKPagesCollectionViewFlowLayout() -@property (nonatomic,strong) NSMutableArray* deleteIndexPaths; -@property (nonatomic,strong) NSMutableArray* insertIndexPaths; + +@property (nonatomic,strong) NSMutableArray *deleteIndexPaths; +@property (nonatomic,strong) NSMutableArray *insertIndexPaths; + @end -@implementation WKPagesCollectionViewFlowLayout{ - -} --(id)init{ - self=[super init]; - if (self){ - - } - return self; -} --(void)prepareLayout + +@implementation WKPagesCollectionViewFlowLayout + +#pragma mark - UICollectionViewLayout (UISubclassingHooks) + +- (CGSize)collectionViewContentSize { - [super prepareLayout]; - self.itemSize=[UIScreen mainScreen].bounds.size; - self.minimumLineSpacing=-1*(self.itemSize.height-WKPagesCollectionViewPageSpacing); - self.scrollDirection=UICollectionViewScrollDirectionVertical; -} --(CGFloat)pageHeight{ - return self.itemSize.height; -} --(CGSize)collectionViewContentSize{ + NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:0]; + CGFloat contentHeight = numberOfItems*self.pageHeight + self.self.minimumLineSpacing*(numberOfItems - 1); + contentHeight = fmaxf(contentHeight, self.collectionView.frame.size.height); - NSInteger numberOfItems=[self.collectionView numberOfItemsInSection:0]; -// CGFloat topMargin=[(WKPagesCollectionView*)self.collectionView topOffScreenMargin]; - CGFloat contentHeight=numberOfItems*self.pageHeight+self.self.minimumLineSpacing*(numberOfItems-1); - contentHeight=fmaxf(contentHeight, self.collectionView.frame.size.height); return CGSizeMake(self.collectionView.frame.size.width,contentHeight); } @@ -47,80 +35,107 @@ - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)oldBounds { return YES; } --(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path + +#pragma mark - UICollectionViewLayout (UIUpdateSupportHooks) + +- (void)prepareLayout +{ + [super prepareLayout]; + + self.minimumLineSpacing = -1*(self.itemSize.height-WKPagesCollectionViewPageSpacing); + self.scrollDirection = UICollectionViewScrollDirectionVertical; +} + +- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path { -// NSLog(@"layoutAttributesForItemAtIndexPath:%d",path.row); - UICollectionViewLayoutAttributes* attributes=[super layoutAttributesForItemAtIndexPath:path]; + UICollectionViewLayoutAttributes* attributes = [super layoutAttributesForItemAtIndexPath:path]; [self makeRotateTransformForAttributes:attributes]; + return attributes; } --(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect + +-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { -// NSLog(@"layoutAttributesForElementsInRect:%@",NSStringFromCGRect(rect)); - NSArray* array = [super layoutAttributesForElementsInRect:rect]; - for (UICollectionViewLayoutAttributes* attributes in array) { + NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:rect]; + for (UICollectionViewLayoutAttributes *attributes in layoutAttributes) { [self makeRotateTransformForAttributes:attributes]; } - return array; + + return layoutAttributes; } -#pragma mark Collection Update --(void)prepareForCollectionViewUpdates:(NSArray *)updateItems{ -// NSLog(@"prepareForCollectionViewUpdates"); + +- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems +{ [super prepareForCollectionViewUpdates:updateItems]; - self.deleteIndexPaths=[NSMutableArray array]; - self.insertIndexPaths=[NSMutableArray array]; - for (UICollectionViewUpdateItem* updateItem in updateItems) { - if (updateItem.updateAction==UICollectionUpdateActionDelete){ + self.deleteIndexPaths = [NSMutableArray array]; + self.insertIndexPaths = [NSMutableArray array]; + for (UICollectionViewUpdateItem *updateItem in updateItems) { + if (updateItem.updateAction == UICollectionUpdateActionDelete){ [self.deleteIndexPaths addObject:updateItem.indexPathBeforeUpdate]; } - if (updateItem.updateAction==UICollectionUpdateActionInsert){ + if (updateItem.updateAction == UICollectionUpdateActionInsert){ [self.insertIndexPaths addObject:updateItem.indexPathAfterUpdate]; } } } --(void)finalizeCollectionViewUpdates{ -// NSLog(@"finalizeCollectionViewUpdates"); + +- (void)finalizeCollectionViewUpdates +{ [super finalizeCollectionViewUpdates]; - self.deleteIndexPaths=nil; - self.insertIndexPaths=nil; + self.deleteIndexPaths = nil; + self.insertIndexPaths = nil; } --(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ - UICollectionViewLayoutAttributes* attributes=[super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; -// NSLog(@"initialLayoutAttributesForAppearingItemAtIndexPath:%d",itemIndexPath.row); + +- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath +{ + UICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; + if ([self.insertIndexPaths containsObject:itemIndexPath]){ if (!attributes) - attributes=[self layoutAttributesForItemAtIndexPath:itemIndexPath]; + attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath]; CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(-90.0f); attributes.transform3D=rotateTransform; } + return attributes; } --(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ - NSLog(@"finalLayoutAttributesForDisappearingItemAtIndexPath:%ld",(long)itemIndexPath.row); - UICollectionViewLayoutAttributes* attributes=[super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath]; + +- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath +{ + UICollectionViewLayoutAttributes *attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath]; + if ([self.deleteIndexPaths containsObject:itemIndexPath]){ if (!attributes){ - attributes=[self layoutAttributesForItemAtIndexPath:itemIndexPath]; + attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath]; } - CATransform3D moveTransform=CATransform3DMakeTranslation(-320.0f, 0.0f, 0.0f); - attributes.transform3D=CATransform3DConcat(attributes.transform3D, moveTransform); - } - return attributes; + CATransform3D moveTransform = CATransform3DMakeTranslation(-self.itemSize.width, 0.0, 0.0); + attributes.transform3D = CATransform3DConcat(attributes.transform3D, moveTransform); + } + return attributes; +} + +#pragma mark - + +- (CGFloat)pageHeight +{ + return self.itemSize.height; } -///As attribute set up a new perspective --(void)makeRotateTransformForAttributes:(UICollectionViewLayoutAttributes*)attributes{ - attributes.zIndex=attributes.indexPath.row;///To set the zIndex,Otherwise, there will be NO blocking order - CGFloat distance=attributes.frame.origin.y-self.collectionView.contentOffset.y; + +#pragma mark - + +// As attribute set up a new perspective +- (void)makeRotateTransformForAttributes:(UICollectionViewLayoutAttributes *)attributes +{ + attributes.zIndex = attributes.indexPath.row; //To set the zIndex,Otherwise, there will be NO blocking order + CGFloat distance = attributes.frame.origin.y - self.collectionView.contentOffset.y; CGFloat normalizedDistance = distance / self.collectionView.frame.size.height; - normalizedDistance=fmaxf(normalizedDistance, 0.0f); - CGFloat rotate=RotateDegree+20.0f*normalizedDistance; - //CGFloat rotate=RotateDegree; -// NSLog(@"makeRotateTransformForAttributes:row:%d,normalizedDistance:%f,rotate:%f", -// attributes.indexPath.row,normalizedDistance,rotate); - ///Angle and angle will cross a small cell, even if you set zIndex is useless here to set the angle of the bottom of the cell is growing - CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(rotate); - attributes.transform3D=rotateTransform; - + normalizedDistance = fmaxf(normalizedDistance, 0.0); + CGFloat rotate = RotateDegree+ 20.0*normalizedDistance; + + // Angle and angle will cross a small cell, even if you set zIndex is useless here to set the angle of the bottom of the cell is growing + CATransform3D rotateTransform = WKFlipCATransform3DPerspectSimpleWithRotate(rotate); + attributes.transform3D = rotateTransform; } + @end \ No newline at end of file From 19f811fac16ab3208acd043bda24be29efc4d62e Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Mon, 20 Apr 2015 14:52:48 +0930 Subject: [PATCH 29/31] updated README --- README.md | 258 +++--------------------------------------------------- 1 file changed, 13 insertions(+), 245 deletions(-) diff --git a/README.md b/README.md index 0b5041e..b37f972 100644 --- a/README.md +++ b/README.md @@ -1,254 +1,22 @@ # WKPagesCollectionView -I wanted to implement an UI effect like iOS7 Safari tabs pages. +An implementation of the tab switcher as seen in Safari for iOS (> 7.0) using UICollectionViews. -* Page-flipping effect; -* Click on a page then can put it into a normal display state; -* Scratch to left can delete the cell; -* You can add a new cell at the bottom; +Features: +* Page flipping tranform +* Tap on a page to select it +* Swipe the cell to the left to delete it +* New cells can be added at the bottom -[See video](http://v.youku.com/v_show/id_XNzAzNDg4OTQ4.html) - -![Effect video](http://farm4.staticflickr.com/3829/11171831814_9c5972bbe6_z.jpg)] +[Video](http://v.youku.com/v_show/id_XNzAzNDg4OTQ4.html) ## Usage -* Add `WKPagesCollectionView` folder and the following files inside it to project :`WK.h`, `WKPagesCollectionView.h`, `WKPagesCollectionView.m`, `WKPagesCollectionViewCell.h`, `WKPagesCollectionViewCell.m`, `WKPagesCollectionViewFlowLayout.h`, `WKPagesCollectionViewFlowLayout.m`; -* Import `WKPagesCollectionView`; -* Prepare data - - _array=[[NSMutableArray alloc]init]; - for (int a=0; a<=30; a++) { - [_array addObject:[NSString stringWithFormat:@"button %d",a]]; - } - -* Create `collectionView` - - _collectionView=[[[WKPagesCollectionView alloc]initWithPagesFlowLayoutAndFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height)] autorelease]; - _collectionView.dataSource=self; - _collectionView.delegate=self; - [_collectionView registerClass:[WKPagesCollectionViewCell class] forCellWithReuseIdentifier:@"cell"]; - [self.view addSubview:_collectionView]; - _collectionView.maskShow=YES; - - -* Implement `WKPagesCollectionViewDataSource`(inherited from `UICollectionViewDataSource`) and `WKPagesCollectionViewDelegate`(inherited from `UICollectionViewDelegate`), in addition of these, also need to provide methods of append item and remove item : -`-(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView` -and `-(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath` - - #pragma mark - UICollectionViewDataSource and UICollectionViewDelegate - -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ - return _array.count; - } - -(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ - // NSLog(@"cellForItemAtIndexPath:%d",indexPath.row); - static NSString* identity=@"cell"; - WKPagesCollectionViewCell* cell=(WKPagesCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:identity forIndexPath:indexPath]; - cell.collectionView=collectionView; - UIImageView* imageView=[[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image-0"]] autorelease]; - imageView.frame=self.view.bounds; - [cell.cellContentView addSubview:imageView]; - UIButton* button=[UIButton buttonWithType:UIButtonTypeCustom]; - button.frame=CGRectMake(0, (indexPath.row+1)*10+100, 320, 50.0f); - button.backgroundColor=[UIColor whiteColor]; - [button setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal]; - [button setTitle:_array[indexPath.row] forState:UIControlStateNormal]; - [button addTarget:self action:@selector(onButtonTitle:) forControlEvents:UIControlEventTouchUpInside]; - [cell.cellContentView addSubview:button]; - return cell; - } - #pragma mark WKPagesCollectionViewDataSource - ///append item - -(void)willAppendItemInCollectionView:(WKPagesCollectionView *)collectionView{ - [_array addObject:@"new button"]; - } - ///remove item - -(void)collectionView:(WKPagesCollectionView *)collectionView willRemoveCellAtNSIndexPath:(NSIndexPath *)indexPath{ - [_array removeObjectAtIndex:indexPath.row]; - } - -* Append a page by press button - - -(IBAction)onButtonAdd:(id)sender{ - [_collectionView appendItem]; - } - -* Expand to display a specific page. this will be triggered when clicking the page, the code be invoked as follows; - - [_collectionView showCellToHighLightAtIndexPath:indexPath completion:^(BOOL finished) { - NSLog(@"highlight completed"); - }]; - -* Stop expand the page and back to normal mode(tab mode) - - -(IBAction)onButtonTitle:(id)sender{ - NSLog(@"button"); - [_collectionView dismissFromHightLightWithCompletion:^(BOOL finished) { - NSLog(@"dismiss completed"); - }]; - } - -##TODO -* `bug` ~~When roll the tab several times, the top page will be first invisible and then suddenly appeared, did not found the reason~~ This problem has been solved by @ Nikolay Abelyashev. The root cause is due to the too small height of WKPagesCollectionView, and the `UICollectionView` will not display cells outside the device screen. In `WKPagesCollectionView` the three cells outside the screen will not be displayed. The solution is to modify the frame of `WKPagesCollectionView` , so that the height will higher than the device window (here add `topOfScreen: 120.0f`), then the `frame.origin.y` also adds up that distance, so in fact the `WKPagesCollectionView` is larger than the window. - - -##Way to implement -###Implement scroll - -I used `UICollectionView` to implement the scroll, this is essentially a vertical list, and the main part is a `CollectionViewLayout`. (I define it as `WKPagesCollectionViewFlowLayout`) each cell have the same size of device screen, that is actually a pile of screen size cells stagger folded together, and the space between them is `self.minimumLineSpacing = -1 * (self.itemSize.height-160.0f);`. - -![When not flip cell](http://farm6.staticflickr.com/5521/11171968153_7a7aeb5893_z.jpg) - -In order to achieve the flipping effect, in the function -`-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect` of WKPagesCollectionViewFlowLayout, I modify the transform3D. - -Looks simple, but if all the pages have fixed angle, then its ok, but I imagine that like safari when scroll the page, there have a little parallax effect, so I set up a different flip angles for each page. In fact, is in `layoutAttributesForElementsInRect` function, base on the position of each cell calculate the angle so that when they scroll there have a little different perspective. the following is the code to set the angle: - - -(void)makeRotateTransformForAttributes:(UICollectionViewLayoutAttributes*)attributes{ - attributes.zIndex=attributes.indexPath.row;///Set the zIndex, to implement sequential occlusion - CGFloat distance=attributes.frame.origin.y-self.collectionView.contentOffset.y; - CGFloat normalizedDistance = distance / self.collectionView.frame.size.height; - normalizedDistance=fmaxf(normalizedDistance, 0.0f); - CGFloat rotate=RotateDegree+20.0f*normalizedDistance; - //CGFloat rotate=RotateDegree; - NSLog(@"makeRotateTransformForAttributes:row:%d,normalizedDistance:%f,rotate:%f", - attributes.indexPath.row,normalizedDistance,rotate); - ///Bigger angle cell will have cross with smaller angle cell, even set the zIndex. Here set the lower cell have the bigger angle. - CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(rotate); - attributes.transform3D=rotateTransform; - - } - -``` --(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path -{ - NSLog(@"layoutAttributesForItemAtIndexPath:%d",path.row); - UICollectionViewLayoutAttributes* attributes=[super layoutAttributesForItemAtIndexPath:path]; - [self makeRotateTransformForAttributes:attributes]; - return attributes; -} --(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect -{ - NSLog(@"layoutAttributesForElementsInRect:%@",NSStringFromCGRect(rect)); - NSArray* array = [super layoutAttributesForElementsInRect:rect]; - for (UICollectionViewLayoutAttributes* attributes in array) { - [self makeRotateTransformForAttributes:attributes]; - } - return array; -} -``` - -Now have the desired effect, although not so perfect like Safari's. - -##Implement delete item - -Later I want to implement the delete item effect which like Safari's: hold on one of the cell and slide left then can remove it. I add a scrollView in every cell, in function of `scrollViewDidEndDragging`, when slide to left reach a certain distance then trigger the delete function. The animation effect of removing was implemented in UICollectionView's `performBatchUpdates` function. - -![The UI effect of deletion.](http://farm4.staticflickr.com/3831/11171811316_c681d80cc2_z.jpg) - - -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ - if (self.showingState==WKPagesCollectionViewCellShowingStateNormal){ - if (scrollView.contentOffset.x>=90.0f){ - NSIndexPath* indexPath=[self.collectionView indexPathForCell:self]; - NSLog(@"delete cell at %d",indexPath.row); - //self.alpha=0.0f; - ///Remove item - id pagesDataSource=(id)self.collectionView.dataSource; - [pagesDataSource collectionView:(WKPagesCollectionView*)self.collectionView willRemoveCellAtNSIndexPath:indexPath]; - ///Animation - [self.collectionView performBatchUpdates:^{ - [self.collectionView deleteItemsAtIndexPaths:@[indexPath,]]; - } completion:^(BOOL finished) { - - }]; - } - } - } - -To make the animation effect of add and delete item look better, we have to modify -`(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` - -and - -`-(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath` - -I add `insertIndexPaths` and `deleteIndexPaths` functions in `WKPagesCollectionViewFlowLayout`, to record the position when add and remove item. The two callback functions will be called not just for being added or deleted `NSIndexPath`, and will be called at another place. - - -(UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ - UICollectionViewLayoutAttributes* attributes=[super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; - NSLog(@"initialLayoutAttributesForAppearingItemAtIndexPath:%d",itemIndexPath.row); - if ([self.insertIndexPaths containsObject:itemIndexPath]){ - if (!attributes) - attributes=[self layoutAttributesForItemAtIndexPath:itemIndexPath]; - CATransform3D rotateTransform=WKFlipCATransform3DPerspectSimpleWithRotate(-90.0f); - attributes.transform3D=rotateTransform; - } - return attributes; - } - -(UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath{ - NSLog(@"finalLayoutAttributesForDisappearingItemAtIndexPath:%d",itemIndexPath.row); - UICollectionViewLayoutAttributes* attributes=[super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath]; - if ([self.deleteIndexPaths containsObject:itemIndexPath]){ - if (!attributes){ - attributes=[self layoutAttributesForItemAtIndexPath:itemIndexPath]; - } - CATransform3D moveTransform=CATransform3DMakeTranslation(-320.0f, 0.0f, 0.0f); - attributes.transform3D=CATransform3DConcat(attributes.transform3D, moveTransform); - } - return attributes; - - } - - -Beginning will be some unexpected animation, scrolling to the end, and then press command + t to open slow animations in simulator can see very clearly. When slide left to remove the last two cell, at the beginning of remove effect it works normal, but when almost complete the remove effect, will see one flash happened at a very strange position between two cells, and then slowly return to the normal animation. - -Now the question is, if I remove the cell of button-0, button-1, button-2, button-3, the animation is OK, but if I delete the last several cell of button-6, button -7, button-8, it will appear unexpected animation. - -And I found that if the flip angle is all fixed, then when delete cell, there will not have strange animation, my `makeRotateTransformForAttributes2` is assigned a fixed angle. -####Fixed - -Then finally know where the problem lies, just because the miscalculation of contentSize leading to the lack of content area, so when the cell is deleted and then rolling will produce this behaviour. so the height which be set in `- (CGSize) collectionViewContentSize` must be correct. - -###Implement add page - -Now the `WKPagesCollectionView` have two states, one is `normal` state, another is `highlight` state. At normal state, one can scroll the pages. When tap on one page, it will trigger to transfer to `highlight` state. In highlight state the page be tapped will be displayed in full screen. -When you go to add a new page, you need to press `+` which at the bottom of screen to add a page, then the last page which be added will be displayed in full screen(`highlight` state). If currently is in `highlight` state, it will back to `normal` state and then transfer to `highlight` state to display the last page in full screen. +### CocoaPods + pod 'WKPagesCollectionView', :git => 'git@github.com:NextFaze/WKPagesCollectionView.git' -Here is add page method in `WKPagesCollectionView`: +### Manually +Add `WKPagesCollectionView` folder and the following files inside it to project :`WK.h`, `WKPagesCollectionView.h`, `WKPagesCollectionView.m`, `WKPagesCollectionViewCell.h`, `WKPagesCollectionViewCell.m`, `WKPagesCollectionViewFlowLayout.h`, `WKPagesCollectionViewFlowLayout.m`; - ///Append an item - -(void)appendItem{ - if (self.isHighLight){ - [self dismissFromHightLightWithCompletion:^(BOOL finished) { - [self addNewPage]; - }]; - } - else{ - [self addNewPage]; - } - } - ///Add a new page - -(void)addNewPage{ - int total=[self numberOfItemsInSection:0]; - [self scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:total-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; - double delayInSeconds = 0.3f; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - ///Add an item - [(id)self.dataSource willAppendItemInCollectionView:self]; - int lastRow=total; - NSIndexPath* insertIndexPath=[NSIndexPath indexPathForItem:lastRow inSection:0]; - [self performBatchUpdates:^{ - [self insertItemsAtIndexPaths:@[insertIndexPath]]; - } completion:^(BOOL finished) { - double delayInSeconds = 0.3f; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - [self showCellToHighLightAtIndexPath:insertIndexPath completion:^(BOOL finished) { - - }]; - }); - - }]; - }); - } +### LICENSE +??? From 39e7303284d977f5613ecb4af5a66f5303111429 Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Mon, 20 Apr 2015 15:02:16 +0930 Subject: [PATCH 30/31] added LICENSE file --- LICENSE.txt | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 6 +- 2 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..d5a08b8 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2010-2013 NextFaze + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index b37f972..edb53a7 100644 --- a/README.md +++ b/README.md @@ -18,5 +18,7 @@ Features: ### Manually Add `WKPagesCollectionView` folder and the following files inside it to project :`WK.h`, `WKPagesCollectionView.h`, `WKPagesCollectionView.m`, `WKPagesCollectionViewCell.h`, `WKPagesCollectionViewCell.m`, `WKPagesCollectionViewFlowLayout.h`, `WKPagesCollectionViewFlowLayout.m`; -### LICENSE -??? +## License + +WKPagesCollectionView is licensed under the terms of the [Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). Please see the [LICENSE](/LICENSE.txt) file for full details. + From 254c300a79bcca6b852343366cfd5472a086bfb4 Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Mon, 20 Apr 2015 15:03:49 +0930 Subject: [PATCH 31/31] updated LICENSE --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index d5a08b8..747a47f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2010-2013 NextFaze + Copyright 2015 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.