From ef216f94f9452156f982242bef830cfffd1d691e Mon Sep 17 00:00:00 2001 From: "[KOP] Thuong Corleone" Date: Fri, 10 Nov 2017 17:47:33 +0700 Subject: [PATCH 01/28] fix iphoneX top --- ICViewPager/ICViewPager/ViewPagerController.m | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/ICViewPager/ICViewPager/ViewPagerController.m b/ICViewPager/ICViewPager/ViewPagerController.m index 7c3ceb4..2241145 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.m +++ b/ICViewPager/ICViewPager/ViewPagerController.m @@ -203,10 +203,26 @@ - (void)didReceiveMemoryWarning { - (void)layoutSubviews { CGFloat topLayoutGuide = 0.0; - if (IOS_VERSION_7) { - topLayoutGuide = 20.0; - if (self.navigationController && !self.navigationController.navigationBarHidden) { - topLayoutGuide += self.navigationController.navigationBar.frame.size.height; + + + if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) { + + switch ((int)[[UIScreen mainScreen] nativeBounds].size.height) { + + + case 2436: + topLayoutGuide = 44.0; + if (self.navigationController && !self.navigationController.navigationBarHidden) { + topLayoutGuide += self.navigationController.navigationBar.frame.size.height; + } + break; + default: + if (IOS_VERSION_7) { + topLayoutGuide = 20.0; + if (self.navigationController && !self.navigationController.navigationBarHidden) { + topLayoutGuide += self.navigationController.navigationBar.frame.size.height; + } + } } } From a159f6015b44bbd1da23f4781915acb9e711a68f Mon Sep 17 00:00:00 2001 From: "[KOP] Thuong Corleone" Date: Fri, 10 Nov 2017 17:53:40 +0700 Subject: [PATCH 02/28] fix some thing --- ICViewPager/ICViewPager/ViewPagerController.m | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ICViewPager/ICViewPager/ViewPagerController.m b/ICViewPager/ICViewPager/ViewPagerController.m index 2241145..3ceba24 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.m +++ b/ICViewPager/ICViewPager/ViewPagerController.m @@ -205,6 +205,13 @@ - (void)layoutSubviews { CGFloat topLayoutGuide = 0.0; + if (IOS_VERSION_7) { + topLayoutGuide = 20.0; + if (self.navigationController && !self.navigationController.navigationBarHidden) { + topLayoutGuide += self.navigationController.navigationBar.frame.size.height; + } + } + if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) { switch ((int)[[UIScreen mainScreen] nativeBounds].size.height) { @@ -217,12 +224,8 @@ - (void)layoutSubviews { } break; default: - if (IOS_VERSION_7) { - topLayoutGuide = 20.0; - if (self.navigationController && !self.navigationController.navigationBarHidden) { - topLayoutGuide += self.navigationController.navigationBar.frame.size.height; - } - } + NSLog(@""); + } } From 8b410019afe9d12eda2e5c93f485bdacc7180fc2 Mon Sep 17 00:00:00 2001 From: "[KOP] Thuong Corleone" Date: Tue, 14 Nov 2017 14:47:24 +0700 Subject: [PATCH 03/28] fix navigator iphone x --- ICViewPager/ICViewPager/ViewPagerController.m | 45 ++++--------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/ICViewPager/ICViewPager/ViewPagerController.m b/ICViewPager/ICViewPager/ViewPagerController.m index 3ceba24..0d4ac07 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.m +++ b/ICViewPager/ICViewPager/ViewPagerController.m @@ -203,32 +203,17 @@ - (void)didReceiveMemoryWarning { - (void)layoutSubviews { CGFloat topLayoutGuide = 0.0; - - if (IOS_VERSION_7) { + if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone && ((int)[[UIScreen mainScreen] nativeBounds].size.height) == 2436) { + topLayoutGuide = 44.0; + } else { topLayoutGuide = 20.0; + } if (self.navigationController && !self.navigationController.navigationBarHidden) { topLayoutGuide += self.navigationController.navigationBar.frame.size.height; } } - if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) { - - switch ((int)[[UIScreen mainScreen] nativeBounds].size.height) { - - - case 2436: - topLayoutGuide = 44.0; - if (self.navigationController && !self.navigationController.navigationBarHidden) { - topLayoutGuide += self.navigationController.navigationBar.frame.size.height; - } - break; - default: - NSLog(@""); - - } - } - CGRect frame = self.tabsView.frame; frame.origin.x = 0.0; frame.origin.y = [self.tabLocation boolValue] ? topLayoutGuide : CGRectGetHeight(self.view.frame) - [self.tabHeight floatValue]; @@ -240,7 +225,7 @@ - (void)layoutSubviews { frame.origin.x = 0.0; frame.origin.y = [self.tabLocation boolValue] ? topLayoutGuide + CGRectGetHeight(self.tabsView.frame) : topLayoutGuide; frame.size.width = CGRectGetWidth(self.view.frame); - frame.size.height = CGRectGetHeight(self.view.frame) - (topLayoutGuide + CGRectGetHeight(self.tabsView.frame)) - (self.tabBarController.tabBar.hidden ? 0 : CGRectGetHeight(self.tabBarController.tabBar.frame)); + frame.size.height = CGRectGetHeight(self.view.frame) - (topLayoutGuide + CGRectGetHeight(self.tabsView.frame)) - CGRectGetHeight(self.tabBarController.tabBar.frame); self.contentView.frame = frame; } @@ -255,7 +240,7 @@ - (IBAction)handleTapGesture:(id)sender { //if Tap is not selected Tab(new Tab) if (self.activeTabIndex != index) { // Select the tab - [self selectTabAtIndex:index didSwipe:NO]; + [self selectTabAtIndex:index]; } } @@ -592,12 +577,7 @@ - (void)reloadData { // Call to setup again with the updated data [self defaultSetup]; } - - (void)selectTabAtIndex:(NSUInteger)index { - [self selectTabAtIndex:index didSwipe:NO]; -} - -- (void)selectTabAtIndex:(NSUInteger)index didSwipe:(BOOL)didSwipe { if (index >= self.tabCount) { return; @@ -605,9 +585,6 @@ - (void)selectTabAtIndex:(NSUInteger)index didSwipe:(BOOL)didSwipe { self.animatingToTab = YES; - // Keep a reference to previousIndex in case it is needed for the delegate - NSUInteger previousIndex = self.activeTabIndex; - // Set activeTabIndex self.activeTabIndex = index; @@ -618,12 +595,6 @@ - (void)selectTabAtIndex:(NSUInteger)index didSwipe:(BOOL)didSwipe { if ([self.delegate respondsToSelector:@selector(viewPager:didChangeTabToIndex:)]) { [self.delegate viewPager:self didChangeTabToIndex:self.activeTabIndex]; } - else if([self.delegate respondsToSelector:@selector(viewPager:didChangeTabToIndex:fromIndex:)]){ - [self.delegate viewPager:self didChangeTabToIndex:self.activeTabIndex fromIndex:previousIndex]; - } - else if ([self.delegate respondsToSelector:@selector(viewPager:didChangeTabToIndex:fromIndex:didSwipe:)]) { - [self.delegate viewPager:self didChangeTabToIndex:self.activeTabIndex fromIndex:previousIndex didSwipe:didSwipe]; - } } - (void)setNeedsReloadOptions { @@ -895,7 +866,7 @@ - (void)defaultSetup { // Select starting tab NSUInteger index = [self.startFromSecondTab boolValue] ? 1 : 0; - [self selectTabAtIndex:index didSwipe:NO]; + [self selectTabAtIndex:index]; // Set setup done self.defaultSetupDone = YES; @@ -988,7 +959,7 @@ - (void)pageViewController:(UIPageViewController *)pageViewController didFinishA // Select tab NSUInteger index = [self indexForViewController:viewController]; - [self selectTabAtIndex:index didSwipe:YES]; + [self selectTabAtIndex:index]; } #pragma mark - UIScrollViewDelegate, Responding to Scrolling and Dragging From 1cafd33f721bb108dab8673473137494b07dd52a Mon Sep 17 00:00:00 2001 From: "[KOP] Thuong Corleone" Date: Wed, 22 Nov 2017 11:14:46 +0700 Subject: [PATCH 04/28] add bottom layout --- ICViewPager/ICViewPager/ViewPagerController.m | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ICViewPager/ICViewPager/ViewPagerController.m b/ICViewPager/ICViewPager/ViewPagerController.m index 0d4ac07..2c3400a 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.m +++ b/ICViewPager/ICViewPager/ViewPagerController.m @@ -203,11 +203,16 @@ - (void)didReceiveMemoryWarning { - (void)layoutSubviews { CGFloat topLayoutGuide = 0.0; + CGFloat bottomLayoutGuide = 0.0; if (IOS_VERSION_7) { if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone && ((int)[[UIScreen mainScreen] nativeBounds].size.height) == 2436) { - topLayoutGuide = 44.0; + topLayoutGuide = 44.0f; + if (@available(iOS 11.0, *)) { + UIWindow *window = UIApplication.sharedApplication.keyWindow; + bottomLayoutGuide = window.safeAreaInsets.bottom; + } } else { - topLayoutGuide = 20.0; + topLayoutGuide = 20.0f; } if (self.navigationController && !self.navigationController.navigationBarHidden) { topLayoutGuide += self.navigationController.navigationBar.frame.size.height; @@ -225,7 +230,7 @@ - (void)layoutSubviews { frame.origin.x = 0.0; frame.origin.y = [self.tabLocation boolValue] ? topLayoutGuide + CGRectGetHeight(self.tabsView.frame) : topLayoutGuide; frame.size.width = CGRectGetWidth(self.view.frame); - frame.size.height = CGRectGetHeight(self.view.frame) - (topLayoutGuide + CGRectGetHeight(self.tabsView.frame)) - CGRectGetHeight(self.tabBarController.tabBar.frame); + frame.size.height = CGRectGetHeight(self.view.frame) - bottomLayoutGuide - (topLayoutGuide + CGRectGetHeight(self.tabsView.frame)) - CGRectGetHeight(self.tabBarController.tabBar.frame); self.contentView.frame = frame; } From 6d7a404607161a9e6ceea0cc0fda17555aa796a7 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Fri, 18 May 2018 17:01:40 +0400 Subject: [PATCH 05/28] Update project format to Xcode 9.3 --- ICViewPager.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index 4046009..ba4a377 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -165,7 +165,7 @@ ORGANIZATIONNAME = "Ilter Cengiz"; }; buildConfigurationList = 7CF3D64C17CE32E40021036A /* Build configuration list for PBXProject "ICViewPager" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( From 0800da6431507302e5a25c7913b002e20e77c8f0 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Fri, 18 May 2018 18:17:39 +0400 Subject: [PATCH 06/28] Clean up - Project version updated - Updated project setup - Swift 4.1 - Legacy source moved into a separate group - Created empty screen for control purposes --- ICViewPager.xcodeproj/project.pbxproj | 215 ++++++++++-------- .../Application/ApplicationDelegate.swift | 25 ++ ICViewPager/ICViewPager-Prefix.pch | 14 -- .../AppIcon.appiconset/Contents.json | 90 -------- .../AppIcon.appiconset/Icon-1.png | Bin 7773 -> 0 bytes .../AppIcon.appiconset/Icon.png | Bin 8358 -> 0 bytes .../LaunchImage.launchimage/Contents.json | 91 -------- .../Default-568h@2x.png | Bin 18594 -> 0 bytes ICViewPager/{ => Legacy}/AppDelegate.h | 0 ICViewPager/{ => Legacy}/AppDelegate.m | 0 .../Controller/ContentViewController.h | 0 .../Controller/ContentViewController.m | 0 .../Controller/HostViewController.h | 0 .../Controller/HostViewController.m | 0 .../ICViewPager/ViewPagerController.h | 0 .../ICViewPager/ViewPagerController.m | 0 ICViewPager/{ => Legacy}/iPad.storyboard | 0 ICViewPager/{ => Legacy}/iPhone.storyboard | 0 .../Scenes/Empty/EmptyViewController.swift | 17 ++ .../Info.plist} | 10 +- .../Supporting Files/LaunchScreen.storyboard | 52 +++++ ICViewPager/en.lproj/InfoPlist.strings | 2 - ICViewPager/en.lproj/Localization.strings | 7 - ICViewPager/main.m | 18 -- ICViewPager/tr.lproj/InfoPlist.strings | 2 - ICViewPager/tr.lproj/Localization.strings | 7 - 26 files changed, 220 insertions(+), 330 deletions(-) create mode 100644 ICViewPager/Application/ApplicationDelegate.swift delete mode 100644 ICViewPager/ICViewPager-Prefix.pch delete mode 100644 ICViewPager/Images.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 ICViewPager/Images.xcassets/AppIcon.appiconset/Icon-1.png delete mode 100644 ICViewPager/Images.xcassets/AppIcon.appiconset/Icon.png delete mode 100644 ICViewPager/Images.xcassets/LaunchImage.launchimage/Contents.json delete mode 100644 ICViewPager/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png rename ICViewPager/{ => Legacy}/AppDelegate.h (100%) rename ICViewPager/{ => Legacy}/AppDelegate.m (100%) rename ICViewPager/{ => Legacy}/Controller/ContentViewController.h (100%) rename ICViewPager/{ => Legacy}/Controller/ContentViewController.m (100%) rename ICViewPager/{ => Legacy}/Controller/HostViewController.h (100%) rename ICViewPager/{ => Legacy}/Controller/HostViewController.m (100%) rename ICViewPager/{ => Legacy}/ICViewPager/ViewPagerController.h (100%) rename ICViewPager/{ => Legacy}/ICViewPager/ViewPagerController.m (100%) rename ICViewPager/{ => Legacy}/iPad.storyboard (100%) rename ICViewPager/{ => Legacy}/iPhone.storyboard (100%) create mode 100644 ICViewPager/Scenes/Empty/EmptyViewController.swift rename ICViewPager/{ICViewPager-Info.plist => Supporting Files/Info.plist} (89%) create mode 100644 ICViewPager/Supporting Files/LaunchScreen.storyboard delete mode 100644 ICViewPager/en.lproj/InfoPlist.strings delete mode 100644 ICViewPager/en.lproj/Localization.strings delete mode 100644 ICViewPager/main.m delete mode 100644 ICViewPager/tr.lproj/InfoPlist.strings delete mode 100644 ICViewPager/tr.lproj/Localization.strings diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index ba4a377..e8f3d07 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -7,38 +7,21 @@ objects = { /* Begin PBXBuildFile section */ - 7C115E011816DED1000BCE63 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7C115E001816DED1000BCE63 /* Images.xcassets */; }; - 7CEC17A917DA1EC000E4A439 /* iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7CEC17A817DA1EC000E4A439 /* iPad.storyboard */; }; - 7CF3D65517CE32E40021036A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CF3D65417CE32E40021036A /* UIKit.framework */; }; - 7CF3D65717CE32E40021036A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CF3D65617CE32E40021036A /* Foundation.framework */; }; - 7CF3D65917CE32E40021036A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CF3D65817CE32E40021036A /* CoreGraphics.framework */; }; - 7CF3D65F17CE32E40021036A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7CF3D65D17CE32E40021036A /* InfoPlist.strings */; }; - 7CF3D66117CE32E40021036A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CF3D66017CE32E40021036A /* main.m */; }; - 7CF3D66517CE32E40021036A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CF3D66417CE32E40021036A /* AppDelegate.m */; }; - 7CF3D67617CE336E0021036A /* Localization.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7CF3D67817CE336E0021036A /* Localization.strings */; }; - 7CF3D67E17CE33E10021036A /* ViewPagerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CF3D67D17CE33E10021036A /* ViewPagerController.m */; }; - 7CF3D68117CE33EC0021036A /* HostViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CF3D68017CE33EC0021036A /* HostViewController.m */; }; - 7CF3D68217CE35500021036A /* iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7CF3D67117CE332F0021036A /* iPhone.storyboard */; }; - 7CF3D68517CE3F5B0021036A /* ContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CF3D68417CE3F5B0021036A /* ContentViewController.m */; }; + 36F4A3B220AF0685000995B2 /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */; }; + 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */; }; + 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 7C115E001816DED1000BCE63 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = ""; }; + 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyViewController.swift; sourceTree = ""; }; + 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 7CEC17A817DA1EC000E4A439 /* iPad.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = iPad.storyboard; sourceTree = ""; }; 7CF3D65117CE32E40021036A /* ICViewPager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ICViewPager.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 7CF3D65417CE32E40021036A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 7CF3D65617CE32E40021036A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 7CF3D65817CE32E40021036A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 7CF3D65C17CE32E40021036A /* ICViewPager-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ICViewPager-Info.plist"; sourceTree = ""; }; - 7CF3D65E17CE32E40021036A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 7CF3D66017CE32E40021036A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 7CF3D66217CE32E40021036A /* ICViewPager-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ICViewPager-Prefix.pch"; sourceTree = ""; }; + 7CF3D65C17CE32E40021036A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 7CF3D66317CE32E40021036A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7CF3D66417CE32E40021036A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 7CF3D67117CE332F0021036A /* iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = iPhone.storyboard; sourceTree = ""; }; - 7CF3D67317CE335B0021036A /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; }; - 7CF3D67717CE336E0021036A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localization.strings; sourceTree = ""; }; - 7CF3D67917CE336F0021036A /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localization.strings; sourceTree = ""; }; 7CF3D67C17CE33E10021036A /* ViewPagerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewPagerController.h; sourceTree = ""; }; 7CF3D67D17CE33E10021036A /* ViewPagerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewPagerController.m; sourceTree = ""; }; 7CF3D67F17CE33EC0021036A /* HostViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HostViewController.h; sourceTree = ""; }; @@ -52,43 +35,37 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7CF3D65517CE32E40021036A /* UIKit.framework in Frameworks */, - 7CF3D65717CE32E40021036A /* Foundation.framework in Frameworks */, - 7CF3D65917CE32E40021036A /* CoreGraphics.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 7CF3D64817CE32E40021036A = { + 36F4A3B020AF0675000995B2 /* Application */ = { isa = PBXGroup; children = ( - 7CF3D65A17CE32E40021036A /* ICViewPager */, - 7CF3D65317CE32E40021036A /* Frameworks */, - 7CF3D65217CE32E40021036A /* Products */, + 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */, ); + path = Application; sourceTree = ""; }; - 7CF3D65217CE32E40021036A /* Products */ = { + 36F4A3B320AF0E1D000995B2 /* Scenes */ = { isa = PBXGroup; children = ( - 7CF3D65117CE32E40021036A /* ICViewPager.app */, + 36F4A3B420AF0EB1000995B2 /* Empty */, ); - name = Products; + path = Scenes; sourceTree = ""; }; - 7CF3D65317CE32E40021036A /* Frameworks */ = { + 36F4A3B420AF0EB1000995B2 /* Empty */ = { isa = PBXGroup; children = ( - 7CF3D65417CE32E40021036A /* UIKit.framework */, - 7CF3D65617CE32E40021036A /* Foundation.framework */, - 7CF3D65817CE32E40021036A /* CoreGraphics.framework */, + 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */, ); - name = Frameworks; + path = Empty; sourceTree = ""; }; - 7CF3D65A17CE32E40021036A /* ICViewPager */ = { + 36F4A3B720AF0F22000995B2 /* Legacy */ = { isa = PBXGroup; children = ( 7CF3D66317CE32E40021036A /* AppDelegate.h */, @@ -97,22 +74,44 @@ 7CEC17A817DA1EC000E4A439 /* iPad.storyboard */, 7CF3D67B17CE33C80021036A /* ICViewPager */, 7CF3D67A17CE33C80021036A /* Controller */, - 7C115E001816DED1000BCE63 /* Images.xcassets */, - 7CF3D65B17CE32E40021036A /* Supporting Files */, ); - path = ICViewPager; + path = Legacy; + sourceTree = ""; + }; + 36F4A3BB20AF0FC4000995B2 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 7CF3D65C17CE32E40021036A /* Info.plist */, + 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */, + ); + path = "Supporting Files"; + sourceTree = ""; + }; + 7CF3D64817CE32E40021036A = { + isa = PBXGroup; + children = ( + 7CF3D65A17CE32E40021036A /* ICViewPager */, + 7CF3D65217CE32E40021036A /* Products */, + ); + sourceTree = ""; + }; + 7CF3D65217CE32E40021036A /* Products */ = { + isa = PBXGroup; + children = ( + 7CF3D65117CE32E40021036A /* ICViewPager.app */, + ); + name = Products; sourceTree = ""; }; - 7CF3D65B17CE32E40021036A /* Supporting Files */ = { + 7CF3D65A17CE32E40021036A /* ICViewPager */ = { isa = PBXGroup; children = ( - 7CF3D65C17CE32E40021036A /* ICViewPager-Info.plist */, - 7CF3D65D17CE32E40021036A /* InfoPlist.strings */, - 7CF3D66017CE32E40021036A /* main.m */, - 7CF3D66217CE32E40021036A /* ICViewPager-Prefix.pch */, - 7CF3D67817CE336E0021036A /* Localization.strings */, + 36F4A3B020AF0675000995B2 /* Application */, + 36F4A3B320AF0E1D000995B2 /* Scenes */, + 36F4A3BB20AF0FC4000995B2 /* Supporting Files */, + 36F4A3B720AF0F22000995B2 /* Legacy */, ); - name = "Supporting Files"; + path = ICViewPager; sourceTree = ""; }; 7CF3D67A17CE33C80021036A /* Controller */ = { @@ -161,8 +160,13 @@ 7CF3D64917CE32E40021036A /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0460; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Ilter Cengiz"; + TargetAttributes = { + 7CF3D65017CE32E40021036A = { + LastSwiftMigration = 0930; + }; + }; }; buildConfigurationList = 7CF3D64C17CE32E40021036A /* Build configuration list for PBXProject "ICViewPager" */; compatibilityVersion = "Xcode 9.3"; @@ -187,11 +191,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7CF3D65F17CE32E40021036A /* InfoPlist.strings in Resources */, - 7C115E011816DED1000BCE63 /* Images.xcassets in Resources */, - 7CF3D68217CE35500021036A /* iPhone.storyboard in Resources */, - 7CEC17A917DA1EC000E4A439 /* iPad.storyboard in Resources */, - 7CF3D67617CE336E0021036A /* Localization.strings in Resources */, + 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -202,64 +202,59 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7CF3D66117CE32E40021036A /* main.m in Sources */, - 7CF3D66517CE32E40021036A /* AppDelegate.m in Sources */, - 7CF3D67E17CE33E10021036A /* ViewPagerController.m in Sources */, - 7CF3D68117CE33EC0021036A /* HostViewController.m in Sources */, - 7CF3D68517CE3F5B0021036A /* ContentViewController.m in Sources */, + 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */, + 36F4A3B220AF0685000995B2 /* ApplicationDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXVariantGroup section */ - 7CF3D65D17CE32E40021036A /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 7CF3D65E17CE32E40021036A /* en */, - 7CF3D67317CE335B0021036A /* tr */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 7CF3D67817CE336E0021036A /* Localization.strings */ = { - isa = PBXVariantGroup; - children = ( - 7CF3D67717CE336E0021036A /* en */, - 7CF3D67917CE336F0021036A /* tr */, - ); - name = Localization.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ 7CF3D66C17CE32E40021036A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -270,23 +265,42 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.1; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -295,13 +309,20 @@ 7CF3D66F17CE32E40021036A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; + DEVELOPMENT_TEAM = P8EBW8LF2M; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "ICViewPager/ICViewPager-Prefix.pch"; - INFOPLIST_FILE = "ICViewPager/ICViewPager-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + INFOPLIST_FILE = "$(SRCROOT)/ICViewPager/Supporting Files/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "info.iltercengiz.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; name = Debug; @@ -309,13 +330,19 @@ 7CF3D67017CE32E40021036A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; + DEVELOPMENT_TEAM = P8EBW8LF2M; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "ICViewPager/ICViewPager-Prefix.pch"; - INFOPLIST_FILE = "ICViewPager/ICViewPager-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + INFOPLIST_FILE = "$(SRCROOT)/ICViewPager/Supporting Files/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "info.iltercengiz.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/ICViewPager/Application/ApplicationDelegate.swift b/ICViewPager/Application/ApplicationDelegate.swift new file mode 100644 index 0000000..5e2afad --- /dev/null +++ b/ICViewPager/Application/ApplicationDelegate.swift @@ -0,0 +1,25 @@ +// +// ApplicationDelegate.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class ApplicationDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + + window = UIWindow(frame: UIScreen.main.bounds) + window?.rootViewController = EmptyViewController() + window?.makeKeyAndVisible() + + return true + } +} diff --git a/ICViewPager/ICViewPager-Prefix.pch b/ICViewPager/ICViewPager-Prefix.pch deleted file mode 100644 index 5325a36..0000000 --- a/ICViewPager/ICViewPager-Prefix.pch +++ /dev/null @@ -1,14 +0,0 @@ -// -// Prefix header for all source files of the 'ICViewPager' target in the 'ICViewPager' project -// - -#import - -#ifndef __IPHONE_3_0 -#warning "This project uses features only available in iOS SDK 3.0 and later." -#endif - -#ifdef __OBJC__ - #import - #import -#endif diff --git a/ICViewPager/Images.xcassets/AppIcon.appiconset/Contents.json b/ICViewPager/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 8dc09c3..0000000 --- a/ICViewPager/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "57x57", - "scale" : "1x" - }, - { - "size" : "57x57", - "idiom" : "iphone", - "filename" : "Icon-1.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon.png", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "50x50", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "50x50", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "72x72", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "72x72", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/ICViewPager/Images.xcassets/AppIcon.appiconset/Icon-1.png b/ICViewPager/Images.xcassets/AppIcon.appiconset/Icon-1.png deleted file mode 100644 index 97ebcca58fa62e8890e761960473c6dc63e757a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7773 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 diff --git a/ICViewPager/Images.xcassets/LaunchImage.launchimage/Contents.json b/ICViewPager/Images.xcassets/LaunchImage.launchimage/Contents.json deleted file mode 100644 index 8b61e90..0000000 --- a/ICViewPager/Images.xcassets/LaunchImage.launchimage/Contents.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "1x", - "orientation" : "portrait" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "orientation" : "portrait" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "filename" : "Default-568h@2x.png", - "subtype" : "retina4", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "filename" : "Default-568h@2x.png", - "minimum-system-version" : "7.0", - "subtype" : "retina4", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "extent" : "to-status-bar", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "extent" : "to-status-bar", - "scale" : "2x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "extent" : "to-status-bar", - "scale" : "1x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "extent" : "to-status-bar", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "minimum-system-version" : "7.0", - "extent" : "full-screen", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "minimum-system-version" : "7.0", - "extent" : "full-screen", - "scale" : "2x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "minimum-system-version" : "7.0", - "extent" : "full-screen", - "scale" : "1x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "minimum-system-version" : "7.0", - "extent" : "full-screen", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/ICViewPager/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/ICViewPager/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png deleted file mode 100644 index 0891b7aabfcf3422423b109c8beed2bab838c607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18594 zcmeI4X;f257Jx&9fS`ixvS;&$x8J@slQFSel)6zJN=?13FB7H(lQjRkSy8x_-S~tvu2gzn1oS+dLcF#eqtq$ z%tf9TTvX?`)R@}3uBI;jzS-=ZR-Td&MHaS&;!0?Ni*#$#`n*~CcQK)Q9vAQ~TUpnI!j)a2biYK^R)M~A5wUDZhx?ULMX z3x1P&qt=trOY6P2U67L=m=U?F|5#Uj(eCueNTZaHs_ceWiHeET+j+tp3Jt9g(ekqP z2WOvfR{qV+9r+o4J5?qK>7;;^+I7tGv-i)es$X_D=EoKF+S?zsyj^oRFElP}c}JT< zd8SUs-?O?}2YD#ngKbnHgzHBcboxK_2r9l(?eNCl-pEzkJm}fY?WC*jnS?VBE4EpY zO$fEejz6fU;W2Kl>JeQBZBl-%Irg`obSlg*@4QB;Dd1H7^Oi5wvt4d{RZ!8Og?^aE z)k0$1g+V3fd(gdQ3d&q2q-FL*uy#}|bc^=VhFsl0jBgUGJ+-s3U8MK9A!YJJMxpci z5hJ%|{DwV48fZn0{n5l$N_KcSb#NKE4plB`9I6Zt=Z!~-zw0{9tg$L&Ju1F0X)Cy8 zKF;(&lJ>x)Jw(=;p~sF(Sd9VWGwFE2rnyS9!f^DZ8+aCLq zQ};>lcJ1GDLqjm6Hd>|Eabno@P`~Bn(~6^aD_#yoEH(a?Nm1S<;S+hSxI5d16^<1lEM3NPFi zkqPrpL)+ zgnseFikg`gJVBha1&7C4;O6>h=dt~`ND+;Zd?W(4v2JIb7Pt>Td42%M-Ju-XAH#Pns762L}K3 zDhvsRqN0Ni(1UrishD2YvV?4*h2iFj$+&N||Fn$4n|^NSU+o?~jq`0jVQt8T9l{7b zXiwwODFh2V!Q6sqP9S>WH$oOf$N~=d0-bqTlD61!=`&0eAP-F>XN?*|gtOXX{ zQVTWyYo4ZK0GAw!GHf|pz9`D;-bbb*5LBX*{bnz|+)$@&P9|ORM2o?95{;ejvo&r- zq8cBhTN6nn)7~W>54U)%-F_-b?YKdfk5I8MHcuzBD5)!;yv#Z&R&^y=@=>VTIMy#r zX&U<=BsPkdqcMe<_}2+>H%XKyrr5ZR8_KVe>ZqYN z^=^~TFD};;rHJ$U;{~w^hYojl4hRI@SH$^K{YEo=sg)WY87r!*7blQK&qnpDo0`Vn zkl)9u9g=mCh&ZCJS(L4yN3k0kQ zuvg$h2KEEk51T+O0JQ+r0`R>g{jvqM0Mr6d3qUOZwE!?PI7HY@CE|dr sfw?Q;rAv?G4&^^8-z_>&sWXMxvD*gPOU4CBe-*@OtE+wfmVJNyHv)PfH~;_u diff --git a/ICViewPager/AppDelegate.h b/ICViewPager/Legacy/AppDelegate.h similarity index 100% rename from ICViewPager/AppDelegate.h rename to ICViewPager/Legacy/AppDelegate.h diff --git a/ICViewPager/AppDelegate.m b/ICViewPager/Legacy/AppDelegate.m similarity index 100% rename from ICViewPager/AppDelegate.m rename to ICViewPager/Legacy/AppDelegate.m diff --git a/ICViewPager/Controller/ContentViewController.h b/ICViewPager/Legacy/Controller/ContentViewController.h similarity index 100% rename from ICViewPager/Controller/ContentViewController.h rename to ICViewPager/Legacy/Controller/ContentViewController.h diff --git a/ICViewPager/Controller/ContentViewController.m b/ICViewPager/Legacy/Controller/ContentViewController.m similarity index 100% rename from ICViewPager/Controller/ContentViewController.m rename to ICViewPager/Legacy/Controller/ContentViewController.m diff --git a/ICViewPager/Controller/HostViewController.h b/ICViewPager/Legacy/Controller/HostViewController.h similarity index 100% rename from ICViewPager/Controller/HostViewController.h rename to ICViewPager/Legacy/Controller/HostViewController.h diff --git a/ICViewPager/Controller/HostViewController.m b/ICViewPager/Legacy/Controller/HostViewController.m similarity index 100% rename from ICViewPager/Controller/HostViewController.m rename to ICViewPager/Legacy/Controller/HostViewController.m diff --git a/ICViewPager/ICViewPager/ViewPagerController.h b/ICViewPager/Legacy/ICViewPager/ViewPagerController.h similarity index 100% rename from ICViewPager/ICViewPager/ViewPagerController.h rename to ICViewPager/Legacy/ICViewPager/ViewPagerController.h diff --git a/ICViewPager/ICViewPager/ViewPagerController.m b/ICViewPager/Legacy/ICViewPager/ViewPagerController.m similarity index 100% rename from ICViewPager/ICViewPager/ViewPagerController.m rename to ICViewPager/Legacy/ICViewPager/ViewPagerController.m diff --git a/ICViewPager/iPad.storyboard b/ICViewPager/Legacy/iPad.storyboard similarity index 100% rename from ICViewPager/iPad.storyboard rename to ICViewPager/Legacy/iPad.storyboard diff --git a/ICViewPager/iPhone.storyboard b/ICViewPager/Legacy/iPhone.storyboard similarity index 100% rename from ICViewPager/iPhone.storyboard rename to ICViewPager/Legacy/iPhone.storyboard diff --git a/ICViewPager/Scenes/Empty/EmptyViewController.swift b/ICViewPager/Scenes/Empty/EmptyViewController.swift new file mode 100644 index 0000000..0775993 --- /dev/null +++ b/ICViewPager/Scenes/Empty/EmptyViewController.swift @@ -0,0 +1,17 @@ +// +// EmptyViewController.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +class EmptyViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = #colorLiteral(red: 0.7105011344, green: 0.9193516374, blue: 1, alpha: 1) + } +} diff --git a/ICViewPager/ICViewPager-Info.plist b/ICViewPager/Supporting Files/Info.plist similarity index 89% rename from ICViewPager/ICViewPager-Info.plist rename to ICViewPager/Supporting Files/Info.plist index 64d993d..facc833 100644 --- a/ICViewPager/ICViewPager-Info.plist +++ b/ICViewPager/Supporting Files/Info.plist @@ -13,7 +13,7 @@ CFBundleIcons~ipad CFBundleIdentifier - info.iltercengiz.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -21,15 +21,15 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 1.0.0 CFBundleSignature ???? CFBundleVersion - 1.0 + 1 LSRequiresIPhoneOS - UIMainStoryboardFile - iPhone + UILaunchStoryboardName + LaunchScreen UIRequiredDeviceCapabilities armv7 diff --git a/ICViewPager/Supporting Files/LaunchScreen.storyboard b/ICViewPager/Supporting Files/LaunchScreen.storyboard new file mode 100644 index 0000000..085150b --- /dev/null +++ b/ICViewPager/Supporting Files/LaunchScreen.storyboard @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ICViewPager/en.lproj/InfoPlist.strings b/ICViewPager/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28f..0000000 --- a/ICViewPager/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/ICViewPager/en.lproj/Localization.strings b/ICViewPager/en.lproj/Localization.strings deleted file mode 100644 index ed5ec3a..0000000 --- a/ICViewPager/en.lproj/Localization.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localization.strings - ICViewPager - - Created by Ilter Cengiz on 28/08/2013. - Copyright (c) 2013 Ilter Cengiz. All rights reserved. -*/ diff --git a/ICViewPager/main.m b/ICViewPager/main.m deleted file mode 100644 index ba49e8b..0000000 --- a/ICViewPager/main.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// main.m -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import - -#import "AppDelegate.h" - -int main(int argc, char *argv[]) -{ - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/ICViewPager/tr.lproj/InfoPlist.strings b/ICViewPager/tr.lproj/InfoPlist.strings deleted file mode 100644 index 477b28f..0000000 --- a/ICViewPager/tr.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/ICViewPager/tr.lproj/Localization.strings b/ICViewPager/tr.lproj/Localization.strings deleted file mode 100644 index ed5ec3a..0000000 --- a/ICViewPager/tr.lproj/Localization.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localization.strings - ICViewPager - - Created by Ilter Cengiz on 28/08/2013. - Copyright (c) 2013 Ilter Cengiz. All rights reserved. -*/ From 0360d51f9599a76d5feb4bd1b874ef562d79a4f7 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Fri, 18 May 2018 23:16:24 +0400 Subject: [PATCH 07/28] Implement initial layout This change installs a collection view for content, another collection view for tab content, a stack view to house the tab collection view. The stack view later will be used to include an active tab indicator view. --- ICViewPager.xcodeproj/project.pbxproj | 28 ++++++++ .../Application/ApplicationDelegate.swift | 2 +- .../ContentCollectionViewLayout.swift | 13 ++++ .../ICViewPager/TabCollectionViewLayout.swift | 13 ++++ .../ICViewPager/ViewPagerConfiguration.swift | 22 ++++++ .../ICViewPager/ViewPagerController.swift | 50 +++++++++++++ .../ICViewPager/ViewPagerController.xib | 72 +++++++++++++++++++ 7 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 ICViewPager/ICViewPager/ContentCollectionViewLayout.swift create mode 100644 ICViewPager/ICViewPager/TabCollectionViewLayout.swift create mode 100644 ICViewPager/ICViewPager/ViewPagerConfiguration.swift create mode 100644 ICViewPager/ICViewPager/ViewPagerController.swift create mode 100644 ICViewPager/ICViewPager/ViewPagerController.xib diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index e8f3d07..985dd64 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -7,15 +7,25 @@ objects = { /* Begin PBXBuildFile section */ + 36CB293120AF5A370054261E /* ViewPagerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB292F20AF5A370054261E /* ViewPagerController.swift */; }; + 36CB293220AF5A370054261E /* ViewPagerController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 36CB293020AF5A370054261E /* ViewPagerController.xib */; }; + 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */; }; + 36CB293620AF5A610054261E /* ContentCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB293520AF5A610054261E /* ContentCollectionViewLayout.swift */; }; 36F4A3B220AF0685000995B2 /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */; }; 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */; }; 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */; }; + 36F4A3C120AF4F8A000995B2 /* ViewPagerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 36CB292F20AF5A370054261E /* ViewPagerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPagerController.swift; sourceTree = ""; }; + 36CB293020AF5A370054261E /* ViewPagerController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ViewPagerController.xib; sourceTree = ""; }; + 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewLayout.swift; sourceTree = ""; }; + 36CB293520AF5A610054261E /* ContentCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentCollectionViewLayout.swift; sourceTree = ""; }; 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = ""; }; 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyViewController.swift; sourceTree = ""; }; 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPagerConfiguration.swift; sourceTree = ""; }; 7CEC17A817DA1EC000E4A439 /* iPad.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = iPad.storyboard; sourceTree = ""; }; 7CF3D65117CE32E40021036A /* ICViewPager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ICViewPager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7CF3D65C17CE32E40021036A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -87,6 +97,18 @@ path = "Supporting Files"; sourceTree = ""; }; + 36F4A3BC20AF184E000995B2 /* ICViewPager */ = { + isa = PBXGroup; + children = ( + 36CB292F20AF5A370054261E /* ViewPagerController.swift */, + 36CB293020AF5A370054261E /* ViewPagerController.xib */, + 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */, + 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */, + 36CB293520AF5A610054261E /* ContentCollectionViewLayout.swift */, + ); + path = ICViewPager; + sourceTree = ""; + }; 7CF3D64817CE32E40021036A = { isa = PBXGroup; children = ( @@ -108,6 +130,7 @@ children = ( 36F4A3B020AF0675000995B2 /* Application */, 36F4A3B320AF0E1D000995B2 /* Scenes */, + 36F4A3BC20AF184E000995B2 /* ICViewPager */, 36F4A3BB20AF0FC4000995B2 /* Supporting Files */, 36F4A3B720AF0F22000995B2 /* Legacy */, ); @@ -191,6 +214,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 36CB293220AF5A370054261E /* ViewPagerController.xib in Resources */, 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -202,7 +226,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 36CB293620AF5A610054261E /* ContentCollectionViewLayout.swift in Sources */, + 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */, 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */, + 36F4A3C120AF4F8A000995B2 /* ViewPagerConfiguration.swift in Sources */, + 36CB293120AF5A370054261E /* ViewPagerController.swift in Sources */, 36F4A3B220AF0685000995B2 /* ApplicationDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ICViewPager/Application/ApplicationDelegate.swift b/ICViewPager/Application/ApplicationDelegate.swift index 5e2afad..28e6b1b 100644 --- a/ICViewPager/Application/ApplicationDelegate.swift +++ b/ICViewPager/Application/ApplicationDelegate.swift @@ -17,7 +17,7 @@ class ApplicationDelegate: UIResponder, UIApplicationDelegate, UISplitViewContro didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { window = UIWindow(frame: UIScreen.main.bounds) - window?.rootViewController = EmptyViewController() + window?.rootViewController = ViewPagerController() window?.makeKeyAndVisible() return true diff --git a/ICViewPager/ICViewPager/ContentCollectionViewLayout.swift b/ICViewPager/ICViewPager/ContentCollectionViewLayout.swift new file mode 100644 index 0000000..02a546a --- /dev/null +++ b/ICViewPager/ICViewPager/ContentCollectionViewLayout.swift @@ -0,0 +1,13 @@ +// +// ContentCollectionViewLayout.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class ContentCollectionViewLayout: UICollectionViewFlowLayout { + +} diff --git a/ICViewPager/ICViewPager/TabCollectionViewLayout.swift b/ICViewPager/ICViewPager/TabCollectionViewLayout.swift new file mode 100644 index 0000000..4afa06a --- /dev/null +++ b/ICViewPager/ICViewPager/TabCollectionViewLayout.swift @@ -0,0 +1,13 @@ +// +// TabCollectionViewLayout.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class TabCollectionViewLayout: UICollectionViewFlowLayout { + +} diff --git a/ICViewPager/ICViewPager/ViewPagerConfiguration.swift b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift new file mode 100644 index 0000000..3dd786b --- /dev/null +++ b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift @@ -0,0 +1,22 @@ +// +// ViewPagerConfiguration.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +public struct ViewPagerConfiguration { + + public struct Constants { + public static let tabHeight: CGFloat = 44.0 + } + + public var tabHeight: CGFloat + + public init(tabHeight: CGFloat = Constants.tabHeight) { + self.tabHeight = tabHeight + } +} diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift new file mode 100644 index 0000000..d356045 --- /dev/null +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -0,0 +1,50 @@ +// +// ViewPagerController.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final public class ViewPagerController: UIViewController { + + @IBOutlet private weak var contentCollectionView: UICollectionView! + @IBOutlet private weak var tabContainerStackView: UIStackView! + @IBOutlet private weak var tabCollectionView: UICollectionView! + @IBOutlet private weak var tabCollectionViewHeightConstraint: NSLayoutConstraint! + @IBOutlet private weak var tabCollectionViewLayout: TabCollectionViewLayout! + @IBOutlet private weak var contentCollectionViewLayout: ContentCollectionViewLayout! + + public private(set) var configuration: ViewPagerConfiguration + + // MARK: Init + + public init(configuration: ViewPagerConfiguration = ViewPagerConfiguration()) { + self.configuration = configuration + super.init(nibName: nil, bundle: nil) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: View life cycle + + public override func viewDidLoad() { + super.viewDidLoad() + setUpUI() + } +} + +private extension ViewPagerController { + + func setUpUI() { + applyConfiguration(configuration) + } + + func applyConfiguration(_ configuration: ViewPagerConfiguration) { + tabCollectionViewHeightConstraint.constant = configuration.tabHeight + } +} diff --git a/ICViewPager/ICViewPager/ViewPagerController.xib b/ICViewPager/ICViewPager/ViewPagerController.xib new file mode 100644 index 0000000..3be382f --- /dev/null +++ b/ICViewPager/ICViewPager/ViewPagerController.xib @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 639c7703c677c6c8e4e7894fbe09e5c282a77b1c Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sat, 19 May 2018 02:39:27 +0400 Subject: [PATCH 08/28] Implement initial view controller embedding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change does a lot. 😅 After the initial layout implementation, this change implements view controller fetching from the data source and presenting the contents in the content collection view. Although, custom content layout for paging is yet to be implemented. --- ICViewPager.xcodeproj/project.pbxproj | 68 ++++++++++++- .../Application/ApplicationDelegate.swift | 25 ++++- ...ExampleViewPagerControllerDataSource.swift | 42 ++++++++ .../Content/ContentCollectionViewCell.swift | 39 ++++++++ .../ContentCollectionViewDataSource.swift | 95 +++++++++++++++++++ .../ContentCollectionViewDelegate.swift | 57 +++++++++++ .../Content/ContentCollectionViewLayout.swift | 32 +++++++ .../ContentCollectionViewLayout.swift | 13 --- .../ICViewPager/Extensions/UIView+Embed.swift | 23 +++++ .../Extensions/UIViewController+Insets.swift | 35 +++++++ .../{ => Tab}/TabCollectionViewLayout.swift | 0 .../ICViewPager/ViewPagerController.swift | 29 +++++- .../ICViewPager/ViewPagerController.xib | 4 +- .../ViewPagerControllerDataSource.swift | 18 ++++ .../Scenes/Empty/EmptyViewController.swift | 18 +++- .../Scenes/Empty/EmptyViewController.xib | 64 +++++++++++++ 16 files changed, 541 insertions(+), 21 deletions(-) create mode 100644 ICViewPager/Example/ExampleViewPagerControllerDataSource.swift create mode 100644 ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift create mode 100644 ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift create mode 100644 ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift create mode 100644 ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift delete mode 100644 ICViewPager/ICViewPager/ContentCollectionViewLayout.swift create mode 100644 ICViewPager/ICViewPager/Extensions/UIView+Embed.swift create mode 100644 ICViewPager/ICViewPager/Extensions/UIViewController+Insets.swift rename ICViewPager/ICViewPager/{ => Tab}/TabCollectionViewLayout.swift (100%) create mode 100644 ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift create mode 100644 ICViewPager/Scenes/Empty/EmptyViewController.xib diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index 985dd64..0b6b74f 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -11,6 +11,14 @@ 36CB293220AF5A370054261E /* ViewPagerController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 36CB293020AF5A370054261E /* ViewPagerController.xib */; }; 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */; }; 36CB293620AF5A610054261E /* ContentCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB293520AF5A610054261E /* ContentCollectionViewLayout.swift */; }; + 36CB294020AF5F1D0054261E /* ContentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB293F20AF5F1D0054261E /* ContentCollectionViewCell.swift */; }; + 36CB294320AF60440054261E /* UIView+Embed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB294220AF60440054261E /* UIView+Embed.swift */; }; + 36CB294520AF622F0054261E /* ContentCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB294420AF622F0054261E /* ContentCollectionViewDataSource.swift */; }; + 36CB294720AF628F0054261E /* ViewPagerControllerDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB294620AF628F0054261E /* ViewPagerControllerDataSource.swift */; }; + 36CB294920AF687C0054261E /* ContentCollectionViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB294820AF687C0054261E /* ContentCollectionViewDelegate.swift */; }; + 36CB294B20AF6AC20054261E /* EmptyViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 36CB294A20AF6AC20054261E /* EmptyViewController.xib */; }; + 36CB294E20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB294D20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift */; }; + 36CB295020AF80270054261E /* UIViewController+Insets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB294F20AF80270054261E /* UIViewController+Insets.swift */; }; 36F4A3B220AF0685000995B2 /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */; }; 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */; }; 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */; }; @@ -22,6 +30,14 @@ 36CB293020AF5A370054261E /* ViewPagerController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ViewPagerController.xib; sourceTree = ""; }; 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewLayout.swift; sourceTree = ""; }; 36CB293520AF5A610054261E /* ContentCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentCollectionViewLayout.swift; sourceTree = ""; }; + 36CB293F20AF5F1D0054261E /* ContentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentCollectionViewCell.swift; sourceTree = ""; }; + 36CB294220AF60440054261E /* UIView+Embed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Embed.swift"; sourceTree = ""; }; + 36CB294420AF622F0054261E /* ContentCollectionViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentCollectionViewDataSource.swift; sourceTree = ""; }; + 36CB294620AF628F0054261E /* ViewPagerControllerDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPagerControllerDataSource.swift; sourceTree = ""; }; + 36CB294820AF687C0054261E /* ContentCollectionViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentCollectionViewDelegate.swift; sourceTree = ""; }; + 36CB294A20AF6AC20054261E /* EmptyViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EmptyViewController.xib; sourceTree = ""; }; + 36CB294D20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleViewPagerControllerDataSource.swift; sourceTree = ""; }; + 36CB294F20AF80270054261E /* UIViewController+Insets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Insets.swift"; sourceTree = ""; }; 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = ""; }; 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyViewController.swift; sourceTree = ""; }; 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; @@ -51,6 +67,42 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 36CB294120AF60370054261E /* Extensions */ = { + isa = PBXGroup; + children = ( + 36CB294220AF60440054261E /* UIView+Embed.swift */, + 36CB294F20AF80270054261E /* UIViewController+Insets.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 36CB294C20AF6C140054261E /* Example */ = { + isa = PBXGroup; + children = ( + 36CB294D20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift */, + ); + path = Example; + sourceTree = ""; + }; + 36CB295120AF824F0054261E /* Content */ = { + isa = PBXGroup; + children = ( + 36CB293520AF5A610054261E /* ContentCollectionViewLayout.swift */, + 36CB293F20AF5F1D0054261E /* ContentCollectionViewCell.swift */, + 36CB294420AF622F0054261E /* ContentCollectionViewDataSource.swift */, + 36CB294820AF687C0054261E /* ContentCollectionViewDelegate.swift */, + ); + path = Content; + sourceTree = ""; + }; + 36CB295220AF82590054261E /* Tab */ = { + isa = PBXGroup; + children = ( + 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */, + ); + path = Tab; + sourceTree = ""; + }; 36F4A3B020AF0675000995B2 /* Application */ = { isa = PBXGroup; children = ( @@ -71,6 +123,7 @@ isa = PBXGroup; children = ( 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */, + 36CB294A20AF6AC20054261E /* EmptyViewController.xib */, ); path = Empty; sourceTree = ""; @@ -102,9 +155,11 @@ children = ( 36CB292F20AF5A370054261E /* ViewPagerController.swift */, 36CB293020AF5A370054261E /* ViewPagerController.xib */, + 36CB294620AF628F0054261E /* ViewPagerControllerDataSource.swift */, 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */, - 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */, - 36CB293520AF5A610054261E /* ContentCollectionViewLayout.swift */, + 36CB295220AF82590054261E /* Tab */, + 36CB295120AF824F0054261E /* Content */, + 36CB294120AF60370054261E /* Extensions */, ); path = ICViewPager; sourceTree = ""; @@ -129,6 +184,7 @@ isa = PBXGroup; children = ( 36F4A3B020AF0675000995B2 /* Application */, + 36CB294C20AF6C140054261E /* Example */, 36F4A3B320AF0E1D000995B2 /* Scenes */, 36F4A3BC20AF184E000995B2 /* ICViewPager */, 36F4A3BB20AF0FC4000995B2 /* Supporting Files */, @@ -214,6 +270,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 36CB294B20AF6AC20054261E /* EmptyViewController.xib in Resources */, 36CB293220AF5A370054261E /* ViewPagerController.xib in Resources */, 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */, ); @@ -226,11 +283,18 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 36CB294920AF687C0054261E /* ContentCollectionViewDelegate.swift in Sources */, 36CB293620AF5A610054261E /* ContentCollectionViewLayout.swift in Sources */, + 36CB294720AF628F0054261E /* ViewPagerControllerDataSource.swift in Sources */, 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */, + 36CB294020AF5F1D0054261E /* ContentCollectionViewCell.swift in Sources */, 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */, + 36CB294E20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift in Sources */, 36F4A3C120AF4F8A000995B2 /* ViewPagerConfiguration.swift in Sources */, 36CB293120AF5A370054261E /* ViewPagerController.swift in Sources */, + 36CB294520AF622F0054261E /* ContentCollectionViewDataSource.swift in Sources */, + 36CB295020AF80270054261E /* UIViewController+Insets.swift in Sources */, + 36CB294320AF60440054261E /* UIView+Embed.swift in Sources */, 36F4A3B220AF0685000995B2 /* ApplicationDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ICViewPager/Application/ApplicationDelegate.swift b/ICViewPager/Application/ApplicationDelegate.swift index 28e6b1b..16f5be3 100644 --- a/ICViewPager/Application/ApplicationDelegate.swift +++ b/ICViewPager/Application/ApplicationDelegate.swift @@ -12,14 +12,37 @@ import UIKit class ApplicationDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate { var window: UIWindow? + private let dataSource = ExampleViewPagerControllerDataSource() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + + window = UIWindow(frame: UIScreen.main.bounds) - window?.rootViewController = ViewPagerController() +// window?.rootViewController = viewPagerController() +// window?.rootViewController = navigationController() + window?.rootViewController = tabBarController() window?.makeKeyAndVisible() return true } + + // MARK: Functions for test purposes + + private func viewPagerController() -> ViewPagerController { + let viewPagerController = ViewPagerController() + viewPagerController.dataSource = dataSource + return viewPagerController + } + + private func navigationController() -> UINavigationController { + return UINavigationController(rootViewController: viewPagerController()) + } + + private func tabBarController() -> UITabBarController { + let tabBarController = UITabBarController() + tabBarController.viewControllers = [navigationController()] + return tabBarController + } } diff --git a/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift new file mode 100644 index 0000000..626bed9 --- /dev/null +++ b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift @@ -0,0 +1,42 @@ +// +// ExampleViewPagerControllerDataSource.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class ExampleViewPagerControllerDataSource { + + private var viewControllers: [UIViewController] = [ + EmptyViewController(backgroundColor: #colorLiteral(red: 0.1019607857, green: 0.2784313858, blue: 0.400000006, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.7254902124, green: 0.4784313738, blue: 0.09803921729, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.3098039329, green: 0.2039215714, blue: 0.03921568766, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1)), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.521568656, green: 0.1098039225, blue: 0.05098039284, alpha: 1)) + ] +} + +extension ExampleViewPagerControllerDataSource: ViewPagerControllerDataSource { + + func viewPagerController(_ controller: ViewPagerController, + viewControllerAt index: Int) -> UIViewController { + return viewControllers[index] + } + + func viewPagerController(_ controller: ViewPagerController, + titleForTabAt index: Int) -> String { + return "Title #\(index)" + } + + func numberOfViews(in controller: ViewPagerController) -> Int { + return viewControllers.count + } +} diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift new file mode 100644 index 0000000..1b933f7 --- /dev/null +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift @@ -0,0 +1,39 @@ +// +// ContentCollectionViewCell.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class ContentCollectionViewCell: UICollectionViewCell { + + private weak var contentViewController: UIViewController? + + // MARK: Public functions + + func configure(contentViewController: UIViewController) { + self.contentViewController = contentViewController + } + + // MARK: View controller containment + + func addContentViewController(to parentViewController: UIViewController) { + + guard let viewController = contentViewController else { return } + + parentViewController.addChildViewController(viewController) + contentView.embed(viewController.view) + viewController.didMove(toParentViewController: parentViewController) + contentViewController = viewController + } + + func removeContentViewController() { + contentViewController?.willMove(toParentViewController: nil) + contentViewController?.view.removeFromSuperview() + contentViewController?.removeFromParentViewController() + contentViewController = nil + } +} diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift new file mode 100644 index 0000000..410c34e --- /dev/null +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift @@ -0,0 +1,95 @@ +// +// ContentCollectionViewDataSource.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class ContentCollectionViewDataSource: NSObject { + + private struct Constants { + static let cellIdentifier = "\(ContentCollectionViewCell.self)" + } + + private unowned var viewPagerController: ViewPagerController + private unowned var collectionView: UICollectionView + private var viewControllerCache: [Int: UIViewController] = [:] + weak var dataSource: ViewPagerControllerDataSource? + + // MARK: Init + + init(viewPagerController: ViewPagerController, collectionView: UICollectionView) { + self.viewPagerController = viewPagerController + self.collectionView = collectionView + super.init() + registerContentCell() + } +} + +// MARK: Private functions + +private extension ContentCollectionViewDataSource { + + func registerContentCell() { + collectionView.register(ContentCollectionViewCell.self, + forCellWithReuseIdentifier: Constants.cellIdentifier) + } + + func viewController(at index: Int) -> UIViewController { + + if let viewController = viewControllerCache[index] { + return viewController + } + + guard let dataSource = dataSource else { + fatalError("ViewPagerControllerDataSource is not provided!") + } + + let viewController = dataSource.viewPagerController(viewPagerController, + viewControllerAt: index) + + if #available(iOS 11.0, *) { + // Do nothing. Safe area guide handles the insets. + } else { + let topInset = viewPagerController.topLayoutGuide.length + viewPagerController.configuration.tabHeight + let bottomInset = viewPagerController.bottomLayoutGuide.length + let insets = UIEdgeInsetsMake(topInset, 0.0, bottomInset, 0.0) + viewController.adjustScrollViewInsets(insets: insets) + } + + viewControllerCache[index] = viewController + + return viewController + } +} + +// MARK: UICollectionViewDataSource + +extension ContentCollectionViewDataSource: UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Constants.cellIdentifier, + for: indexPath) as! ContentCollectionViewCell + let contentViewController = viewController(at: indexPath.item) + cell.configure(contentViewController: contentViewController) + return cell + } + + func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + func collectionView(_ collectionView: UICollectionView, + numberOfItemsInSection section: Int) -> Int { + + guard let dataSource = dataSource else { + fatalError("ViewPagerControllerDataSource is not provided!") + } + + return dataSource.numberOfViews(in: viewPagerController) + } +} diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift new file mode 100644 index 0000000..cd12963 --- /dev/null +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift @@ -0,0 +1,57 @@ +// +// ContentCollectionViewDelegate.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class ContentCollectionViewDelegate: NSObject { + + private unowned var viewPagerController: ViewPagerController + + // MARK: Init + + init(viewPagerController: ViewPagerController) { + self.viewPagerController = viewPagerController + super.init() + } +} + +// MARK: Private functions + +private extension ContentCollectionViewDelegate { + +} + +// MARK: UICollectionViewDelegate + +extension ContentCollectionViewDelegate: UICollectionViewDelegate { + + public func collectionView(_ collectionView: UICollectionView, + willDisplay cell: UICollectionViewCell, + forItemAt indexPath: IndexPath) { + guard let contentCell = cell as? ContentCollectionViewCell else { return } + contentCell.addContentViewController(to: viewPagerController) + } + + public func collectionView(_ collectionView: UICollectionView, + didEndDisplaying cell: UICollectionViewCell, + forItemAt indexPath: IndexPath) { + guard let contentCell = cell as? ContentCollectionViewCell else { return } + contentCell.removeContentViewController() + } +} + +// MARK: UICollectionViewDelegateFlowLayout + +extension ContentCollectionViewDelegate: UICollectionViewDelegateFlowLayout { + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + return collectionView.bounds.size + } +} diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift new file mode 100644 index 0000000..44b31e9 --- /dev/null +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift @@ -0,0 +1,32 @@ +// +// ContentCollectionViewLayout.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class ContentCollectionViewLayout: UICollectionViewFlowLayout { + + override init() { + super.init() + setUpLayout() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setUpLayout() + } +} + +private extension ContentCollectionViewLayout { + + func setUpLayout() { + scrollDirection = .horizontal + sectionInset = .zero + minimumInteritemSpacing = 0.0 + minimumLineSpacing = 0.0 + } +} diff --git a/ICViewPager/ICViewPager/ContentCollectionViewLayout.swift b/ICViewPager/ICViewPager/ContentCollectionViewLayout.swift deleted file mode 100644 index 02a546a..0000000 --- a/ICViewPager/ICViewPager/ContentCollectionViewLayout.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// ContentCollectionViewLayout.swift -// ICViewPager -// -// Created by Ilter Cengiz on 18/5/18. -// Copyright © 2018 Ilter Cengiz. All rights reserved. -// - -import UIKit - -final class ContentCollectionViewLayout: UICollectionViewFlowLayout { - -} diff --git a/ICViewPager/ICViewPager/Extensions/UIView+Embed.swift b/ICViewPager/ICViewPager/Extensions/UIView+Embed.swift new file mode 100644 index 0000000..12c9dc4 --- /dev/null +++ b/ICViewPager/ICViewPager/Extensions/UIView+Embed.swift @@ -0,0 +1,23 @@ +// +// UIView+Embed.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +extension UIView { + + func embed(_ view: UIView, insets: UIEdgeInsets = .zero) { + view.translatesAutoresizingMaskIntoConstraints = false + addSubview(view) + NSLayoutConstraint.activate( + [view.topAnchor.constraint(equalTo: topAnchor, constant: insets.top), + view.leadingAnchor.constraint(equalTo: leadingAnchor, constant: insets.left), + view.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -insets.bottom), + view.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -insets.right)] + ) + } +} diff --git a/ICViewPager/ICViewPager/Extensions/UIViewController+Insets.swift b/ICViewPager/ICViewPager/Extensions/UIViewController+Insets.swift new file mode 100644 index 0000000..5b67b9f --- /dev/null +++ b/ICViewPager/ICViewPager/Extensions/UIViewController+Insets.swift @@ -0,0 +1,35 @@ +// +// UIViewController+Insets.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +extension UIViewController { + + func adjustScrollViewInsets(insets: UIEdgeInsets) { + if let scrollView = firstQualifyingScrollView() { + adjustInsets(of: scrollView, insets: insets) + } + } + + private func firstQualifyingScrollView() -> UIScrollView? { + if let scrollView = view as? UIScrollView { + return scrollView + } else if let scrollView = view.subviews.first as? UIScrollView { + return scrollView + } + return nil + } + + private func adjustInsets(of scrollView: UIScrollView, insets: UIEdgeInsets) { + var scrollViewInsets = scrollView.contentInset + scrollViewInsets.top = insets.top + scrollViewInsets.bottom = insets.bottom + scrollView.contentInset = scrollViewInsets + scrollView.scrollIndicatorInsets = scrollViewInsets + } +} diff --git a/ICViewPager/ICViewPager/TabCollectionViewLayout.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift similarity index 100% rename from ICViewPager/ICViewPager/TabCollectionViewLayout.swift rename to ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index d356045..4151de9 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -17,7 +17,11 @@ final public class ViewPagerController: UIViewController { @IBOutlet private weak var tabCollectionViewLayout: TabCollectionViewLayout! @IBOutlet private weak var contentCollectionViewLayout: ContentCollectionViewLayout! - public private(set) var configuration: ViewPagerConfiguration + private var contentCollectionViewDataSource: ContentCollectionViewDataSource! + private var contentCollectionViewDelegate: ContentCollectionViewDelegate! + + public weak var dataSource: ViewPagerControllerDataSource? + public var configuration: ViewPagerConfiguration // MARK: Init @@ -27,7 +31,8 @@ final public class ViewPagerController: UIViewController { } required public init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") + configuration = ViewPagerConfiguration() + super.init(coder: aDecoder) } // MARK: View life cycle @@ -41,9 +46,29 @@ final public class ViewPagerController: UIViewController { private extension ViewPagerController { func setUpUI() { + if #available(iOS 11.0, *) { + additionalSafeAreaInsets = UIEdgeInsetsMake(configuration.tabHeight, 0.0, 0.0, 0.0) + contentCollectionView.contentInsetAdjustmentBehavior = .never + } else { + if let constraint = view.constraints.first(where: { $0.identifier == "tabAlignmentConstraint" }) { + view.removeConstraint(constraint) + } + topLayoutGuide.bottomAnchor.constraint(equalTo: tabContainerStackView.topAnchor).isActive = true + automaticallyAdjustsScrollViewInsets = false + } + setUpContentCollectionView(contentCollectionView) applyConfiguration(configuration) } + func setUpContentCollectionView(_ collectionView: UICollectionView) { + contentCollectionViewDataSource = ContentCollectionViewDataSource(viewPagerController: self, + collectionView: collectionView) + contentCollectionViewDataSource.dataSource = dataSource + contentCollectionViewDelegate = ContentCollectionViewDelegate(viewPagerController: self) + collectionView.dataSource = contentCollectionViewDataSource + collectionView.delegate = contentCollectionViewDelegate + } + func applyConfiguration(_ configuration: ViewPagerConfiguration) { tabCollectionViewHeightConstraint.constant = configuration.tabHeight } diff --git a/ICViewPager/ICViewPager/ViewPagerController.xib b/ICViewPager/ICViewPager/ViewPagerController.xib index 3be382f..b9726be 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.xib +++ b/ICViewPager/ICViewPager/ViewPagerController.xib @@ -37,7 +37,7 @@ - + @@ -57,7 +57,7 @@ - + diff --git a/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift b/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift new file mode 100644 index 0000000..af0d7ac --- /dev/null +++ b/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift @@ -0,0 +1,18 @@ +// +// ViewPagerControllerDataSource.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +public protocol ViewPagerControllerDataSource: class { + + func viewPagerController(_ controller: ViewPagerController, viewControllerAt index: Int) -> UIViewController + + func viewPagerController(_ controller: ViewPagerController, titleForTabAt index: Int) -> String + + func numberOfViews(in controller: ViewPagerController) -> Int +} diff --git a/ICViewPager/Scenes/Empty/EmptyViewController.swift b/ICViewPager/Scenes/Empty/EmptyViewController.swift index 0775993..6099937 100644 --- a/ICViewPager/Scenes/Empty/EmptyViewController.swift +++ b/ICViewPager/Scenes/Empty/EmptyViewController.swift @@ -10,8 +10,24 @@ import UIKit class EmptyViewController: UIViewController { + var backgroundColor: UIColor + + // MARK: Init + + init(backgroundColor: UIColor) { + self.backgroundColor = backgroundColor + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + backgroundColor = .blue + super.init(coder: aDecoder) + } + + // MARK: View life cycle + override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = #colorLiteral(red: 0.7105011344, green: 0.9193516374, blue: 1, alpha: 1) + view.backgroundColor = backgroundColor } } diff --git a/ICViewPager/Scenes/Empty/EmptyViewController.xib b/ICViewPager/Scenes/Empty/EmptyViewController.xib new file mode 100644 index 0000000..58e2bb7 --- /dev/null +++ b/ICViewPager/Scenes/Empty/EmptyViewController.xib @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + +Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + +Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + +Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + From 934b241519be29197d4fe0b00551e72c50bb1df1 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sat, 19 May 2018 04:19:55 +0400 Subject: [PATCH 09/28] Implement initial tab bar This change implements the tab bar contents. Although, custom tab layout for paging and active tab indicator are yet to be implemented. --- ICViewPager.xcodeproj/project.pbxproj | 20 +++++ ...ExampleViewPagerControllerDataSource.swift | 10 ++- .../ICViewPager/Tab/DefaultTabItemView.swift | 44 +++++++++++ .../Tab/TabCollectionViewCell.swift | 26 +++++++ .../Tab/TabCollectionViewDataSource.swift | 75 +++++++++++++++++++ .../Tab/TabCollectionViewDelegate.swift | 32 ++++++++ .../Tab/TabCollectionViewLayout.swift | 19 +++++ ICViewPager/ICViewPager/Tab/TabItemView.swift | 14 ++++ .../ICViewPager/ViewPagerController.swift | 20 ++++- .../ViewPagerControllerDataSource.swift | 7 +- 10 files changed, 261 insertions(+), 6 deletions(-) create mode 100644 ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift create mode 100644 ICViewPager/ICViewPager/Tab/TabCollectionViewCell.swift create mode 100644 ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift create mode 100644 ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift create mode 100644 ICViewPager/ICViewPager/Tab/TabItemView.swift diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index 0b6b74f..43c2603 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -7,6 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 36B1150020AF91E200DA4621 /* TabCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */; }; + 36B1151320AF926700DA4621 /* TabItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151220AF926700DA4621 /* TabItemView.swift */; }; + 36B1151520AF92F900DA4621 /* TabCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */; }; + 36B1151720AF9FEB00DA4621 /* DefaultTabItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151620AF9FEB00DA4621 /* DefaultTabItemView.swift */; }; + 36B1151920AFA0CF00DA4621 /* TabCollectionViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151820AFA0CF00DA4621 /* TabCollectionViewDelegate.swift */; }; 36CB293120AF5A370054261E /* ViewPagerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB292F20AF5A370054261E /* ViewPagerController.swift */; }; 36CB293220AF5A370054261E /* ViewPagerController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 36CB293020AF5A370054261E /* ViewPagerController.xib */; }; 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */; }; @@ -26,6 +31,11 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewCell.swift; sourceTree = ""; }; + 36B1151220AF926700DA4621 /* TabItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItemView.swift; sourceTree = ""; }; + 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewDataSource.swift; sourceTree = ""; }; + 36B1151620AF9FEB00DA4621 /* DefaultTabItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTabItemView.swift; sourceTree = ""; }; + 36B1151820AFA0CF00DA4621 /* TabCollectionViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewDelegate.swift; sourceTree = ""; }; 36CB292F20AF5A370054261E /* ViewPagerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPagerController.swift; sourceTree = ""; }; 36CB293020AF5A370054261E /* ViewPagerController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ViewPagerController.xib; sourceTree = ""; }; 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewLayout.swift; sourceTree = ""; }; @@ -99,6 +109,11 @@ isa = PBXGroup; children = ( 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */, + 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */, + 36B1151220AF926700DA4621 /* TabItemView.swift */, + 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */, + 36B1151820AFA0CF00DA4621 /* TabCollectionViewDelegate.swift */, + 36B1151620AF9FEB00DA4621 /* DefaultTabItemView.swift */, ); path = Tab; sourceTree = ""; @@ -286,16 +301,21 @@ 36CB294920AF687C0054261E /* ContentCollectionViewDelegate.swift in Sources */, 36CB293620AF5A610054261E /* ContentCollectionViewLayout.swift in Sources */, 36CB294720AF628F0054261E /* ViewPagerControllerDataSource.swift in Sources */, + 36B1151720AF9FEB00DA4621 /* DefaultTabItemView.swift in Sources */, + 36B1151320AF926700DA4621 /* TabItemView.swift in Sources */, 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */, 36CB294020AF5F1D0054261E /* ContentCollectionViewCell.swift in Sources */, 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */, 36CB294E20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift in Sources */, 36F4A3C120AF4F8A000995B2 /* ViewPagerConfiguration.swift in Sources */, + 36B1150020AF91E200DA4621 /* TabCollectionViewCell.swift in Sources */, 36CB293120AF5A370054261E /* ViewPagerController.swift in Sources */, 36CB294520AF622F0054261E /* ContentCollectionViewDataSource.swift in Sources */, 36CB295020AF80270054261E /* UIViewController+Insets.swift in Sources */, 36CB294320AF60440054261E /* UIView+Embed.swift in Sources */, + 36B1151920AFA0CF00DA4621 /* TabCollectionViewDelegate.swift in Sources */, 36F4A3B220AF0685000995B2 /* ApplicationDelegate.swift in Sources */, + 36B1151520AF92F900DA4621 /* TabCollectionViewDataSource.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift index 626bed9..59d3378 100644 --- a/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift +++ b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift @@ -32,8 +32,14 @@ extension ExampleViewPagerControllerDataSource: ViewPagerControllerDataSource { } func viewPagerController(_ controller: ViewPagerController, - titleForTabAt index: Int) -> String { - return "Title #\(index)" + tabItemViewAt index: Int, + reusingTabItemView tabItemView: TabItemView?) -> TabItemView { + let title = "Title #\(index)" + if let view = tabItemView as? DefaultTabItemView { + view.title = title + return view + } + return DefaultTabItemView(title: title) } func numberOfViews(in controller: ViewPagerController) -> Int { diff --git a/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift b/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift new file mode 100644 index 0000000..a4d1689 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift @@ -0,0 +1,44 @@ +// +// DefaultTabItemView.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class DefaultTabItemView: TabItemView { + + override var intrinsicContentSize: CGSize { + return CGSize(width: 144.0, height: 44.0) + } + + private var label: UILabel + public var title: String { + didSet { + label.text = title + } + } + + init(title: String) { + label = UILabel() + self.title = title + super.init(frame: .zero) + setUpUI() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setUpUI() { + backgroundColor = .white + + label.text = title + label.textAlignment = .center + label.textColor = .black + label.translatesAutoresizingMaskIntoConstraints = false + embed(label) + } +} diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewCell.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewCell.swift new file mode 100644 index 0000000..28ef835 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewCell.swift @@ -0,0 +1,26 @@ +// +// TabCollectionViewCell.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class TabCollectionViewCell: UICollectionViewCell { + + weak var tabItemView: TabItemView? { + didSet { + guard oldValue !== tabItemView else { return } + oldValue?.removeFromSuperview() + guard let view = tabItemView else { return } + contentView.embed(view) + } + } + + override func prepareForReuse() { + super.prepareForReuse() + tabItemView?.prepareForReuse() + } +} diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift new file mode 100644 index 0000000..505abc6 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift @@ -0,0 +1,75 @@ +// +// TabCollectionViewDataSource.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class TabCollectionViewDataSource: NSObject { + + private struct Constants { + static let cellIdentifier = "\(TabCollectionViewCell.self)" + } + + private unowned var viewPagerController: ViewPagerController + private unowned var collectionView: UICollectionView + weak var dataSource: ViewPagerControllerDataSource? + + // MARK: Init + + init(viewPagerController: ViewPagerController, collectionView: UICollectionView) { + self.viewPagerController = viewPagerController + self.collectionView = collectionView + super.init() + registerTabCell() + } +} + +// MARK: Private functions + +private extension TabCollectionViewDataSource { + + func registerTabCell() { + collectionView.register(TabCollectionViewCell.self, + forCellWithReuseIdentifier: Constants.cellIdentifier) + } + + func tabItemView(at index: Int, reuseTabItemView view: TabItemView?) -> TabItemView { + + guard let dataSource = dataSource else { + fatalError("ViewPagerControllerDataSource is not provided!") + } + + return dataSource.viewPagerController(viewPagerController, tabItemViewAt: index, reusingTabItemView: view) + } +} + +// MARK: UICollectionViewDataSource + +extension TabCollectionViewDataSource: UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Constants.cellIdentifier, + for: indexPath) as! TabCollectionViewCell + cell.tabItemView = tabItemView(at: indexPath.item, reuseTabItemView: cell.tabItemView) + return cell + } + + func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + func collectionView(_ collectionView: UICollectionView, + numberOfItemsInSection section: Int) -> Int { + + guard let dataSource = dataSource else { + fatalError("ViewPagerControllerDataSource is not provided!") + } + + return dataSource.numberOfViews(in: viewPagerController) + } +} diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift new file mode 100644 index 0000000..889ba13 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift @@ -0,0 +1,32 @@ +// +// TabCollectionViewDelegate.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class TabCollectionViewDelegate: NSObject { + + private unowned var viewPagerController: ViewPagerController + + // MARK: Init + + init(viewPagerController: ViewPagerController) { + self.viewPagerController = viewPagerController + super.init() + } +} + +// MARK: UICollectionViewDelegateFlowLayout + +extension TabCollectionViewDelegate: UICollectionViewDelegateFlowLayout { + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: 144.0, height: 44.0) + } +} diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift index 4afa06a..9784f65 100644 --- a/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift @@ -10,4 +10,23 @@ import UIKit final class TabCollectionViewLayout: UICollectionViewFlowLayout { + override init() { + super.init() + setUpLayout() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setUpLayout() + } +} + +private extension TabCollectionViewLayout { + + func setUpLayout() { + scrollDirection = .horizontal + sectionInset = .zero + minimumInteritemSpacing = 0.0 + minimumLineSpacing = 0.0 + } } diff --git a/ICViewPager/ICViewPager/Tab/TabItemView.swift b/ICViewPager/ICViewPager/Tab/TabItemView.swift new file mode 100644 index 0000000..f3832f3 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabItemView.swift @@ -0,0 +1,14 @@ +// +// TabItemView.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +open class TabItemView: UIView { + + open func prepareForReuse() {} +} diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index 4151de9..cf323eb 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -19,6 +19,8 @@ final public class ViewPagerController: UIViewController { private var contentCollectionViewDataSource: ContentCollectionViewDataSource! private var contentCollectionViewDelegate: ContentCollectionViewDelegate! + private var tabCollectionViewDataSource: TabCollectionViewDataSource! + private var tabCollectionViewDelegate: TabCollectionViewDelegate! public weak var dataSource: ViewPagerControllerDataSource? public var configuration: ViewPagerConfiguration @@ -46,6 +48,13 @@ final public class ViewPagerController: UIViewController { private extension ViewPagerController { func setUpUI() { + adjustInsets() + setUpContentCollectionView(contentCollectionView) + setUpTabCollectionView(tabCollectionView) + applyConfiguration(configuration) + } + + func adjustInsets() { if #available(iOS 11.0, *) { additionalSafeAreaInsets = UIEdgeInsetsMake(configuration.tabHeight, 0.0, 0.0, 0.0) contentCollectionView.contentInsetAdjustmentBehavior = .never @@ -56,8 +65,6 @@ private extension ViewPagerController { topLayoutGuide.bottomAnchor.constraint(equalTo: tabContainerStackView.topAnchor).isActive = true automaticallyAdjustsScrollViewInsets = false } - setUpContentCollectionView(contentCollectionView) - applyConfiguration(configuration) } func setUpContentCollectionView(_ collectionView: UICollectionView) { @@ -69,6 +76,15 @@ private extension ViewPagerController { collectionView.delegate = contentCollectionViewDelegate } + func setUpTabCollectionView(_ collectionView: UICollectionView) { + tabCollectionViewDataSource = TabCollectionViewDataSource(viewPagerController: self, + collectionView: collectionView) + tabCollectionViewDataSource.dataSource = dataSource + tabCollectionViewDelegate = TabCollectionViewDelegate(viewPagerController: self) + collectionView.dataSource = tabCollectionViewDataSource + collectionView.delegate = tabCollectionViewDelegate + } + func applyConfiguration(_ configuration: ViewPagerConfiguration) { tabCollectionViewHeightConstraint.constant = configuration.tabHeight } diff --git a/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift b/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift index af0d7ac..0bc7720 100644 --- a/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift +++ b/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift @@ -10,9 +10,12 @@ import UIKit public protocol ViewPagerControllerDataSource: class { - func viewPagerController(_ controller: ViewPagerController, viewControllerAt index: Int) -> UIViewController + func viewPagerController(_ controller: ViewPagerController, + viewControllerAt index: Int) -> UIViewController - func viewPagerController(_ controller: ViewPagerController, titleForTabAt index: Int) -> String + func viewPagerController(_ controller: ViewPagerController, + tabItemViewAt index: Int, + reusingTabItemView tabItemView: TabItemView?) -> TabItemView func numberOfViews(in controller: ViewPagerController) -> Int } From 680287ab47f0b076fd156deca9d625ccbed286b5 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sat, 19 May 2018 04:35:21 +0400 Subject: [PATCH 10/28] Fix for view controller embedding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I assumed keeping a weak reference to the content view controller would be fine, but turns out collection view might not call data source function cellForItemAt:IndexPath to let me configure the cell again with the view controller, because it’s already cached. --- .../ICViewPager/Content/ContentCollectionViewCell.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift index 1b933f7..6df4551 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift @@ -10,7 +10,7 @@ import UIKit final class ContentCollectionViewCell: UICollectionViewCell { - private weak var contentViewController: UIViewController? + private var contentViewController: UIViewController? // MARK: Public functions @@ -34,6 +34,5 @@ final class ContentCollectionViewCell: UICollectionViewCell { contentViewController?.willMove(toParentViewController: nil) contentViewController?.view.removeFromSuperview() contentViewController?.removeFromParentViewController() - contentViewController = nil } } From 4be4ad7c0cf2804fd1d0e3e0f957b31c728e2a8d Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sat, 19 May 2018 21:06:41 +0400 Subject: [PATCH 11/28] Implement paging layout --- .../Content/ContentCollectionViewLayout.swift | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift index 44b31e9..c75dc69 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift @@ -12,21 +12,42 @@ final class ContentCollectionViewLayout: UICollectionViewFlowLayout { override init() { super.init() - setUpLayout() + scrollDirection = .horizontal } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - setUpLayout() + scrollDirection = .horizontal } -} - -private extension ContentCollectionViewLayout { - func setUpLayout() { - scrollDirection = .horizontal - sectionInset = .zero - minimumInteritemSpacing = 0.0 - minimumLineSpacing = 0.0 + override func prepare() { + super.prepare() + guard let collectionView = collectionView else { return } + collectionView.decelerationRate = UIScrollViewDecelerationRateFast + collectionView.isPagingEnabled = false + } + + override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { + guard let collectionView = collectionView else { return proposedContentOffset } + let proposedContentOffsetCenterX = proposedContentOffset.x + collectionView.bounds.width / 2.0 + let proposedRect = CGRect(origin: CGPoint(x: proposedContentOffset.x, y: 0.0), + size: collectionView.bounds.size) + let layoutAttributes = layoutAttributesForElements(in: proposedRect)?.sorted(by: { + // Returning `true` means $0, $1 order, whereas `false` means $1, $0 order. + let attr1Diff = fabs($0.center.x - proposedContentOffsetCenterX) + let attr2Diff = fabs($1.center.x - proposedContentOffsetCenterX) + return ((attr1Diff == attr2Diff && $0.indexPath.item == 0) || attr1Diff < attr2Diff) + }) + guard let candidateAttributes = layoutAttributes?.first else { return proposedContentOffset } + // Note: There's a rounding problem on iPhone+ models for x values. + // It's advised to use NSInteger and check if it is smaller than zero and if so set it to zero. + var x = candidateAttributes.center.x - collectionView.bounds.width / 2.0 + if x < 0 { x = 0 } + return CGPoint(x: x, y: proposedContentOffset.y) + } + + override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, + withScrollingVelocity velocity: CGPoint) -> CGPoint { + return targetContentOffset(forProposedContentOffset: proposedContentOffset) } } From 757dcc346f8392de71319b3a87986f365a38208f Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sat, 19 May 2018 21:06:56 +0400 Subject: [PATCH 12/28] Set background color for ViewPagerController --- ICViewPager/ICViewPager/ViewPagerController.swift | 1 + ICViewPager/ICViewPager/ViewPagerController.xib | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index cf323eb..b19afa3 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -48,6 +48,7 @@ final public class ViewPagerController: UIViewController { private extension ViewPagerController { func setUpUI() { + view.backgroundColor = .black adjustInsets() setUpContentCollectionView(contentCollectionView) setUpTabCollectionView(tabCollectionView) diff --git a/ICViewPager/ICViewPager/ViewPagerController.xib b/ICViewPager/ICViewPager/ViewPagerController.xib index b9726be..ee468d5 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.xib +++ b/ICViewPager/ICViewPager/ViewPagerController.xib @@ -28,7 +28,7 @@ - + @@ -41,7 +41,7 @@ - + From bf9cc54e06af74b85c83758b2356046f2e5c8a03 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sun, 20 May 2018 00:08:14 +0400 Subject: [PATCH 13/28] Implement ScrollController This change introduces ScrollController that will be responsible for communication between content and tab collection views. Also with this change we already have content selection over tab collection view, but we still have some work to do for tab and content tracking. --- ICViewPager.xcodeproj/project.pbxproj | 4 ++ .../ContentCollectionViewDelegate.swift | 30 ++++++++++- .../ICViewPager/ScrollController.swift | 54 +++++++++++++++++++ .../Tab/TabCollectionViewDelegate.swift | 16 ++++++ .../ICViewPager/ViewPagerController.swift | 13 ++++- 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 ICViewPager/ICViewPager/ScrollController.swift diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index 43c2603..09f4123 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 36B1151520AF92F900DA4621 /* TabCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */; }; 36B1151720AF9FEB00DA4621 /* DefaultTabItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151620AF9FEB00DA4621 /* DefaultTabItemView.swift */; }; 36B1151920AFA0CF00DA4621 /* TabCollectionViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151820AFA0CF00DA4621 /* TabCollectionViewDelegate.swift */; }; + 36B1152920B0920C00DA4621 /* ScrollController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1152820B0920C00DA4621 /* ScrollController.swift */; }; 36CB293120AF5A370054261E /* ViewPagerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB292F20AF5A370054261E /* ViewPagerController.swift */; }; 36CB293220AF5A370054261E /* ViewPagerController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 36CB293020AF5A370054261E /* ViewPagerController.xib */; }; 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */; }; @@ -36,6 +37,7 @@ 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewDataSource.swift; sourceTree = ""; }; 36B1151620AF9FEB00DA4621 /* DefaultTabItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTabItemView.swift; sourceTree = ""; }; 36B1151820AFA0CF00DA4621 /* TabCollectionViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewDelegate.swift; sourceTree = ""; }; + 36B1152820B0920C00DA4621 /* ScrollController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollController.swift; sourceTree = ""; }; 36CB292F20AF5A370054261E /* ViewPagerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPagerController.swift; sourceTree = ""; }; 36CB293020AF5A370054261E /* ViewPagerController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ViewPagerController.xib; sourceTree = ""; }; 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewLayout.swift; sourceTree = ""; }; @@ -172,6 +174,7 @@ 36CB293020AF5A370054261E /* ViewPagerController.xib */, 36CB294620AF628F0054261E /* ViewPagerControllerDataSource.swift */, 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */, + 36B1152820B0920C00DA4621 /* ScrollController.swift */, 36CB295220AF82590054261E /* Tab */, 36CB295120AF824F0054261E /* Content */, 36CB294120AF60370054261E /* Extensions */, @@ -305,6 +308,7 @@ 36B1151320AF926700DA4621 /* TabItemView.swift in Sources */, 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */, 36CB294020AF5F1D0054261E /* ContentCollectionViewCell.swift in Sources */, + 36B1152920B0920C00DA4621 /* ScrollController.swift in Sources */, 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */, 36CB294E20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift in Sources */, 36F4A3C120AF4F8A000995B2 /* ViewPagerConfiguration.swift in Sources */, diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift index cd12963..6c766f5 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift @@ -8,14 +8,24 @@ import UIKit +protocol ContentCollectionViewDelegateProtocol: class { + + func contentCollectionView(_ collectionView: UICollectionView, didScroll offset: CGPoint) + func contentCollectionViewWillBeginDragging(_ collectionView: UICollectionView) + func contentCollectionViewDidEndDragging(_ collectionView: UICollectionView) +} + final class ContentCollectionViewDelegate: NSObject { private unowned var viewPagerController: ViewPagerController + private unowned var collectionView: UICollectionView + weak var delegate: ContentCollectionViewDelegateProtocol? // MARK: Init - init(viewPagerController: ViewPagerController) { + init(viewPagerController: ViewPagerController, collectionView: UICollectionView) { self.viewPagerController = viewPagerController + self.collectionView = collectionView super.init() } } @@ -55,3 +65,21 @@ extension ContentCollectionViewDelegate: UICollectionViewDelegateFlowLayout { return collectionView.bounds.size } } + +// MARK: UIScrollViewDelegate + +extension ContentCollectionViewDelegate: UIScrollViewDelegate { + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + delegate?.contentCollectionView(collectionView, didScroll: scrollView.contentOffset) + } + + func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { + delegate?.contentCollectionViewWillBeginDragging(collectionView) + } + + func scrollViewDidEndDragging(_ scrollView: UIScrollView, + willDecelerate decelerate: Bool) { + delegate?.contentCollectionViewDidEndDragging(collectionView) + } +} diff --git a/ICViewPager/ICViewPager/ScrollController.swift b/ICViewPager/ICViewPager/ScrollController.swift new file mode 100644 index 0000000..a92a916 --- /dev/null +++ b/ICViewPager/ICViewPager/ScrollController.swift @@ -0,0 +1,54 @@ +// +// ScrollController.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class ScrollController { + + private unowned var viewPagerController: ViewPagerController + private unowned var contentCollectionView: UICollectionView + private unowned var tabCollectionView: UICollectionView + + // MARK: Init + + init(viewPagerController: ViewPagerController, + contentCollectionView: UICollectionView, + tabCollectionView: UICollectionView) { + self.viewPagerController = viewPagerController + self.contentCollectionView = contentCollectionView + self.tabCollectionView = tabCollectionView + } +} + +extension ScrollController: ContentCollectionViewDelegateProtocol { + + func contentCollectionView(_ collectionView: UICollectionView, didScroll offset: CGPoint) { + + } + + func contentCollectionViewWillBeginDragging(_ collectionView: UICollectionView) { + tabCollectionView.isUserInteractionEnabled = false + } + + func contentCollectionViewDidEndDragging(_ collectionView: UICollectionView) { + tabCollectionView.isUserInteractionEnabled = true + } +} + +extension ScrollController: TabCollectionViewDelegateProtocol { + + func tabCollectionView(_ collectionView: UICollectionView, didSelectItemAt index: Int) { + let indexPath = IndexPath(item: index, section: 0) + contentCollectionView.scrollToItem(at: indexPath, + at: .centeredHorizontally, + animated: true) + collectionView.scrollToItem(at: indexPath, + at: .left, + animated: true) + } +} diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift index 889ba13..487429b 100644 --- a/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift @@ -8,9 +8,15 @@ import UIKit +protocol TabCollectionViewDelegateProtocol: class { + + func tabCollectionView(_ collectionView: UICollectionView, didSelectItemAt index: Int) +} + final class TabCollectionViewDelegate: NSObject { private unowned var viewPagerController: ViewPagerController + weak var delegate: TabCollectionViewDelegateProtocol? // MARK: Init @@ -20,6 +26,16 @@ final class TabCollectionViewDelegate: NSObject { } } +// MARK: UICollectionViewDelegate + +extension TabCollectionViewDelegate: UICollectionViewDelegate { + + func collectionView(_ collectionView: UICollectionView, + didSelectItemAt indexPath: IndexPath) { + delegate?.tabCollectionView(collectionView, didSelectItemAt: indexPath.item) + } +} + // MARK: UICollectionViewDelegateFlowLayout extension TabCollectionViewDelegate: UICollectionViewDelegateFlowLayout { diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index b19afa3..3149ba0 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -21,6 +21,7 @@ final public class ViewPagerController: UIViewController { private var contentCollectionViewDelegate: ContentCollectionViewDelegate! private var tabCollectionViewDataSource: TabCollectionViewDataSource! private var tabCollectionViewDelegate: TabCollectionViewDelegate! + private var scrollController: ScrollController! public weak var dataSource: ViewPagerControllerDataSource? public var configuration: ViewPagerConfiguration @@ -41,6 +42,7 @@ final public class ViewPagerController: UIViewController { public override func viewDidLoad() { super.viewDidLoad() + setUpScrollController() setUpUI() } } @@ -72,7 +74,9 @@ private extension ViewPagerController { contentCollectionViewDataSource = ContentCollectionViewDataSource(viewPagerController: self, collectionView: collectionView) contentCollectionViewDataSource.dataSource = dataSource - contentCollectionViewDelegate = ContentCollectionViewDelegate(viewPagerController: self) + contentCollectionViewDelegate = ContentCollectionViewDelegate(viewPagerController: self, + collectionView: collectionView) + contentCollectionViewDelegate.delegate = scrollController collectionView.dataSource = contentCollectionViewDataSource collectionView.delegate = contentCollectionViewDelegate } @@ -82,6 +86,7 @@ private extension ViewPagerController { collectionView: collectionView) tabCollectionViewDataSource.dataSource = dataSource tabCollectionViewDelegate = TabCollectionViewDelegate(viewPagerController: self) + tabCollectionViewDelegate.delegate = scrollController collectionView.dataSource = tabCollectionViewDataSource collectionView.delegate = tabCollectionViewDelegate } @@ -89,4 +94,10 @@ private extension ViewPagerController { func applyConfiguration(_ configuration: ViewPagerConfiguration) { tabCollectionViewHeightConstraint.constant = configuration.tabHeight } + + func setUpScrollController() { + scrollController = ScrollController(viewPagerController: self, + contentCollectionView: contentCollectionView, + tabCollectionView: tabCollectionView) + } } From dc4fd2d482cdfe88247db86130db5f84985c97de Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sun, 20 May 2018 13:11:04 +0400 Subject: [PATCH 14/28] Add numbers to example scenes --- ...ExampleViewPagerControllerDataSource.swift | 20 ++++++------- .../Scenes/Empty/EmptyViewController.swift | 7 ++++- .../Scenes/Empty/EmptyViewController.xib | 29 ++++++++++++++++--- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift index 59d3378..b9efb09 100644 --- a/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift +++ b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift @@ -11,16 +11,16 @@ import UIKit final class ExampleViewPagerControllerDataSource { private var viewControllers: [UIViewController] = [ - EmptyViewController(backgroundColor: #colorLiteral(red: 0.1019607857, green: 0.2784313858, blue: 0.400000006, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.7254902124, green: 0.4784313738, blue: 0.09803921729, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.3098039329, green: 0.2039215714, blue: 0.03921568766, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1)), - EmptyViewController(backgroundColor: #colorLiteral(red: 0.521568656, green: 0.1098039225, blue: 0.05098039284, alpha: 1)) + EmptyViewController(backgroundColor: #colorLiteral(red: 0.1019607857, green: 0.2784313858, blue: 0.400000006, alpha: 1), number: 0), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.7254902124, green: 0.4784313738, blue: 0.09803921729, alpha: 1), number: 1), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1), number: 2), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1), number: 3), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.3098039329, green: 0.2039215714, blue: 0.03921568766, alpha: 1), number: 4), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1), number: 5), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1), number: 6), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1), number: 7), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1), number: 8), + EmptyViewController(backgroundColor: #colorLiteral(red: 0.521568656, green: 0.1098039225, blue: 0.05098039284, alpha: 1), number: 9) ] } diff --git a/ICViewPager/Scenes/Empty/EmptyViewController.swift b/ICViewPager/Scenes/Empty/EmptyViewController.swift index 6099937..4d3e11a 100644 --- a/ICViewPager/Scenes/Empty/EmptyViewController.swift +++ b/ICViewPager/Scenes/Empty/EmptyViewController.swift @@ -11,16 +11,20 @@ import UIKit class EmptyViewController: UIViewController { var backgroundColor: UIColor + var number: Int + @IBOutlet weak var numberLabel: UILabel! // MARK: Init - init(backgroundColor: UIColor) { + init(backgroundColor: UIColor, number: Int) { self.backgroundColor = backgroundColor + self.number = number super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { backgroundColor = .blue + number = 0 super.init(coder: aDecoder) } @@ -29,5 +33,6 @@ class EmptyViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = backgroundColor + numberLabel.text = "\(number)" } } diff --git a/ICViewPager/Scenes/Empty/EmptyViewController.xib b/ICViewPager/Scenes/Empty/EmptyViewController.xib index 58e2bb7..8e1d47b 100644 --- a/ICViewPager/Scenes/Empty/EmptyViewController.xib +++ b/ICViewPager/Scenes/Empty/EmptyViewController.xib @@ -12,6 +12,7 @@ + @@ -20,12 +21,12 @@ - + - Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. @@ -33,14 +34,14 @@ Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. - + - Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. @@ -49,11 +50,31 @@ Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed + + + + + + + + + + + + + + + From 9d5fb4946b49405f390bc446b6ee3daa06129825 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sun, 20 May 2018 13:11:35 +0400 Subject: [PATCH 15/28] Disable bouncing for collection views --- ICViewPager/ICViewPager/ViewPagerController.xib | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ICViewPager/ICViewPager/ViewPagerController.xib b/ICViewPager/ICViewPager/ViewPagerController.xib index ee468d5..4638bf6 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.xib +++ b/ICViewPager/ICViewPager/ViewPagerController.xib @@ -26,7 +26,7 @@ - + @@ -39,7 +39,7 @@ - + From f738952bee8b6422909b5b0feea873e9f7b472fd Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sun, 20 May 2018 13:13:25 +0400 Subject: [PATCH 16/28] Implement scroll on tab bar when content scrolls --- .../ContentCollectionViewDelegate.swift | 25 +++++++++---------- .../Content/ContentCollectionViewLayout.swift | 1 + .../ICViewPager/ScrollController.swift | 10 +++++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift index 6c766f5..b96dbd5 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift @@ -10,9 +10,9 @@ import UIKit protocol ContentCollectionViewDelegateProtocol: class { - func contentCollectionView(_ collectionView: UICollectionView, didScroll offset: CGPoint) func contentCollectionViewWillBeginDragging(_ collectionView: UICollectionView) func contentCollectionViewDidEndDragging(_ collectionView: UICollectionView) + func contentCollectionView(_ collectionView: UICollectionView, didScrollToPageAt index: Int) } final class ContentCollectionViewDelegate: NSObject { @@ -21,6 +21,8 @@ final class ContentCollectionViewDelegate: NSObject { private unowned var collectionView: UICollectionView weak var delegate: ContentCollectionViewDelegateProtocol? + public private(set) var currentPage: Int = 0 + // MARK: Init init(viewPagerController: ViewPagerController, collectionView: UICollectionView) { @@ -55,23 +57,12 @@ extension ContentCollectionViewDelegate: UICollectionViewDelegate { } } -// MARK: UICollectionViewDelegateFlowLayout - -extension ContentCollectionViewDelegate: UICollectionViewDelegateFlowLayout { - - public func collectionView(_ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAt indexPath: IndexPath) -> CGSize { - return collectionView.bounds.size - } -} - // MARK: UIScrollViewDelegate extension ContentCollectionViewDelegate: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { - delegate?.contentCollectionView(collectionView, didScroll: scrollView.contentOffset) + } func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { @@ -82,4 +73,12 @@ extension ContentCollectionViewDelegate: UIScrollViewDelegate { willDecelerate decelerate: Bool) { delegate?.contentCollectionViewDidEndDragging(collectionView) } + + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + guard let layout = collectionView.collectionViewLayout as? ContentCollectionViewLayout else { return } + let width = layout.itemSize.width + let spacing = layout.minimumInteritemSpacing + currentPage = Int(floor((scrollView.contentOffset.x + spacing) / (width + spacing))) + delegate?.contentCollectionView(collectionView, didScrollToPageAt: currentPage) + } } diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift index c75dc69..f83e3b0 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift @@ -23,6 +23,7 @@ final class ContentCollectionViewLayout: UICollectionViewFlowLayout { override func prepare() { super.prepare() guard let collectionView = collectionView else { return } + itemSize = collectionView.bounds.size collectionView.decelerationRate = UIScrollViewDecelerationRateFast collectionView.isPagingEnabled = false } diff --git a/ICViewPager/ICViewPager/ScrollController.swift b/ICViewPager/ICViewPager/ScrollController.swift index a92a916..119c6f1 100644 --- a/ICViewPager/ICViewPager/ScrollController.swift +++ b/ICViewPager/ICViewPager/ScrollController.swift @@ -27,10 +27,6 @@ final class ScrollController { extension ScrollController: ContentCollectionViewDelegateProtocol { - func contentCollectionView(_ collectionView: UICollectionView, didScroll offset: CGPoint) { - - } - func contentCollectionViewWillBeginDragging(_ collectionView: UICollectionView) { tabCollectionView.isUserInteractionEnabled = false } @@ -38,6 +34,12 @@ extension ScrollController: ContentCollectionViewDelegateProtocol { func contentCollectionViewDidEndDragging(_ collectionView: UICollectionView) { tabCollectionView.isUserInteractionEnabled = true } + + func contentCollectionView(_ collectionView: UICollectionView, didScrollToPageAt index: Int) { + tabCollectionView.scrollToItem(at: IndexPath(item: index, section: 0), + at: .left, + animated: true) + } } extension ScrollController: TabCollectionViewDelegateProtocol { From f7b6d00b5922c1a438dc60d576b819be1a49ed61 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sun, 20 May 2018 13:14:15 +0400 Subject: [PATCH 17/28] Fine tune scrolling on content collection view --- .../ICViewPager/Content/ContentCollectionViewLayout.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift index f83e3b0..3a7c3f5 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift @@ -24,7 +24,8 @@ final class ContentCollectionViewLayout: UICollectionViewFlowLayout { super.prepare() guard let collectionView = collectionView else { return } itemSize = collectionView.bounds.size - collectionView.decelerationRate = UIScrollViewDecelerationRateFast + let sweetSpot = (UIScrollViewDecelerationRateFast * 0.64 + UIScrollViewDecelerationRateNormal * 0.36) + collectionView.decelerationRate = sweetSpot collectionView.isPagingEnabled = false } From fd983f9afccad6c638e18ec9c3aeb2e349fab231 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Mon, 21 May 2018 12:57:22 +0400 Subject: [PATCH 18/28] Implement tab indicator --- ICViewPager.xcodeproj/project.pbxproj | 8 ++ .../ContentCollectionViewDelegate.swift | 26 ++++- .../Content/ContentCollectionViewLayout.swift | 4 + .../ICViewPager/ScrollController.swift | 7 ++ ICViewPager/ICViewPager/ScrollDirection.swift | 15 +++ .../Tab/ActiveTabIndicatorView.swift | 30 +++++ .../Tab/TabCollectionViewLayout.swift | 103 +++++++++++++++++- 7 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 ICViewPager/ICViewPager/ScrollDirection.swift create mode 100644 ICViewPager/ICViewPager/Tab/ActiveTabIndicatorView.swift diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index 09f4123..c8ef6a2 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 365567DA20B0BD7100D5C00F /* ActiveTabIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 365567D920B0BD7100D5C00F /* ActiveTabIndicatorView.swift */; }; 36B1150020AF91E200DA4621 /* TabCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */; }; 36B1151320AF926700DA4621 /* TabItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151220AF926700DA4621 /* TabItemView.swift */; }; 36B1151520AF92F900DA4621 /* TabCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */; }; @@ -25,6 +26,7 @@ 36CB294B20AF6AC20054261E /* EmptyViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 36CB294A20AF6AC20054261E /* EmptyViewController.xib */; }; 36CB294E20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB294D20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift */; }; 36CB295020AF80270054261E /* UIViewController+Insets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CB294F20AF80270054261E /* UIViewController+Insets.swift */; }; + 36E1376E20B2245D0021F3EF /* ScrollDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E1376D20B2245D0021F3EF /* ScrollDirection.swift */; }; 36F4A3B220AF0685000995B2 /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */; }; 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */; }; 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */; }; @@ -32,6 +34,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 365567D920B0BD7100D5C00F /* ActiveTabIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveTabIndicatorView.swift; sourceTree = ""; }; 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewCell.swift; sourceTree = ""; }; 36B1151220AF926700DA4621 /* TabItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItemView.swift; sourceTree = ""; }; 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewDataSource.swift; sourceTree = ""; }; @@ -50,6 +53,7 @@ 36CB294A20AF6AC20054261E /* EmptyViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EmptyViewController.xib; sourceTree = ""; }; 36CB294D20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleViewPagerControllerDataSource.swift; sourceTree = ""; }; 36CB294F20AF80270054261E /* UIViewController+Insets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Insets.swift"; sourceTree = ""; }; + 36E1376D20B2245D0021F3EF /* ScrollDirection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollDirection.swift; sourceTree = ""; }; 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = ""; }; 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyViewController.swift; sourceTree = ""; }; 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; @@ -115,6 +119,7 @@ 36B1151220AF926700DA4621 /* TabItemView.swift */, 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */, 36B1151820AFA0CF00DA4621 /* TabCollectionViewDelegate.swift */, + 365567D920B0BD7100D5C00F /* ActiveTabIndicatorView.swift */, 36B1151620AF9FEB00DA4621 /* DefaultTabItemView.swift */, ); path = Tab; @@ -175,6 +180,7 @@ 36CB294620AF628F0054261E /* ViewPagerControllerDataSource.swift */, 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */, 36B1152820B0920C00DA4621 /* ScrollController.swift */, + 36E1376D20B2245D0021F3EF /* ScrollDirection.swift */, 36CB295220AF82590054261E /* Tab */, 36CB295120AF824F0054261E /* Content */, 36CB294120AF60370054261E /* Extensions */, @@ -307,10 +313,12 @@ 36B1151720AF9FEB00DA4621 /* DefaultTabItemView.swift in Sources */, 36B1151320AF926700DA4621 /* TabItemView.swift in Sources */, 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */, + 365567DA20B0BD7100D5C00F /* ActiveTabIndicatorView.swift in Sources */, 36CB294020AF5F1D0054261E /* ContentCollectionViewCell.swift in Sources */, 36B1152920B0920C00DA4621 /* ScrollController.swift in Sources */, 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */, 36CB294E20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift in Sources */, + 36E1376E20B2245D0021F3EF /* ScrollDirection.swift in Sources */, 36F4A3C120AF4F8A000995B2 /* ViewPagerConfiguration.swift in Sources */, 36B1150020AF91E200DA4621 /* TabCollectionViewCell.swift in Sources */, 36CB293120AF5A370054261E /* ViewPagerController.swift in Sources */, diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift index b96dbd5..aff6c23 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift @@ -10,6 +10,7 @@ import UIKit protocol ContentCollectionViewDelegateProtocol: class { + func contentCollectionViewDidScroll(_ collectionView: UICollectionView, direction: ScrollDirection) func contentCollectionViewWillBeginDragging(_ collectionView: UICollectionView) func contentCollectionViewDidEndDragging(_ collectionView: UICollectionView) func contentCollectionView(_ collectionView: UICollectionView, didScrollToPageAt index: Int) @@ -22,6 +23,8 @@ final class ContentCollectionViewDelegate: NSObject { weak var delegate: ContentCollectionViewDelegateProtocol? public private(set) var currentPage: Int = 0 + private var contentOffsetBeforeDragging: CGPoint = .zero + private var shouldResetContentOffsetBeforeDragging: Bool = true // MARK: Init @@ -63,9 +66,28 @@ extension ContentCollectionViewDelegate: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { + guard let layout = collectionView.collectionViewLayout as? ContentCollectionViewLayout else { return } + + let diff = CGFloat(abs(contentOffsetBeforeDragging.x - scrollView.contentOffset.x)) + let percentage = diff / (scrollView.bounds.width + layout.minimumLineSpacing) + + let direction: ScrollDirection + if scrollView.contentOffset.x < contentOffsetBeforeDragging.x { + direction = .left(percentage: percentage) + } else if scrollView.contentOffset.x > contentOffsetBeforeDragging.x { + direction = .right(percentage: percentage) + } else { + direction = .stationary + } + + delegate?.contentCollectionViewDidScroll(collectionView, direction: direction) } func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { + if shouldResetContentOffsetBeforeDragging { + contentOffsetBeforeDragging = scrollView.contentOffset + shouldResetContentOffsetBeforeDragging = false + } delegate?.contentCollectionViewWillBeginDragging(collectionView) } @@ -77,8 +99,10 @@ extension ContentCollectionViewDelegate: UIScrollViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { guard let layout = collectionView.collectionViewLayout as? ContentCollectionViewLayout else { return } let width = layout.itemSize.width - let spacing = layout.minimumInteritemSpacing + let spacing = layout.minimumLineSpacing currentPage = Int(floor((scrollView.contentOffset.x + spacing) / (width + spacing))) delegate?.contentCollectionView(collectionView, didScrollToPageAt: currentPage) + + shouldResetContentOffsetBeforeDragging = true } } diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift index 3a7c3f5..19c60b1 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift @@ -23,7 +23,11 @@ final class ContentCollectionViewLayout: UICollectionViewFlowLayout { override func prepare() { super.prepare() guard let collectionView = collectionView else { return } + itemSize = collectionView.bounds.size + minimumLineSpacing = 10.0 + minimumInteritemSpacing = 0.0 + let sweetSpot = (UIScrollViewDecelerationRateFast * 0.64 + UIScrollViewDecelerationRateNormal * 0.36) collectionView.decelerationRate = sweetSpot collectionView.isPagingEnabled = false diff --git a/ICViewPager/ICViewPager/ScrollController.swift b/ICViewPager/ICViewPager/ScrollController.swift index 119c6f1..247a546 100644 --- a/ICViewPager/ICViewPager/ScrollController.swift +++ b/ICViewPager/ICViewPager/ScrollController.swift @@ -13,6 +13,7 @@ final class ScrollController { private unowned var viewPagerController: ViewPagerController private unowned var contentCollectionView: UICollectionView private unowned var tabCollectionView: UICollectionView + private unowned var tabCollectionViewLayout: TabCollectionViewLayout // MARK: Init @@ -22,11 +23,16 @@ final class ScrollController { self.viewPagerController = viewPagerController self.contentCollectionView = contentCollectionView self.tabCollectionView = tabCollectionView + self.tabCollectionViewLayout = tabCollectionView.collectionViewLayout as! TabCollectionViewLayout } } extension ScrollController: ContentCollectionViewDelegateProtocol { + func contentCollectionViewDidScroll(_ collectionView: UICollectionView, direction: ScrollDirection) { + tabCollectionViewLayout.updateIndicator(direction: direction) + } + func contentCollectionViewWillBeginDragging(_ collectionView: UICollectionView) { tabCollectionView.isUserInteractionEnabled = false } @@ -36,6 +42,7 @@ extension ScrollController: ContentCollectionViewDelegateProtocol { } func contentCollectionView(_ collectionView: UICollectionView, didScrollToPageAt index: Int) { + tabCollectionViewLayout.currentPage = index tabCollectionView.scrollToItem(at: IndexPath(item: index, section: 0), at: .left, animated: true) diff --git a/ICViewPager/ICViewPager/ScrollDirection.swift b/ICViewPager/ICViewPager/ScrollDirection.swift new file mode 100644 index 0000000..91a3073 --- /dev/null +++ b/ICViewPager/ICViewPager/ScrollDirection.swift @@ -0,0 +1,15 @@ +// +// ScrollDirection.swift +// ICViewPager +// +// Created by Ilter Cengiz on 21/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +enum ScrollDirection { + case left(percentage: CGFloat) + case right(percentage: CGFloat) + case stationary +} diff --git a/ICViewPager/ICViewPager/Tab/ActiveTabIndicatorView.swift b/ICViewPager/ICViewPager/Tab/ActiveTabIndicatorView.swift new file mode 100644 index 0000000..1391071 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/ActiveTabIndicatorView.swift @@ -0,0 +1,30 @@ +// +// ActiveTabIndicatorView.swift +// ICViewPager +// +// Created by Ilter Cengiz on 20/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class ActiveTabIndicatorView: UICollectionReusableView { + + class var kind: String { + return "\(ActiveTabIndicatorView.self)" + } + + override init(frame: CGRect) { + super.init(frame: frame) + setUpUI() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setUpUI() + } + + private func setUpUI() { + backgroundColor = .red + } +} diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift index 9784f65..d7e8a2b 100644 --- a/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift @@ -10,14 +10,92 @@ import UIKit final class TabCollectionViewLayout: UICollectionViewFlowLayout { + private enum Constants { + static let indicatorIndexPath: IndexPath = IndexPath(item: 0, section: 0) + static let indicatorHeight: CGFloat = 2.0 + } + + private var indicatorAttributes: UICollectionViewLayoutAttributes! + private var invalidationContext: UICollectionViewFlowLayoutInvalidationContext = { + let context = UICollectionViewFlowLayoutInvalidationContext() + context.invalidateFlowLayoutAttributes = false + context.invalidateFlowLayoutDelegateMetrics = false + context.invalidateDecorationElements(ofKind: ActiveTabIndicatorView.kind, at: [Constants.indicatorIndexPath]) + return context + }() + + var currentPage: Int = 0 + + // MARK: Init + override init() { super.init() setUpLayout() + registerDecorationView() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setUpLayout() + registerDecorationView() + } + + // MARK: Layout + + override func prepare() { + super.prepare() + indicatorAttributes = indicatorAttributes(for: currentPage) + } + + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + var attributes = super.layoutAttributesForElements(in: rect) + attributes?.append(indicatorAttributes) + return attributes + } + + override func layoutAttributesForDecorationView(ofKind elementKind: String, + at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + guard elementKind == ActiveTabIndicatorView.kind else { return nil } + return indicatorAttributes + } + + // MARK: Public functions + + func updateIndicator(direction: ScrollDirection) { + + let currentIndicatorAttributes = indicatorAttributes(for: currentPage) + + switch direction { + case .left(let percentage): + + let previousIndicatorAttributes = indicatorAttributes(for: currentPage - 1) + + let frame = currentIndicatorAttributes.frame + currentIndicatorAttributes.frame = CGRect(x: frame.minX - (frame.minX - previousIndicatorAttributes.frame.minX) * percentage, + y: frame.minY, + width: frame.width - (frame.width - previousIndicatorAttributes.frame.width) * percentage, + height: frame.height) + + indicatorAttributes = currentIndicatorAttributes + + case .right(let percentage): + + let nextIndicatorAttributes = indicatorAttributes(for: currentPage + 1) + + let frame = currentIndicatorAttributes.frame + currentIndicatorAttributes.frame = CGRect(x: frame.minX + (nextIndicatorAttributes.frame.minX - frame.minX) * percentage, + y: frame.minY, + width: frame.width - (frame.width - nextIndicatorAttributes.frame.width) * percentage, + height: frame.height) + + indicatorAttributes = currentIndicatorAttributes + + case .stationary: + + break + } + + invalidateLayout(with: invalidationContext) } } @@ -25,8 +103,31 @@ private extension TabCollectionViewLayout { func setUpLayout() { scrollDirection = .horizontal - sectionInset = .zero minimumInteritemSpacing = 0.0 minimumLineSpacing = 0.0 } + + func registerDecorationView() { + register(ActiveTabIndicatorView.self, + forDecorationViewOfKind: ActiveTabIndicatorView.kind) + } + + func indicatorAttributes(for page: Int) -> UICollectionViewLayoutAttributes { + + guard let tabItemAttributes = layoutAttributesForItem(at: IndexPath(item: page, section: 0)) else { + #if DEBUG + NSLog("Called `indicatorAttributes(for:)` before super did its preparations.") + #endif + return UICollectionViewLayoutAttributes() + } + + let tabItemFrame = tabItemAttributes.frame + + let indicatorAttributes = UICollectionViewLayoutAttributes(forDecorationViewOfKind: ActiveTabIndicatorView.kind, + with: Constants.indicatorIndexPath) + indicatorAttributes.frame = CGRect(x: tabItemFrame.minX, y: tabItemFrame.maxY - Constants.indicatorHeight, + width: tabItemFrame.width, height: Constants.indicatorHeight) + indicatorAttributes.zIndex = Int.max + return indicatorAttributes + } } From 7e80a95c5096bb314df10604904c6a7320f80597 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Mon, 21 May 2018 14:18:00 +0400 Subject: [PATCH 19/28] Add tab item sizing policy This change allows the client to configure tab width to be either fixed or flexible to fill the full width. Auto sizing is planned for future development. --- ICViewPager/Application/ApplicationDelegate.swift | 14 +++++++++++--- .../ExampleViewPagerControllerDataSource.swift | 10 +++++++++- .../Tab/TabCollectionViewDataSource.swift | 8 +++----- .../Tab/TabCollectionViewDelegate.swift | 11 ++++++++++- .../ICViewPager/ViewPagerConfiguration.swift | 12 +++++++++++- ICViewPager/ICViewPager/ViewPagerController.swift | 10 +++++----- 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/ICViewPager/Application/ApplicationDelegate.swift b/ICViewPager/Application/ApplicationDelegate.swift index 16f5be3..d4af203 100644 --- a/ICViewPager/Application/ApplicationDelegate.swift +++ b/ICViewPager/Application/ApplicationDelegate.swift @@ -20,9 +20,12 @@ class ApplicationDelegate: UIResponder, UIApplicationDelegate, UISplitViewContro window = UIWindow(frame: UIScreen.main.bounds) -// window?.rootViewController = viewPagerController() + + /** To test different container scenarios, enable one option. */ + window?.rootViewController = viewPagerController() // window?.rootViewController = navigationController() - window?.rootViewController = tabBarController() +// window?.rootViewController = tabBarController() + window?.makeKeyAndVisible() return true @@ -31,7 +34,12 @@ class ApplicationDelegate: UIResponder, UIApplicationDelegate, UISplitViewContro // MARK: Functions for test purposes private func viewPagerController() -> ViewPagerController { - let viewPagerController = ViewPagerController() + + /** ViewPagerController configuration here. All the configuration properties are optional. */ + let configuration = ViewPagerConfiguration(tabHeight: 48.0, + tabItemSizingPolicy: .fill) + + let viewPagerController = ViewPagerController(configuration: configuration) viewPagerController.dataSource = dataSource return viewPagerController } diff --git a/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift index b9efb09..9e01d33 100644 --- a/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift +++ b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift @@ -43,6 +43,14 @@ extension ExampleViewPagerControllerDataSource: ViewPagerControllerDataSource { } func numberOfViews(in controller: ViewPagerController) -> Int { - return viewControllers.count + + /** Return all the view controllers if the tab bar is not configured to fill the full width. */ + let tabItemSizingPolicy = controller.configuration.tabItemSizingPolicy + switch tabItemSizingPolicy { + case .fixed(_): + return viewControllers.count + case .fill: + return 3 + } } } diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift index 505abc6..340df78 100644 --- a/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift @@ -17,6 +17,7 @@ final class TabCollectionViewDataSource: NSObject { private unowned var viewPagerController: ViewPagerController private unowned var collectionView: UICollectionView weak var dataSource: ViewPagerControllerDataSource? + var numberOfViews: Int = 0 // MARK: Init @@ -59,10 +60,6 @@ extension TabCollectionViewDataSource: UICollectionViewDataSource { return cell } - func numberOfSections(in collectionView: UICollectionView) -> Int { - return 1 - } - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { @@ -70,6 +67,7 @@ extension TabCollectionViewDataSource: UICollectionViewDataSource { fatalError("ViewPagerControllerDataSource is not provided!") } - return dataSource.numberOfViews(in: viewPagerController) + numberOfViews = dataSource.numberOfViews(in: viewPagerController) + return numberOfViews } } diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift index 487429b..4e6433f 100644 --- a/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift @@ -16,6 +16,7 @@ protocol TabCollectionViewDelegateProtocol: class { final class TabCollectionViewDelegate: NSObject { private unowned var viewPagerController: ViewPagerController + private lazy var numberOfItems: Int = self.viewPagerController.tabCollectionViewDataSource.numberOfViews weak var delegate: TabCollectionViewDelegateProtocol? // MARK: Init @@ -43,6 +44,14 @@ extension TabCollectionViewDelegate: UICollectionViewDelegateFlowLayout { public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - return CGSize(width: 144.0, height: 44.0) + + let tabItemSizingPolicy = viewPagerController.configuration.tabItemSizingPolicy + switch tabItemSizingPolicy { + case .fixed(let size): + return size + case .fill: + return CGSize(width: collectionView.bounds.width / CGFloat(numberOfItems), + height: collectionView.bounds.height) + } } } diff --git a/ICViewPager/ICViewPager/ViewPagerConfiguration.swift b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift index 3dd786b..e3c236b 100644 --- a/ICViewPager/ICViewPager/ViewPagerConfiguration.swift +++ b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift @@ -14,9 +14,19 @@ public struct ViewPagerConfiguration { public static let tabHeight: CGFloat = 44.0 } + public enum TabItemSizingPolicy { + public static let defaultTabWidth: CGSize = CGSize(width: 144.0, height: Constants.tabHeight) + + case fixed(size: CGSize) + case fill + } + public var tabHeight: CGFloat + public var tabItemSizingPolicy: TabItemSizingPolicy - public init(tabHeight: CGFloat = Constants.tabHeight) { + public init(tabHeight: CGFloat = Constants.tabHeight, + tabItemSizingPolicy: TabItemSizingPolicy = .fixed(size: TabItemSizingPolicy.defaultTabWidth)) { self.tabHeight = tabHeight + self.tabItemSizingPolicy = tabItemSizingPolicy } } diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index 3149ba0..657c235 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -17,11 +17,11 @@ final public class ViewPagerController: UIViewController { @IBOutlet private weak var tabCollectionViewLayout: TabCollectionViewLayout! @IBOutlet private weak var contentCollectionViewLayout: ContentCollectionViewLayout! - private var contentCollectionViewDataSource: ContentCollectionViewDataSource! - private var contentCollectionViewDelegate: ContentCollectionViewDelegate! - private var tabCollectionViewDataSource: TabCollectionViewDataSource! - private var tabCollectionViewDelegate: TabCollectionViewDelegate! - private var scrollController: ScrollController! + internal var contentCollectionViewDataSource: ContentCollectionViewDataSource! + internal var contentCollectionViewDelegate: ContentCollectionViewDelegate! + internal var tabCollectionViewDataSource: TabCollectionViewDataSource! + internal var tabCollectionViewDelegate: TabCollectionViewDelegate! + internal var scrollController: ScrollController! public weak var dataSource: ViewPagerControllerDataSource? public var configuration: ViewPagerConfiguration From ebeb80ee578985e1dcd9b8b09e439992adb0c40e Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Mon, 21 May 2018 14:57:49 +0400 Subject: [PATCH 20/28] Remove legacy code base --- ICViewPager.podspec | 32 +- ICViewPager.xcodeproj/project.pbxproj | 44 - ICViewPager/Legacy/AppDelegate.h | 15 - ICViewPager/Legacy/AppDelegate.m | 46 - .../Legacy/Controller/ContentViewController.h | 16 - .../Legacy/Controller/ContentViewController.m | 29 - .../Legacy/Controller/HostViewController.h | 15 - .../Legacy/Controller/HostViewController.m | 146 --- .../Legacy/ICViewPager/ViewPagerController.h | 218 ---- .../Legacy/ICViewPager/ViewPagerController.m | 1081 ----------------- ICViewPager/Legacy/iPad.storyboard | 81 -- ICViewPager/Legacy/iPhone.storyboard | 81 -- Resources/Screenshot.jpg | Bin 6958 -> 0 bytes 13 files changed, 6 insertions(+), 1798 deletions(-) delete mode 100644 ICViewPager/Legacy/AppDelegate.h delete mode 100644 ICViewPager/Legacy/AppDelegate.m delete mode 100644 ICViewPager/Legacy/Controller/ContentViewController.h delete mode 100644 ICViewPager/Legacy/Controller/ContentViewController.m delete mode 100644 ICViewPager/Legacy/Controller/HostViewController.h delete mode 100644 ICViewPager/Legacy/Controller/HostViewController.m delete mode 100644 ICViewPager/Legacy/ICViewPager/ViewPagerController.h delete mode 100644 ICViewPager/Legacy/ICViewPager/ViewPagerController.m delete mode 100644 ICViewPager/Legacy/iPad.storyboard delete mode 100644 ICViewPager/Legacy/iPhone.storyboard delete mode 100644 Resources/Screenshot.jpg diff --git a/ICViewPager.podspec b/ICViewPager.podspec index 3d96184..d36f67d 100644 --- a/ICViewPager.podspec +++ b/ICViewPager.podspec @@ -1,39 +1,19 @@ Pod::Spec.new do |s| s.name = "ICViewPager" - s.version = "1.5.1" - s.summary = "You can create sliding tabs with ViewPager." + s.version = "2.0.0" + s.summary = "" s.description = <<-DESC - Slide through the contents or select from tabs or slide through tabs and select! - - ## Installation - Just copy ViewPagerController.m and ViewPagerController.h files to your project. - Or you can use CocoaPods (as this is the recommended way). - `pod 'ICViewPager'` - - ## Usage - Subclass ViewPagerController (as it's a `UIViewController` subclass) and implement dataSource and delegate methods in the subclass. - - ## Requirements - ViewPager supports minimum iOS 6 and uses ARC. - Supports both iPhone and iPad. - - ## Contact - [Ilter Cengiz](mailto:me@iltercengiz.info) - [@monsieurje](https://twitter.com/monsieurje) - - ## Licence - ICViewPager is MIT licensed. See the LICENSE file for more info. DESC s.homepage = "https://github.com/monsieurje/ICViewPager" - s.screenshots = "https://raw.githubusercontent.com/iltercengiz/ICViewPager/master/Resources/Screenshot.jpg" + s.screenshots = "" s.license = { :type => 'MIT', :file => 'LICENSE' } - s.author = { "Ilter Cengiz" => "me@iltercengiz.info" } + s.author = { "Ilter Cengiz" => "iltercengiz@yahoo.com" } s.platform = :ios, '6.0' - s.source = { :git => "https://github.com/monsieurje/ICViewPager.git", :tag => "1.5.1" } - s.source_files = 'ICViewPager/ICViewPager/*.{h,m}' + s.source = { :git => "https://github.com/monsieurje/ICViewPager.git", :tag => "2.0.0" } + s.source_files = 'ICViewPager/ICViewPager/**/*.swift' s.requires_arc = true end diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index c8ef6a2..34b4b25 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -58,18 +58,8 @@ 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyViewController.swift; sourceTree = ""; }; 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPagerConfiguration.swift; sourceTree = ""; }; - 7CEC17A817DA1EC000E4A439 /* iPad.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = iPad.storyboard; sourceTree = ""; }; 7CF3D65117CE32E40021036A /* ICViewPager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ICViewPager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7CF3D65C17CE32E40021036A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7CF3D66317CE32E40021036A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7CF3D66417CE32E40021036A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 7CF3D67117CE332F0021036A /* iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = iPhone.storyboard; sourceTree = ""; }; - 7CF3D67C17CE33E10021036A /* ViewPagerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewPagerController.h; sourceTree = ""; }; - 7CF3D67D17CE33E10021036A /* ViewPagerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewPagerController.m; sourceTree = ""; }; - 7CF3D67F17CE33EC0021036A /* HostViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HostViewController.h; sourceTree = ""; }; - 7CF3D68017CE33EC0021036A /* HostViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HostViewController.m; sourceTree = ""; }; - 7CF3D68317CE3F5B0021036A /* ContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentViewController.h; sourceTree = ""; }; - 7CF3D68417CE3F5B0021036A /* ContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContentViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -150,19 +140,6 @@ path = Empty; sourceTree = ""; }; - 36F4A3B720AF0F22000995B2 /* Legacy */ = { - isa = PBXGroup; - children = ( - 7CF3D66317CE32E40021036A /* AppDelegate.h */, - 7CF3D66417CE32E40021036A /* AppDelegate.m */, - 7CF3D67117CE332F0021036A /* iPhone.storyboard */, - 7CEC17A817DA1EC000E4A439 /* iPad.storyboard */, - 7CF3D67B17CE33C80021036A /* ICViewPager */, - 7CF3D67A17CE33C80021036A /* Controller */, - ); - path = Legacy; - sourceTree = ""; - }; 36F4A3BB20AF0FC4000995B2 /* Supporting Files */ = { isa = PBXGroup; children = ( @@ -212,27 +189,6 @@ 36F4A3B320AF0E1D000995B2 /* Scenes */, 36F4A3BC20AF184E000995B2 /* ICViewPager */, 36F4A3BB20AF0FC4000995B2 /* Supporting Files */, - 36F4A3B720AF0F22000995B2 /* Legacy */, - ); - path = ICViewPager; - sourceTree = ""; - }; - 7CF3D67A17CE33C80021036A /* Controller */ = { - isa = PBXGroup; - children = ( - 7CF3D67F17CE33EC0021036A /* HostViewController.h */, - 7CF3D68017CE33EC0021036A /* HostViewController.m */, - 7CF3D68317CE3F5B0021036A /* ContentViewController.h */, - 7CF3D68417CE3F5B0021036A /* ContentViewController.m */, - ); - path = Controller; - sourceTree = ""; - }; - 7CF3D67B17CE33C80021036A /* ICViewPager */ = { - isa = PBXGroup; - children = ( - 7CF3D67C17CE33E10021036A /* ViewPagerController.h */, - 7CF3D67D17CE33E10021036A /* ViewPagerController.m */, ); path = ICViewPager; sourceTree = ""; diff --git a/ICViewPager/Legacy/AppDelegate.h b/ICViewPager/Legacy/AppDelegate.h deleted file mode 100644 index cf72238..0000000 --- a/ICViewPager/Legacy/AppDelegate.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// AppDelegate.h -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import - -@interface AppDelegate : UIResponder - -@property (strong, nonatomic) UIWindow *window; - -@end diff --git a/ICViewPager/Legacy/AppDelegate.m b/ICViewPager/Legacy/AppDelegate.m deleted file mode 100644 index 453922b..0000000 --- a/ICViewPager/Legacy/AppDelegate.m +++ /dev/null @@ -1,46 +0,0 @@ -// -// AppDelegate.m -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import "AppDelegate.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - // Override point for customization after application launch. - return YES; -} - -- (void)applicationWillResignActive:(UIApplication *)application -{ - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. -} - -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. -} - -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. -} - -- (void)applicationDidBecomeActive:(UIApplication *)application -{ - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. -} - -- (void)applicationWillTerminate:(UIApplication *)application -{ - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. -} - -@end diff --git a/ICViewPager/Legacy/Controller/ContentViewController.h b/ICViewPager/Legacy/Controller/ContentViewController.h deleted file mode 100644 index f77a6c6..0000000 --- a/ICViewPager/Legacy/Controller/ContentViewController.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// ContentViewController.h -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import - -@interface ContentViewController : UIViewController - -@property NSString *labelString; -@property (weak, nonatomic) IBOutlet UILabel *label; - -@end diff --git a/ICViewPager/Legacy/Controller/ContentViewController.m b/ICViewPager/Legacy/Controller/ContentViewController.m deleted file mode 100644 index 40d2b28..0000000 --- a/ICViewPager/Legacy/Controller/ContentViewController.m +++ /dev/null @@ -1,29 +0,0 @@ -// -// ContentViewController.m -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import "ContentViewController.h" - -@interface ContentViewController () - -@end - -@implementation ContentViewController - -- (void)viewDidLoad { - - [super viewDidLoad]; - - _label.text = _labelString; -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -@end diff --git a/ICViewPager/Legacy/Controller/HostViewController.h b/ICViewPager/Legacy/Controller/HostViewController.h deleted file mode 100644 index 613038b..0000000 --- a/ICViewPager/Legacy/Controller/HostViewController.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// HostViewController.h -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import - -#import "ViewPagerController.h" - -@interface HostViewController : ViewPagerController - -@end diff --git a/ICViewPager/Legacy/Controller/HostViewController.m b/ICViewPager/Legacy/Controller/HostViewController.m deleted file mode 100644 index b113549..0000000 --- a/ICViewPager/Legacy/Controller/HostViewController.m +++ /dev/null @@ -1,146 +0,0 @@ -// -// HostViewController.m -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import "HostViewController.h" -#import "ContentViewController.h" - -@interface HostViewController () - -@property (nonatomic) NSUInteger numberOfTabs; - -@end - -@implementation HostViewController - -- (void)viewDidLoad { - - [super viewDidLoad]; - - self.dataSource = self; - self.delegate = self; - - self.title = @"View Pager"; - - // Keeps tab bar below navigation bar on iOS 7.0+ - // if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) { - // self.edgesForExtendedLayout = UIRectEdgeNone; - // } - - self.navigationItem.rightBarButtonItem = ({ - - UIBarButtonItem *button; - button = [[UIBarButtonItem alloc] initWithTitle:@"Tab #5" style:UIBarButtonItemStylePlain target:self action:@selector(selectTabWithNumberFive)]; - - button; - }); - -} -- (void)viewDidAppear:(BOOL)animated { - - [super viewDidAppear:animated]; - - [self performSelector:@selector(loadContent) withObject:nil afterDelay:3.0]; - -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -#pragma mark - Setters -- (void)setNumberOfTabs:(NSUInteger)numberOfTabs { - - // Set numberOfTabs - _numberOfTabs = numberOfTabs; - - // Reload data - [self reloadData]; - -} - -#pragma mark - Helpers -- (void)selectTabWithNumberFive { - [self selectTabAtIndex:5]; -} -- (void)loadContent { - self.numberOfTabs = 10; -} - -#pragma mark - Interface Orientation Changes -- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - - // Update changes after screen rotates - [self performSelector:@selector(setNeedsReloadOptions) withObject:nil afterDelay:duration]; -} - -#pragma mark - ViewPagerDataSource -- (NSUInteger)numberOfTabsForViewPager:(ViewPagerController *)viewPager { - return self.numberOfTabs; -} -- (UIView *)viewPager:(ViewPagerController *)viewPager viewForTabAtIndex:(NSUInteger)index { - - UILabel *label = [UILabel new]; - label.backgroundColor = [UIColor clearColor]; - label.font = [UIFont systemFontOfSize:12.0]; - label.text = [NSString stringWithFormat:@"Tab #%i", index]; - label.textAlignment = NSTextAlignmentCenter; - label.textColor = [UIColor blackColor]; - [label sizeToFit]; - - return label; -} - -- (UIViewController *)viewPager:(ViewPagerController *)viewPager contentViewControllerForTabAtIndex:(NSUInteger)index { - - ContentViewController *cvc = [self.storyboard instantiateViewControllerWithIdentifier:@"contentViewController"]; - - cvc.labelString = [NSString stringWithFormat:@"Content View #%i", index]; - - return cvc; -} - -#pragma mark - ViewPagerDelegate -- (CGFloat)viewPager:(ViewPagerController *)viewPager valueForOption:(ViewPagerOption)option withDefault:(CGFloat)value { - - switch (option) { - case ViewPagerOptionStartFromSecondTab: - return 0.0; - case ViewPagerOptionCenterCurrentTab: - return 1.0; - case ViewPagerOptionTabLocation: - return 0.0; - case ViewPagerOptionTabHeight: - return 49.0; - case ViewPagerOptionTabOffset: - return 36.0; - case ViewPagerOptionTabWidth: - return UIInterfaceOrientationIsLandscape(self.interfaceOrientation) ? 128.0 : 96.0; - case ViewPagerOptionFixFormerTabsPositions: - return 1.0; - case ViewPagerOptionFixLatterTabsPositions: - return 1.0; - default: - return value; - } -} -- (UIColor *)viewPager:(ViewPagerController *)viewPager colorForComponent:(ViewPagerComponent)component withDefault:(UIColor *)color { - - switch (component) { - case ViewPagerIndicator: - return [[UIColor redColor] colorWithAlphaComponent:0.64]; - case ViewPagerTabsView: - return [[UIColor lightGrayColor] colorWithAlphaComponent:0.32]; - case ViewPagerContent: - return [[UIColor darkGrayColor] colorWithAlphaComponent:0.32]; - default: - return color; - } -} - -@end diff --git a/ICViewPager/Legacy/ICViewPager/ViewPagerController.h b/ICViewPager/Legacy/ICViewPager/ViewPagerController.h deleted file mode 100644 index 37218a3..0000000 --- a/ICViewPager/Legacy/ICViewPager/ViewPagerController.h +++ /dev/null @@ -1,218 +0,0 @@ -// -// ViewPagerController.h -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import - -/** - * Every option has a default value. - * - * ViewPagerOptionTabHeight: Tab bar's height, defaults to 44.0 - * ViewPagerOptionTabOffset: Tab bar's offset from left, defaults to 56.0 - * ViewPagerOptionTabWidth: Any tab item's width, defaults to 128.0 - * ViewPagerOptionTabLocation: 1.0: Top, 0.0: Bottom, Defaults to Top - * ViewPagerOptionStartFromSecondTab: 1.0: YES, 0.0: NO, defines if view should appear with the 1st or 2nd tab. Defaults to NO - * ViewPagerOptionCenterCurrentTab: 1.0: YES, 0.0: NO, defines if tabs should be centered, with the given tabWidth. Defaults to NO - * ViewPagerOptionFixFormerTabsPositions: 1.0: YES, 0.0: NO, defines if the active tab should be placed margined by the offset amount to the left. Effects only the former tabs. If set 1.0 (YES), first tab will be placed at the same position with the second one, leaving space before itself. Defaults to NO - * ViewPagerOptionFixLatterTabsPositions: 1.0: YES, 0.0: NO, like ViewPagerOptionFixFormerTabsPositions, but effects the latter tabs, making them leave space after themselves. Defaults to NO - */ -typedef NS_ENUM(NSUInteger, ViewPagerOption) { - ViewPagerOptionTabHeight, - ViewPagerOptionTabOffset, - ViewPagerOptionTabWidth, - ViewPagerOptionTabLocation, - ViewPagerOptionStartFromSecondTab, - ViewPagerOptionCenterCurrentTab, - ViewPagerOptionFixFormerTabsPositions, - ViewPagerOptionFixLatterTabsPositions -}; - -/** - * Main parts of the ViewPagerController - * - * ViewPagerIndicator: The colored line in the view of the active tab - * ViewPagerTabsView: The tabs view itself - * ViewPagerContent: Provided views goes here as content - */ -typedef NS_ENUM(NSUInteger, ViewPagerComponent) { - ViewPagerIndicator, - ViewPagerTabsView, - ViewPagerContent -}; - -@protocol ViewPagerDataSource; -@protocol ViewPagerDelegate; - -@interface ViewPagerController : UIViewController - -/** - * The object that acts as the data source of the receiving viewPager - * @discussion The data source must adopt the ViewPagerDataSource protocol. The data source is not retained. - */ -@property (weak) id dataSource; -/** - * The object that acts as the delegate of the receiving viewPager - * @discussion The delegate must adopt the ViewPagerDelegate protocol. The delegate is not retained. - */ -@property (weak) id delegate; - -#pragma mark Methods -/** - * Reloads all tabs and contents - */ -- (void)reloadData; - -/** - * Selects the given tab and shows the content at this index - * - * @param index The index of the tab that will be selected - */ -- (void)selectTabAtIndex:(NSUInteger)index; - -/** - * Reloads the appearance of the tabs view. - * Adjusts tabs' width, offset, the center, fix former/latter tabs cases. - * Without implementing the - viewPager:valueForOption:withDefault: delegate method, - * this method does nothing. - * Calling this method without changing any option will affect the performance. - */ -- (void)setNeedsReloadOptions; - -/** - * Reloads the colors. - * You can make ViewPager to reload its components colors. - * Changing `ViewPagerTabsView` and `ViewPagerContent` color will have no effect to performance, - * but `ViewPagerIndicator`, as it will need to iterate through all tabs to update it. - * Calling this method without changing any color won't affect the performance, - * but will cause your delegate method (if you implemented it) to be called three times. - */ -- (void)setNeedsReloadColors; - -/** - * Call this method to get the value of a given option. - * Returns NAN for any undefined option. - * - * @param option The option key. Keys are defined in ViewPagerController.h - * - * @return A CGFloat, defining the setting for the given option - */ -- (CGFloat)valueForOption:(ViewPagerOption)option; - -/** - * Call this method to get the color of a given component. - * Returns [UIColor clearColor] for any undefined component. - * - * @param component The component key. Keys are defined in ViewPagerController.h - * - * @return A UIColor for the given component - */ -- (UIColor *)colorForComponent:(ViewPagerComponent)component; - -@end - -#pragma mark dataSource -@protocol ViewPagerDataSource -/** - * Asks dataSource how many tabs will there be. - * - * @param viewPager The viewPager that's subject to - * @return Number of tabs - */ -- (NSUInteger)numberOfTabsForViewPager:(ViewPagerController *)viewPager; -/** - * Asks dataSource to give a view to display as a tab item. - * It is suggested to return a view with a clearColor background. - * So that un/selected states can be clearly seen. - * - * @param viewPager The viewPager that's subject to - * @param index The index of the tab whose view is asked - * - * @return A view that will be shown as tab at the given index - */ -- (UIView *)viewPager:(ViewPagerController *)viewPager viewForTabAtIndex:(NSUInteger)index; - -@optional -/** - * The content for any tab. Return a view controller and ViewPager will use its view to show as content. - * - * @param viewPager The viewPager that's subject to - * @param index The index of the content whose view is asked - * - * @return A viewController whose view will be shown as content - */ -- (UIViewController *)viewPager:(ViewPagerController *)viewPager contentViewControllerForTabAtIndex:(NSUInteger)index; -/** - * The content for any tab. Return a view and ViewPager will use it to show as content. - * - * @param viewPager The viewPager that's subject to - * @param index The index of the content whose view is asked - * - * @return A view which will be shown as content - */ -- (UIView *)viewPager:(ViewPagerController *)viewPager contentViewForTabAtIndex:(NSUInteger)index; - -@end - -#pragma mark delegate -@protocol ViewPagerDelegate - -@optional -/** - * delegate object must implement this method if wants to be informed when a tab changes - * - * @param viewPager The viewPager that's subject to - * @param index The index of the active tab - */ -- (void)viewPager:(ViewPagerController *)viewPager didChangeTabToIndex:(NSUInteger)index; -/** - * delegate object should implement this method if it wants to be informed when a tab changes and what its previous tab index was - * - * @param viewPager The viewPager that's subject to - * @param index The index of the active tab - * @param previousIndex The previous index of the active tab - */ -- (void)viewPager:(ViewPagerController *)viewPager didChangeTabToIndex:(NSUInteger)index fromIndex:(NSUInteger)previousIndex; -/** - * delegate object should implement this method if it wants to be informed when a tab changes and what its previous tab index was and whether the change action was caused by a swipe gesture or tab bar button press - * - * @param viewPager The viewPager that's subject to - * @param index The index of the active tab - * @param previousIndex The previous index of the active tab - * @param didSwipe Indicating if the change action was caused by a swipe gesture or a tab bar button press - */ -- (void)viewPager:(ViewPagerController *)viewPager didChangeTabToIndex:(NSUInteger)index fromIndex:(NSUInteger)previousIndex didSwipe:(BOOL)didSwipe; -/** - * Every time -reloadData method called, ViewPager will ask its delegate for option values. - * So you don't have to set options from ViewPager itself. - * You don't have to provide values for all options. - * Just return the values for the interested options and return the given 'value' parameter for the rest. - * - * @param viewPager The viewPager that's subject to - * @param option The option key. Keys are defined in ViewPagerController.h - * @param value The default value for the given option - * - * @return A CGFloat, defining the setting for the given option - */ -- (CGFloat)viewPager:(ViewPagerController *)viewPager valueForOption:(ViewPagerOption)option withDefault:(CGFloat)value; - -/** - * Use this method to customize the look and feel. - * viewPager will ask its delegate for colors for its components. - * And if they are provided, it will use them, otherwise it will use default colors. - * Also not that, colors for tab and content views will change the tabView's and contentView's background - * (you should provide these views with a clearColor to see the colors), - * and indicator will change its own color. - * - * @param viewPager The viewPager that's subject to - * @param component The component key. Keys are defined in ViewPagerController.h - * @param color The default color for the given component - * - * @return A UIColor for the given component - */ -- (UIColor *)viewPager:(ViewPagerController *)viewPager colorForComponent:(ViewPagerComponent)component withDefault:(UIColor *)color; - -@end diff --git a/ICViewPager/Legacy/ICViewPager/ViewPagerController.m b/ICViewPager/Legacy/ICViewPager/ViewPagerController.m deleted file mode 100644 index 7c3ceb4..0000000 --- a/ICViewPager/Legacy/ICViewPager/ViewPagerController.m +++ /dev/null @@ -1,1081 +0,0 @@ -// -// ViewPagerController.m -// ICViewPager -// -// Created by Ilter Cengiz on 28/08/2013. -// Copyright (c) 2013 Ilter Cengiz. All rights reserved. -// - -#import "ViewPagerController.h" - -#pragma mark - Constants and macros -#define kTabViewTag 38 -#define kContentViewTag 34 -#define IOS_VERSION_7 [[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending - -#define kTabHeight 44.0 -#define kTabOffset 56.0 -#define kTabWidth 128.0 -#define kTabLocation 1.0 -#define kStartFromSecondTab 0.0 -#define kCenterCurrentTab 0.0 -#define kFixFormerTabsPositions 0.0 -#define kFixLatterTabsPositions 0.0 - -#define kIndicatorColor [UIColor colorWithRed:178.0/255.0 green:203.0/255.0 blue:57.0/255.0 alpha:0.75] -#define kTabsViewBackgroundColor [UIColor colorWithRed:234.0/255.0 green:234.0/255.0 blue:234.0/255.0 alpha:0.75] -#define kContentViewBackgroundColor [UIColor colorWithRed:248.0/255.0 green:248.0/255.0 blue:248.0/255.0 alpha:0.75] - -#pragma mark - UIColor+Equality -@interface UIColor (Equality) -- (BOOL)isEqualToColor:(UIColor *)otherColor; -@end - -@implementation UIColor (Equality) -// This method checks if two UIColors are the same -// Thanks to @samvermette for this method: http://stackoverflow.com/a/8899384/1931781 -- (BOOL)isEqualToColor:(UIColor *)otherColor { - - CGColorSpaceRef colorSpaceRGB = CGColorSpaceCreateDeviceRGB(); - - UIColor *(^convertColorToRGBSpace)(UIColor *) = ^(UIColor *color) { - if (CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)) == kCGColorSpaceModelMonochrome) { - const CGFloat *oldComponents = CGColorGetComponents(color.CGColor); - CGFloat components[4] = {oldComponents[0], oldComponents[0], oldComponents[0], oldComponents[1]}; - return [UIColor colorWithCGColor:CGColorCreate(colorSpaceRGB, components)]; - } else { - return color; - } - }; - - UIColor *selfColor = convertColorToRGBSpace(self); - otherColor = convertColorToRGBSpace(otherColor); - CGColorSpaceRelease(colorSpaceRGB); - - return [selfColor isEqual:otherColor]; -} -@end - -#pragma mark - TabView -@class TabView; - -@interface TabView : UIView -@property (nonatomic, getter = isSelected) BOOL selected; -@property (nonatomic) UIColor *indicatorColor; -@end - -@implementation TabView -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - self.backgroundColor = [UIColor clearColor]; - } - return self; -} -- (void)setSelected:(BOOL)selected { - _selected = selected; - // Update view as state changed - [self setNeedsDisplay]; -} -- (void)drawRect:(CGRect)rect { - - UIBezierPath *bezierPath; - - // Draw top line - bezierPath = [UIBezierPath bezierPath]; - [bezierPath moveToPoint:CGPointMake(0.0, 0.0)]; - [bezierPath addLineToPoint:CGPointMake(CGRectGetWidth(rect), 0.0)]; - [[UIColor colorWithWhite:197.0/255.0 alpha:0.75] setStroke]; - [bezierPath setLineWidth:1.0]; - [bezierPath stroke]; - - // Draw bottom line - bezierPath = [UIBezierPath bezierPath]; - [bezierPath moveToPoint:CGPointMake(0.0, CGRectGetHeight(rect))]; - [bezierPath addLineToPoint:CGPointMake(CGRectGetWidth(rect), CGRectGetHeight(rect))]; - [[UIColor colorWithWhite:197.0/255.0 alpha:0.75] setStroke]; - [bezierPath setLineWidth:1.0]; - [bezierPath stroke]; - - // Draw an indicator line if tab is selected - if (self.selected) { - - bezierPath = [UIBezierPath bezierPath]; - - // Draw the indicator - [bezierPath moveToPoint:CGPointMake(0.0, CGRectGetHeight(rect) - 1.0)]; - [bezierPath addLineToPoint:CGPointMake(CGRectGetWidth(rect), CGRectGetHeight(rect) - 1.0)]; - [bezierPath setLineWidth:5.0]; - [self.indicatorColor setStroke]; - [bezierPath stroke]; - } -} -@end - -#pragma mark - ViewPagerController -@interface ViewPagerController () - -// Tab and content stuff -@property UIScrollView *tabsView; -@property UIView *contentView; - -@property UIPageViewController *pageViewController; -@property (assign) id actualDelegate; - -// Tab and content cache -@property NSMutableArray *tabs; -@property NSMutableArray *contents; - -// Options -@property (nonatomic) NSNumber *tabHeight; -@property (nonatomic) NSNumber *tabOffset; -@property (nonatomic) NSNumber *tabWidth; -@property (nonatomic) NSNumber *tabLocation; -@property (nonatomic) NSNumber *startFromSecondTab; -@property (nonatomic) NSNumber *centerCurrentTab; -@property (nonatomic) NSNumber *fixFormerTabsPositions; -@property (nonatomic) NSNumber *fixLatterTabsPositions; - -@property (nonatomic) NSUInteger tabCount; -@property (nonatomic) NSUInteger activeTabIndex; -@property (nonatomic) NSUInteger activeContentIndex; - -@property (getter = isAnimatingToTab, assign) BOOL animatingToTab; -@property (getter = isDefaultSetupDone, assign) BOOL defaultSetupDone; - -// Colors -@property (nonatomic) UIColor *indicatorColor; -@property (nonatomic) UIColor *tabsViewBackgroundColor; -@property (nonatomic) UIColor *contentViewBackgroundColor; - -@end - -@implementation ViewPagerController - -@synthesize tabHeight = _tabHeight; -@synthesize tabOffset = _tabOffset; -@synthesize tabWidth = _tabWidth; -@synthesize tabLocation = _tabLocation; -@synthesize startFromSecondTab = _startFromSecondTab; -@synthesize centerCurrentTab = _centerCurrentTab; -@synthesize fixFormerTabsPositions = _fixFormerTabsPositions; -@synthesize fixLatterTabsPositions = _fixLatterTabsPositions; - -#pragma mark - Init -- (id)initWithCoder:(NSCoder *)aDecoder { - self = [super initWithCoder:aDecoder]; - if (self) { - [self defaultSettings]; - } - return self; -} -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - if (self) { - [self defaultSettings]; - } - return self; -} - -#pragma mark - View life cycle -- (void)viewDidLoad { - [super viewDidLoad]; -} -- (void)viewWillAppear:(BOOL)animated { - - [super viewWillAppear:animated]; - - // Do setup if it's not done yet - if (![self isDefaultSetupDone]) { - [self defaultSetup]; - } -} -- (void)viewWillLayoutSubviews { - - // Re-layout sub views - [self layoutSubviews]; -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; -} - -- (void)layoutSubviews { - - CGFloat topLayoutGuide = 0.0; - if (IOS_VERSION_7) { - topLayoutGuide = 20.0; - if (self.navigationController && !self.navigationController.navigationBarHidden) { - topLayoutGuide += self.navigationController.navigationBar.frame.size.height; - } - } - - CGRect frame = self.tabsView.frame; - frame.origin.x = 0.0; - frame.origin.y = [self.tabLocation boolValue] ? topLayoutGuide : CGRectGetHeight(self.view.frame) - [self.tabHeight floatValue]; - frame.size.width = CGRectGetWidth(self.view.frame); - frame.size.height = [self.tabHeight floatValue]; - self.tabsView.frame = frame; - - frame = self.contentView.frame; - frame.origin.x = 0.0; - frame.origin.y = [self.tabLocation boolValue] ? topLayoutGuide + CGRectGetHeight(self.tabsView.frame) : topLayoutGuide; - frame.size.width = CGRectGetWidth(self.view.frame); - frame.size.height = CGRectGetHeight(self.view.frame) - (topLayoutGuide + CGRectGetHeight(self.tabsView.frame)) - (self.tabBarController.tabBar.hidden ? 0 : CGRectGetHeight(self.tabBarController.tabBar.frame)); - self.contentView.frame = frame; -} - -#pragma mark - IBAction -- (IBAction)handleTapGesture:(id)sender { - - // Get the desired page's index - UITapGestureRecognizer *tapGestureRecognizer = (UITapGestureRecognizer *)sender; - UIView *tabView = tapGestureRecognizer.view; - __block NSUInteger index = [self.tabs indexOfObject:tabView]; - - //if Tap is not selected Tab(new Tab) - if (self.activeTabIndex != index) { - // Select the tab - [self selectTabAtIndex:index didSwipe:NO]; - } -} - -#pragma mark - Interface rotation -- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { - - // Re-layout sub views - [self layoutSubviews]; - - // Re-align tabs if needed - self.activeTabIndex = self.activeTabIndex; -} - -#pragma mark - Setters -- (void)setTabHeight:(NSNumber *)tabHeight { - - if ([tabHeight floatValue] < 4.0) - tabHeight = [NSNumber numberWithFloat:4.0]; - else if ([tabHeight floatValue] > CGRectGetHeight(self.view.frame)) - tabHeight = [NSNumber numberWithFloat:CGRectGetHeight(self.view.frame)]; - - _tabHeight = tabHeight; -} -- (void)setTabOffset:(NSNumber *)tabOffset { - - if ([tabOffset floatValue] < 0.0) - tabOffset = [NSNumber numberWithFloat:0.0]; - else if ([tabOffset floatValue] > CGRectGetWidth(self.view.frame) - [self.tabWidth floatValue]) - tabOffset = [NSNumber numberWithFloat:CGRectGetWidth(self.view.frame) - [self.tabWidth floatValue]]; - - _tabOffset = tabOffset; -} -- (void)setTabWidth:(NSNumber *)tabWidth { - - if ([tabWidth floatValue] < 4.0) - tabWidth = [NSNumber numberWithFloat:4.0]; - else if ([tabWidth floatValue] > CGRectGetWidth(self.view.frame)) - tabWidth = [NSNumber numberWithFloat:CGRectGetWidth(self.view.frame)]; - - _tabWidth = tabWidth; -} -- (void)setTabLocation:(NSNumber *)tabLocation { - - if ([tabLocation floatValue] != 1.0 && [tabLocation floatValue] != 0.0) - tabLocation = [tabLocation boolValue] ? [NSNumber numberWithBool:YES] : [NSNumber numberWithBool:NO]; - - _tabLocation = tabLocation; -} -- (void)setStartFromSecondTab:(NSNumber *)startFromSecondTab { - - if ([startFromSecondTab floatValue] != 1.0 && [startFromSecondTab floatValue] != 0.0) - startFromSecondTab = [startFromSecondTab boolValue] ? [NSNumber numberWithBool:YES] : [NSNumber numberWithBool:NO]; - - _startFromSecondTab = startFromSecondTab; -} -- (void)setCenterCurrentTab:(NSNumber *)centerCurrentTab { - - if ([centerCurrentTab floatValue] != 1.0 && [centerCurrentTab floatValue] != 0.0) - centerCurrentTab = [centerCurrentTab boolValue] ? [NSNumber numberWithBool:YES] : [NSNumber numberWithBool:NO]; - - _centerCurrentTab = centerCurrentTab; -} -- (void)setFixFormerTabsPositions:(NSNumber *)fixFormerTabsPositions { - - if ([fixFormerTabsPositions floatValue] != 1.0 && [fixFormerTabsPositions floatValue] != 0.0) - fixFormerTabsPositions = [fixFormerTabsPositions boolValue] ? [NSNumber numberWithBool:YES] : [NSNumber numberWithBool:NO]; - - _fixFormerTabsPositions = fixFormerTabsPositions; -} -- (void)setFixLatterTabsPositions:(NSNumber *)fixLatterTabsPositions { - - if ([fixLatterTabsPositions floatValue] != 1.0 && [fixLatterTabsPositions floatValue] != 0.0) - fixLatterTabsPositions = [fixLatterTabsPositions boolValue] ? [NSNumber numberWithBool:YES] : [NSNumber numberWithBool:NO]; - - _fixLatterTabsPositions = fixLatterTabsPositions; -} - -- (void)setActiveTabIndex:(NSUInteger)activeTabIndex { - - TabView *activeTabView; - - // Set to-be-inactive tab unselected - activeTabView = [self tabViewAtIndex:self.activeTabIndex]; - activeTabView.selected = NO; - - // Set to-be-active tab selected - activeTabView = [self tabViewAtIndex:activeTabIndex]; - activeTabView.selected = YES; - - // Set current activeTabIndex - _activeTabIndex = activeTabIndex; - - // Bring tab to active position - // Position the tab in center if centerCurrentTab option is provided as YES - UIView *tabView = [self tabViewAtIndex:self.activeTabIndex]; - CGRect frame = tabView.frame; - - if ([self.centerCurrentTab boolValue]) { - - frame.origin.x += (CGRectGetWidth(frame) / 2); - frame.origin.x -= CGRectGetWidth(self.tabsView.frame) / 2; - frame.size.width = CGRectGetWidth(self.tabsView.frame); - - if (frame.origin.x < 0) { - frame.origin.x = 0; - } - - if ((frame.origin.x + CGRectGetWidth(frame)) > self.tabsView.contentSize.width) { - frame.origin.x = (self.tabsView.contentSize.width - CGRectGetWidth(self.tabsView.frame)); - } - } else { - - frame.origin.x -= [self.tabOffset floatValue]; - frame.size.width = CGRectGetWidth(self.tabsView.frame); - } - - [self.tabsView scrollRectToVisible:frame animated:YES]; -} -- (void)setActiveContentIndex:(NSUInteger)activeContentIndex { - - // Get the desired viewController - UIViewController *viewController = [self viewControllerAtIndex:activeContentIndex]; - - if (!viewController) { - viewController = [[UIViewController alloc] init]; - viewController.view = [[UIView alloc] init]; - viewController.view.backgroundColor = [UIColor clearColor]; - } - - // __weak pageViewController to be used in blocks to prevent retaining strong reference to self - __weak UIPageViewController *weakPageViewController = self.pageViewController; - __weak ViewPagerController *weakSelf = self; - - if (activeContentIndex == self.activeContentIndex) { - - [self.pageViewController setViewControllers:@[viewController] - direction:UIPageViewControllerNavigationDirectionForward - animated:NO - completion:^(BOOL completed) { - weakSelf.animatingToTab = NO; - }]; - - } else if (!(activeContentIndex + 1 == self.activeContentIndex || activeContentIndex - 1 == self.activeContentIndex)) { - - [self.pageViewController setViewControllers:@[viewController] - direction:(activeContentIndex < self.activeContentIndex) ? UIPageViewControllerNavigationDirectionReverse : UIPageViewControllerNavigationDirectionForward - animated:YES - completion:^(BOOL completed) { - - weakSelf.animatingToTab = NO; - - // Set the current page again to obtain synchronisation between tabs and content - dispatch_async(dispatch_get_main_queue(), ^{ - [weakPageViewController setViewControllers:@[viewController] - direction:(activeContentIndex < weakSelf.activeContentIndex) ? UIPageViewControllerNavigationDirectionReverse : UIPageViewControllerNavigationDirectionForward - animated:NO - completion:nil]; - }); - }]; - - } else { - - [self.pageViewController setViewControllers:@[viewController] - direction:(activeContentIndex < self.activeContentIndex) ? UIPageViewControllerNavigationDirectionReverse : UIPageViewControllerNavigationDirectionForward - animated:YES - completion:^(BOOL completed) { - weakSelf.animatingToTab = NO; - }]; - } - - // Clean out of sight contents - NSInteger index; - index = self.activeContentIndex - 1; - if (index >= 0 && - index != activeContentIndex && - index != activeContentIndex - 1) - { - [self.contents replaceObjectAtIndex:index withObject:[NSNull null]]; - } - index = self.activeContentIndex; - if (index != activeContentIndex - 1 && - index != activeContentIndex && - index != activeContentIndex + 1) - { - [self.contents replaceObjectAtIndex:index withObject:[NSNull null]]; - } - index = self.activeContentIndex + 1; - if (index < self.contents.count && - index != activeContentIndex && - index != activeContentIndex + 1) - { - [self.contents replaceObjectAtIndex:index withObject:[NSNull null]]; - } - - _activeContentIndex = activeContentIndex; -} - -#pragma mark - Getters -- (NSNumber *)tabHeight { - - if (!_tabHeight) { - CGFloat value = kTabHeight; - if ([self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) - value = [self.delegate viewPager:self valueForOption:ViewPagerOptionTabHeight withDefault:value]; - self.tabHeight = [NSNumber numberWithFloat:value]; - } - return _tabHeight; -} -- (NSNumber *)tabOffset { - - if (!_tabOffset) { - CGFloat value = kTabOffset; - if ([self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) - value = [self.delegate viewPager:self valueForOption:ViewPagerOptionTabOffset withDefault:value]; - self.tabOffset = [NSNumber numberWithFloat:value]; - } - return _tabOffset; -} -- (NSNumber *)tabWidth { - - if (!_tabWidth) { - CGFloat value = kTabWidth; - if ([self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) - value = [self.delegate viewPager:self valueForOption:ViewPagerOptionTabWidth withDefault:value]; - self.tabWidth = [NSNumber numberWithFloat:value]; - } - return _tabWidth; -} -- (NSNumber *)tabLocation { - - if (!_tabLocation) { - CGFloat value = kTabLocation; - if ([self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) - value = [self.delegate viewPager:self valueForOption:ViewPagerOptionTabLocation withDefault:value]; - self.tabLocation = [NSNumber numberWithFloat:value]; - } - return _tabLocation; -} -- (NSNumber *)startFromSecondTab { - - if (!_startFromSecondTab) { - CGFloat value = kStartFromSecondTab; - if ([self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) - value = [self.delegate viewPager:self valueForOption:ViewPagerOptionStartFromSecondTab withDefault:value]; - self.startFromSecondTab = [NSNumber numberWithFloat:value]; - } - return _startFromSecondTab; -} -- (NSNumber *)centerCurrentTab { - - if (!_centerCurrentTab) { - CGFloat value = kCenterCurrentTab; - if ([self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) - value = [self.delegate viewPager:self valueForOption:ViewPagerOptionCenterCurrentTab withDefault:value]; - self.centerCurrentTab = [NSNumber numberWithFloat:value]; - } - return _centerCurrentTab; -} -- (NSNumber *)fixFormerTabsPositions { - - if (!_fixFormerTabsPositions) { - CGFloat value = kFixFormerTabsPositions; - if ([self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) - value = [self.delegate viewPager:self valueForOption:ViewPagerOptionFixFormerTabsPositions withDefault:value]; - self.fixFormerTabsPositions = [NSNumber numberWithFloat:value]; - } - return _fixFormerTabsPositions; -} -- (NSNumber *)fixLatterTabsPositions { - - if (!_fixLatterTabsPositions) { - CGFloat value = kFixLatterTabsPositions; - if ([self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) - value = [self.delegate viewPager:self valueForOption:ViewPagerOptionFixLatterTabsPositions withDefault:value]; - self.fixLatterTabsPositions = [NSNumber numberWithFloat:value]; - } - return _fixLatterTabsPositions; -} - -- (UIColor *)indicatorColor { - - if (!_indicatorColor) { - UIColor *color = kIndicatorColor; - if ([self.delegate respondsToSelector:@selector(viewPager:colorForComponent:withDefault:)]) { - color = [self.delegate viewPager:self colorForComponent:ViewPagerIndicator withDefault:color]; - } - self.indicatorColor = color; - } - return _indicatorColor; -} -- (UIColor *)tabsViewBackgroundColor { - - if (!_tabsViewBackgroundColor) { - UIColor *color = kTabsViewBackgroundColor; - if ([self.delegate respondsToSelector:@selector(viewPager:colorForComponent:withDefault:)]) { - color = [self.delegate viewPager:self colorForComponent:ViewPagerTabsView withDefault:color]; - } - self.tabsViewBackgroundColor = color; - } - return _tabsViewBackgroundColor; -} -- (UIColor *)contentViewBackgroundColor { - - if (!_contentViewBackgroundColor) { - UIColor *color = kContentViewBackgroundColor; - if ([self.delegate respondsToSelector:@selector(viewPager:colorForComponent:withDefault:)]) { - color = [self.delegate viewPager:self colorForComponent:ViewPagerContent withDefault:color]; - } - self.contentViewBackgroundColor = color; - } - return _contentViewBackgroundColor; -} - -#pragma mark - Public methods -- (void)reloadData { - - // Empty all options and colors - // So that, ViewPager will reflect the changes - // Empty all options - _tabHeight = nil; - _tabOffset = nil; - _tabWidth = nil; - _tabLocation = nil; - _startFromSecondTab = nil; - _centerCurrentTab = nil; - _fixFormerTabsPositions = nil; - _fixLatterTabsPositions = nil; - - // Empty all colors - _indicatorColor = nil; - _tabsViewBackgroundColor = nil; - _contentViewBackgroundColor = nil; - - // Call to setup again with the updated data - [self defaultSetup]; -} - -- (void)selectTabAtIndex:(NSUInteger)index { - [self selectTabAtIndex:index didSwipe:NO]; -} - -- (void)selectTabAtIndex:(NSUInteger)index didSwipe:(BOOL)didSwipe { - - if (index >= self.tabCount) { - return; - } - - self.animatingToTab = YES; - - // Keep a reference to previousIndex in case it is needed for the delegate - NSUInteger previousIndex = self.activeTabIndex; - - // Set activeTabIndex - self.activeTabIndex = index; - - // Set activeContentIndex - self.activeContentIndex = index; - - // Inform delegate about the change - if ([self.delegate respondsToSelector:@selector(viewPager:didChangeTabToIndex:)]) { - [self.delegate viewPager:self didChangeTabToIndex:self.activeTabIndex]; - } - else if([self.delegate respondsToSelector:@selector(viewPager:didChangeTabToIndex:fromIndex:)]){ - [self.delegate viewPager:self didChangeTabToIndex:self.activeTabIndex fromIndex:previousIndex]; - } - else if ([self.delegate respondsToSelector:@selector(viewPager:didChangeTabToIndex:fromIndex:didSwipe:)]) { - [self.delegate viewPager:self didChangeTabToIndex:self.activeTabIndex fromIndex:previousIndex didSwipe:didSwipe]; - } -} - -- (void)setNeedsReloadOptions { - - // If our delegate doesn't respond to our options method, return - // Otherwise reload options - if (![self.delegate respondsToSelector:@selector(viewPager:valueForOption:withDefault:)]) { - return; - } - - // Update these options - self.tabWidth = [NSNumber numberWithFloat:[self.delegate viewPager:self valueForOption:ViewPagerOptionTabWidth withDefault:kTabWidth]]; - self.tabOffset = [NSNumber numberWithFloat:[self.delegate viewPager:self valueForOption:ViewPagerOptionTabOffset withDefault:kTabOffset]]; - self.centerCurrentTab = [NSNumber numberWithFloat:[self.delegate viewPager:self valueForOption:ViewPagerOptionCenterCurrentTab withDefault:kCenterCurrentTab]]; - self.fixFormerTabsPositions = [NSNumber numberWithFloat:[self.delegate viewPager:self valueForOption:ViewPagerOptionFixFormerTabsPositions withDefault:kFixFormerTabsPositions]]; - self.fixLatterTabsPositions = [NSNumber numberWithFloat:[self.delegate viewPager:self valueForOption:ViewPagerOptionFixLatterTabsPositions withDefault:kFixLatterTabsPositions]]; - - // We should update contentSize property of our tabsView, so we should recalculate it with the new values - CGFloat contentSizeWidth = 0; - - // Give the standard offset if fixFormerTabsPositions is provided as YES - if ([self.fixFormerTabsPositions boolValue]) { - - // And if the centerCurrentTab is provided as YES fine tune the offset according to it - if ([self.centerCurrentTab boolValue]) { - contentSizeWidth = (CGRectGetWidth(self.tabsView.frame) - [self.tabWidth floatValue]) / 2.0; - } else { - contentSizeWidth = [self.tabOffset floatValue]; - } - } - - // Update every tab's frame - for (NSUInteger i = 0; i < self.tabCount; i++) { - - UIView *tabView = [self tabViewAtIndex:i]; - - CGRect frame = tabView.frame; - frame.origin.x = contentSizeWidth; - frame.size.width = [self.tabWidth floatValue]; - tabView.frame = frame; - - contentSizeWidth += CGRectGetWidth(tabView.frame); - } - - // Extend contentSizeWidth if fixLatterTabsPositions is provided YES - if ([self.fixLatterTabsPositions boolValue]) { - - // And if the centerCurrentTab is provided as YES fine tune the content size according to it - if ([self.centerCurrentTab boolValue]) { - contentSizeWidth += (CGRectGetWidth(self.tabsView.frame) - [self.tabWidth floatValue]) / 2.0; - } else { - contentSizeWidth += CGRectGetWidth(self.tabsView.frame) - [self.tabWidth floatValue] - [self.tabOffset floatValue]; - } - } - - // Update tabsView's contentSize with the new width - self.tabsView.contentSize = CGSizeMake(contentSizeWidth, [self.tabHeight floatValue]); - -} -- (void)setNeedsReloadColors { - - // If our delegate doesn't respond to our colors method, return - // Otherwise reload colors - if (![self.delegate respondsToSelector:@selector(viewPager:colorForComponent:withDefault:)]) { - return; - } - - // These colors will be updated - UIColor *indicatorColor; - UIColor *tabsViewBackgroundColor; - UIColor *contentViewBackgroundColor; - - // Get indicatorColor and check if it is different from the current one - // If it is, update it - indicatorColor = [self.delegate viewPager:self colorForComponent:ViewPagerIndicator withDefault:kIndicatorColor]; - - if (![self.indicatorColor isEqualToColor:indicatorColor]) { - - // We will iterate through all of the tabs to update its indicatorColor - [self.tabs enumerateObjectsUsingBlock:^(TabView *tabView, NSUInteger index, BOOL *stop) { - tabView.indicatorColor = indicatorColor; - }]; - - // Update indicatorColor to check again later - self.indicatorColor = indicatorColor; - } - - // Get tabsViewBackgroundColor and check if it is different from the current one - // If it is, update it - tabsViewBackgroundColor = [self.delegate viewPager:self colorForComponent:ViewPagerTabsView withDefault:kTabsViewBackgroundColor]; - - if (![self.tabsViewBackgroundColor isEqualToColor:tabsViewBackgroundColor]) { - - // Update it - self.tabsView.backgroundColor = tabsViewBackgroundColor; - - // Update tabsViewBackgroundColor to check again later - self.tabsViewBackgroundColor = tabsViewBackgroundColor; - } - - // Get contentViewBackgroundColor and check if it is different from the current one - // Yeah update it, too - contentViewBackgroundColor = [self.delegate viewPager:self colorForComponent:ViewPagerContent withDefault:kContentViewBackgroundColor]; - - if (![self.contentViewBackgroundColor isEqualToColor:contentViewBackgroundColor]) { - - // Yup, update - self.contentView.backgroundColor = contentViewBackgroundColor; - - // Update this, too, to check again later - self.contentViewBackgroundColor = contentViewBackgroundColor; - } - -} - -- (CGFloat)valueForOption:(ViewPagerOption)option { - - switch (option) { - case ViewPagerOptionTabHeight: - return [[self tabHeight] floatValue]; - case ViewPagerOptionTabOffset: - return [[self tabOffset] floatValue]; - case ViewPagerOptionTabWidth: - return [[self tabWidth] floatValue]; - case ViewPagerOptionTabLocation: - return [[self tabLocation] floatValue]; - case ViewPagerOptionStartFromSecondTab: - return [[self startFromSecondTab] floatValue]; - case ViewPagerOptionCenterCurrentTab: - return [[self centerCurrentTab] floatValue]; - default: - return NAN; - } -} -- (UIColor *)colorForComponent:(ViewPagerComponent)component { - - switch (component) { - case ViewPagerIndicator: - return [self indicatorColor]; - case ViewPagerTabsView: - return [self tabsViewBackgroundColor]; - case ViewPagerContent: - return [self contentViewBackgroundColor]; - default: - return [UIColor clearColor]; - } -} - -#pragma mark - Private methods -- (void)defaultSettings { - - // pageViewController - self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll - navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal - options:nil]; - [self addChildViewController:self.pageViewController]; - - // Setup some forwarding events to hijack the scrollView - // Keep a reference to the actual delegate - self.actualDelegate = ((UIScrollView *)[self.pageViewController.view.subviews objectAtIndex:0]).delegate; - // Set self as new delegate - ((UIScrollView *)[self.pageViewController.view.subviews objectAtIndex:0]).delegate = self; - - self.pageViewController.dataSource = self; - self.pageViewController.delegate = self; - - self.animatingToTab = NO; - self.defaultSetupDone = NO; -} -- (void)defaultSetup { - - // Empty tabs and contents - for (UIView *tabView in self.tabs) { - [tabView removeFromSuperview]; - } - self.tabsView.contentSize = CGSizeZero; - - [self.tabs removeAllObjects]; - [self.contents removeAllObjects]; - - // Get tabCount from dataSource - self.tabCount = [self.dataSource numberOfTabsForViewPager:self]; - - // Populate arrays with [NSNull null]; - self.tabs = [NSMutableArray arrayWithCapacity:self.tabCount]; - for (NSUInteger i = 0; i < self.tabCount; i++) { - [self.tabs addObject:[NSNull null]]; - } - - self.contents = [NSMutableArray arrayWithCapacity:self.tabCount]; - for (NSUInteger i = 0; i < self.tabCount; i++) { - [self.contents addObject:[NSNull null]]; - } - - // Add tabsView - self.tabsView = (UIScrollView *)[self.view viewWithTag:kTabViewTag]; - - if (!self.tabsView) { - - self.tabsView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.frame), [self.tabHeight floatValue])]; - self.tabsView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - self.tabsView.backgroundColor = self.tabsViewBackgroundColor; - self.tabsView.scrollsToTop = NO; - self.tabsView.showsHorizontalScrollIndicator = NO; - self.tabsView.showsVerticalScrollIndicator = NO; - self.tabsView.tag = kTabViewTag; - - [self.view insertSubview:self.tabsView atIndex:0]; - } - - // Add tab views to _tabsView - CGFloat contentSizeWidth = 0; - - // Give the standard offset if fixFormerTabsPositions is provided as YES - if ([self.fixFormerTabsPositions boolValue]) { - - // And if the centerCurrentTab is provided as YES fine tune the offset according to it - if ([self.centerCurrentTab boolValue]) { - contentSizeWidth = (CGRectGetWidth(self.tabsView.frame) - [self.tabWidth floatValue]) / 2.0; - } else { - contentSizeWidth = [self.tabOffset floatValue]; - } - } - - for (NSUInteger i = 0; i < self.tabCount; i++) { - - UIView *tabView = [self tabViewAtIndex:i]; - - CGRect frame = tabView.frame; - frame.origin.x = contentSizeWidth; - frame.size.width = [self.tabWidth floatValue]; - tabView.frame = frame; - - [self.tabsView addSubview:tabView]; - - contentSizeWidth += CGRectGetWidth(tabView.frame); - - // To capture tap events - UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; - [tabView addGestureRecognizer:tapGestureRecognizer]; - } - - // Extend contentSizeWidth if fixLatterTabsPositions is provided YES - if ([self.fixLatterTabsPositions boolValue]) { - - // And if the centerCurrentTab is provided as YES fine tune the content size according to it - if ([self.centerCurrentTab boolValue]) { - contentSizeWidth += (CGRectGetWidth(self.tabsView.frame) - [self.tabWidth floatValue]) / 2.0; - } else { - contentSizeWidth += CGRectGetWidth(self.tabsView.frame) - [self.tabWidth floatValue] - [self.tabOffset floatValue]; - } - } - - self.tabsView.contentSize = CGSizeMake(contentSizeWidth, [self.tabHeight floatValue]); - - // Add contentView - self.contentView = [self.view viewWithTag:kContentViewTag]; - - if (!self.contentView) { - - self.contentView = self.pageViewController.view; - self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; - self.contentView.backgroundColor = self.contentViewBackgroundColor; - self.contentView.bounds = self.view.bounds; - self.contentView.tag = kContentViewTag; - - [self.view insertSubview:self.contentView atIndex:0]; - } - - // Select starting tab - NSUInteger index = [self.startFromSecondTab boolValue] ? 1 : 0; - [self selectTabAtIndex:index didSwipe:NO]; - - // Set setup done - self.defaultSetupDone = YES; -} - -- (TabView *)tabViewAtIndex:(NSUInteger)index { - - if (index >= self.tabCount) { - return nil; - } - - if ([[self.tabs objectAtIndex:index] isEqual:[NSNull null]]) { - - // Get view from dataSource - UIView *tabViewContent = [self.dataSource viewPager:self viewForTabAtIndex:index]; - tabViewContent.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; - - // Create TabView and subview the content - TabView *tabView = [[TabView alloc] initWithFrame:CGRectMake(0.0, 0.0, [self.tabWidth floatValue], [self.tabHeight floatValue])]; - [tabView addSubview:tabViewContent]; - [tabView setClipsToBounds:YES]; - [tabView setIndicatorColor:self.indicatorColor]; - - tabViewContent.center = tabView.center; - - // Replace the null object with tabView - [self.tabs replaceObjectAtIndex:index withObject:tabView]; - } - - return [self.tabs objectAtIndex:index]; -} -- (NSUInteger)indexForTabView:(UIView *)tabView { - - return [self.tabs indexOfObject:tabView]; -} - -- (UIViewController *)viewControllerAtIndex:(NSUInteger)index { - - if (index >= self.tabCount) { - return nil; - } - - if ([[self.contents objectAtIndex:index] isEqual:[NSNull null]]) { - - UIViewController *viewController; - - if ([self.dataSource respondsToSelector:@selector(viewPager:contentViewControllerForTabAtIndex:)]) { - viewController = [self.dataSource viewPager:self contentViewControllerForTabAtIndex:index]; - } else if ([self.dataSource respondsToSelector:@selector(viewPager:contentViewForTabAtIndex:)]) { - - UIView *view = [self.dataSource viewPager:self contentViewForTabAtIndex:index]; - - // Adjust view's bounds to match the pageView's bounds - UIView *pageView = [self.view viewWithTag:kContentViewTag]; - view.frame = pageView.bounds; - - viewController = [UIViewController new]; - viewController.view = view; - } else { - viewController = [[UIViewController alloc] init]; - viewController.view = [[UIView alloc] init]; - } - - [self.contents replaceObjectAtIndex:index withObject:viewController]; - } - - return [self.contents objectAtIndex:index]; -} -- (NSUInteger)indexForViewController:(UIViewController *)viewController { - - return [self.contents indexOfObject:viewController]; -} - -#pragma mark - UIPageViewControllerDataSource -- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController { - NSUInteger index = [self indexForViewController:viewController]; - index++; - return [self viewControllerAtIndex:index]; -} -- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController { - NSUInteger index = [self indexForViewController:viewController]; - index--; - return [self viewControllerAtIndex:index]; -} - -#pragma mark - UIPageViewControllerDelegate -- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed { - - UIViewController *viewController = self.pageViewController.viewControllers[0]; - - // Select tab - NSUInteger index = [self indexForViewController:viewController]; - [self selectTabAtIndex:index didSwipe:YES]; -} - -#pragma mark - UIScrollViewDelegate, Responding to Scrolling and Dragging -- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - - if ([self.actualDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) { - [self.actualDelegate scrollViewDidScroll:scrollView]; - } - - if (![self isAnimatingToTab]) { - UIView *tabView = [self tabViewAtIndex:self.activeTabIndex]; - - // Get the related tab view position - CGRect frame = tabView.frame; - - CGFloat movedRatio = (scrollView.contentOffset.x / CGRectGetWidth(scrollView.frame)) - 1; - frame.origin.x += movedRatio * CGRectGetWidth(frame); - - if ([self.centerCurrentTab boolValue]) { - - frame.origin.x += (frame.size.width / 2); - frame.origin.x -= CGRectGetWidth(self.tabsView.frame) / 2; - frame.size.width = CGRectGetWidth(self.tabsView.frame); - - if (frame.origin.x < 0) { - frame.origin.x = 0; - } - - if ((frame.origin.x + frame.size.width) > self.tabsView.contentSize.width) { - frame.origin.x = (self.tabsView.contentSize.width - CGRectGetWidth(self.tabsView.frame)); - } - } else { - - frame.origin.x -= [self.tabOffset floatValue]; - frame.size.width = CGRectGetWidth(self.tabsView.frame); - } - - [self.tabsView scrollRectToVisible:frame animated:NO]; - } -} -- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) { - [self.actualDelegate scrollViewWillBeginDragging:scrollView]; - } -} -- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) { - [self.actualDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset]; - } -} -- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ - if ([self.actualDelegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]) { - [self.actualDelegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate]; - } -} -- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView{ - if ([self.actualDelegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)]) { - return [self.actualDelegate scrollViewShouldScrollToTop:scrollView]; - } - return NO; -} -- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewDidScrollToTop:)]) { - [self.actualDelegate scrollViewDidScrollToTop:scrollView]; - } -} -- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)]) { - [self.actualDelegate scrollViewWillBeginDecelerating:scrollView]; - } -} -- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) { - [self.actualDelegate scrollViewDidEndDecelerating:scrollView]; - } -} - -#pragma mark - UIScrollViewDelegate, Managing Zooming -- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { - if ([self.actualDelegate respondsToSelector:@selector(viewForZoomingInScrollView:)]) { - return [self.actualDelegate viewForZoomingInScrollView:scrollView]; - } - return nil; -} -- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewWillBeginZooming:withView:)]) { - [self.actualDelegate scrollViewWillBeginZooming:scrollView withView:view]; - } -} -- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)]) { - [self.actualDelegate scrollViewDidEndZooming:scrollView withView:view atScale:scale]; - } -} -- (void)scrollViewDidZoom:(UIScrollView *)scrollView { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewDidZoom:)]) { - [self.actualDelegate scrollViewDidZoom:scrollView]; - } -} - -#pragma mark - UIScrollViewDelegate, Responding to Scrolling Animations -- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { - if ([self.actualDelegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) { - [self.actualDelegate scrollViewDidEndScrollingAnimation:scrollView]; - } -} - -@end - diff --git a/ICViewPager/Legacy/iPad.storyboard b/ICViewPager/Legacy/iPad.storyboard deleted file mode 100644 index c425f6c..0000000 --- a/ICViewPager/Legacy/iPad.storyboard +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ICViewPager/Legacy/iPhone.storyboard b/ICViewPager/Legacy/iPhone.storyboard deleted file mode 100644 index e35b3ad..0000000 --- a/ICViewPager/Legacy/iPhone.storyboard +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Resources/Screenshot.jpg b/Resources/Screenshot.jpg deleted file mode 100644 index bc79d17e1775a8798cf0586ad3d81c5fa8082437..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6958 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�CQ?iG6M8@(Df=8W~fsFb<9 zi>FCviC!E*IUMlYb{W1oT}f*jKxS$CcczqCb9 zaSG+=rV2*m{p z(-${CX20L@yrFI8&?sfM+KhY^be0_lR%-{laVse7Acts8rf0L*N_cegPv$XK8`4I& zss(X-ndKOlS^H|uQza$2+U(}p(k`(wGn#B>LCsm%D?VB)Mdswzxg=uDj9P48kO?KT zxP%G3`%m<3b%bfPVNG5v=XW0l)xP9avUdd{|M<*`k0o_4J46^~;r zq=NX{jNK_`8u{C*LyXuFb`BcJ{Ome@0Io8Y1zd+vah9P(KU;ek`_6K;5h>ez^7u+`iH z$#l2cw+xH;@kB9*Rsu%7*d)wFtu5ecCbo*Y_e8Rchss?9XY8VzZWD<$-2d$T=axQ= zeJZ7b&(D42VjG(DF`O_~*`2l|u5n-bj|zIN^z06w9X_a1Tq`I9=~2wtRU6HZVC*_S z4&IaVs3-j*0d6kazY>u-z0eoKA>bQX&UhrAS#RL+MrYR(x~Ruh`m?p~8jnaCz3Mf# z8oRUF&Zmau$35a4U~^@&Hhv-30WuD?(YzH}+-13o%};`~Zb&ecZJv}@f$`XsQC3W6 z6<@pwa`JTH3z4#anhtq&6Av(Q!ph7tGp(m}$$W63u}5xNen)#4qtFYVu2itTU# z6Fia^&LlnS%QbK+Qk1rA_L=v}zXsuca!I+xOAKjt5C*(;I8Aq5OK1 z&INyNBR{}RvW7}a&lAzj!sm|-Wv3$VXQh|GehDh&2=o%1MW*vxf?TmlpR;d@(pK`=#r&<*kO1U!H`N;Wmn!LF2N|bt1QzzN5ssVCbXGOHny+t3L7uxCmFvG2e#~YI7Vt9V4m@{mS`Gu@B zEQN^V`R*PWLq}_J-R5i!PjxU_4v31f8m=fe%qEW19cJ;@*VM3J9Wc!MG_wxa`!01FVP3fuzW;gOIsLl1I@XPe9EF2# X@BJP~##HPor~^0={ht+}^{4* Date: Mon, 21 May 2018 15:05:18 +0400 Subject: [PATCH 21/28] Update Readme --- README.md | 155 +++++------------------------------------------------- 1 file changed, 12 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 18466d6..82afa45 100644 --- a/README.md +++ b/README.md @@ -1,151 +1,20 @@ -ICViewPager +ViewPager 2.0 =========== -You can create sliding tabs with ViewPager. +Sliding tab implemetation for iOS. -Slide through the contents or select from tabs or slide through tabs and select! +Version 2.0 is written from scratch and still under heavy development. You can check the progress from the following Todo list -ICViewPager +## Todo -## Installation - -Just copy ViewPagerController.m and ViewPagerController.h files to your project. - -Or you can use CocoaPods (as this is the recommended way). - -`pod 'ICViewPager'` - -## Usage - -Subclass ViewPagerController (as it's a `UIViewController` subclass) and implement dataSource and delegate methods in the subclass. - -In the subclass assign self as dataSource and delegate, - -``` -- (void)viewDidLoad { - - [super viewDidLoad]; - - self.dataSource = self; - self.delegate = self; -} -``` - -### Methods - -Then implement dataSource and delegate methods. -``` -#pragma mark - ViewPagerDataSource -- (NSUInteger)numberOfTabsForViewPager:(ViewPagerController *)viewPager { - return 10; -} -``` -Returns the number of tabs that will be present in ViewPager. - -``` -#pragma mark - ViewPagerDataSource -- (UIView *)viewPager:(ViewPagerController *)viewPager viewForTabAtIndex:(NSUInteger)index { - - UILabel *label = [UILabel new]; - label.text = [NSString stringWithFormat:@"Tab #%i", index]; - [label sizeToFit]; - - return label; -} -``` -Returns the view that will be shown as tab. Create a `UIView` object (or any `UIView` subclass object) and give it to ViewPager and it will use it as tab view. - -``` -#pragma mark - ViewPagerDataSource -- (UIViewController *)viewPager:(ViewPagerController *)viewPager contentViewControllerForTabAtIndex:(NSUInteger)index { - - ContentViewController *cvc = [self.storyboard instantiateViewControllerWithIdentifier:@"contentViewController"]; - - return cvc; -} -``` -Returns the view controller that will be shown as content. Create a `UIViewController` object (or any `UIViewController` subclass object) and give it to ViewPager and it will use the `view` property of the view controller as content view. - -Alternatively, you can implement `- viewPager:contentViewForTabAtIndex:` method and return a `UIView` object (or any `UIView` subclass object) and ViewPager will use it as content view. - -The `- viewPager:contentViewControllerForTabAtIndex:` and `- viewPager:contentViewForTabAtIndex:` dataSource methods are both defined optional. But, you should implement at least one of them! They are defined as optional to provide you an option. - -All delegate methods are optional. - -``` -#pragma mark - ViewPagerDelegate -- (void)viewPager:(ViewPagerController *)viewPager didChangeTabToIndex:(NSUInteger)index { - - // Do something useful -} -``` -ViewPager will alert your delegate object via `- viewPager:didChangeTabToIndex:` method, so that you can do something useful. - -``` -#pragma mark - ViewPagerDelegate -- (CGFloat)viewPager:(ViewPagerController *)viewPager valueForOption:(ViewPagerOption)option withDefault:(CGFloat)value { - - switch (option) { - case ViewPagerOptionStartFromSecondTab: - return 0.0; - case ViewPagerOptionCenterCurrentTab: - return 0.0; - case ViewPagerOptionTabLocation: - return 0.0; - default: - return value; - } -} -``` -You can change ViewPager's options via `viewPager:valueForOption:withDefault:` delegate method. Just return the desired value for the given option. You don't have to return a value for every option. Only return values for the interested options and ViewPager will use the default values for the rest. Available options are defined in the `ViewPagerController.h` file and described below. - -``` -#pragma mark - ViewPagerDelegate -- (UIColor *)viewPager:(ViewPagerController *)viewPager colorForComponent:(ViewPagerComponent)component withDefault:(UIColor *)color { - - switch (component) { - case ViewPagerIndicator: - return [[UIColor redColor] colorWithAlphaComponent:0.64]; - default: - return color; - } -} -``` -You can change some colors too. Just like options, return the interested component's color, and leave out all the rest! [Link](http://www.youtube.com/watch?v=LBTXNPZPfbE) - -### Options - -Every option has a default value. So - - * `ViewPagerOptionTabHeight`: Tab bar's height, defaults to 44.0 - * `ViewPagerOptionTabOffset`: Tab bar's offset from left, defaults to 56.0 - * `ViewPagerOptionTabWidth`: Any tab item's width, defaults to 128.0 - * `ViewPagerOptionTabLocation`: 1.0: Top, 0.0: Bottom, Defaults to Top - * `ViewPagerOptionStartFromSecondTab`: 1.0: `YES`, 0.0: `NO`, defines if view should appear with the 1st or 2nd tab. Defaults to `NO` - * `ViewPagerOptionCenterCurrentTab`: 1.0: `YES`, 0.0: `NO`, defines if tabs should be centered, with the given tabWidth. Defaults to `NO` - * `ViewPagerOptionFixFormerTabsPositions`: 1.0: `YES`, 0.0: `NO`, defines if the active tab should be placed margined by the offset amount to the left. Effects only the former tabs. If set 1.0 (`YES`), first tab will be placed at the same position with the second one, leaving space before itself. Defaults to `NO` - * `ViewPagerOptionFixLatterTabsPositions`: 1.0: `YES`, 0.0: `NO`, like `ViewPagerOptionFixFormerTabsPositions`, but effects the latter tabs, making them leave space after themselves. Defaults to `NO` - -### Components - -Main parts of the ViewPagerController - - * `ViewPagerIndicator`: The colored line in the view of the active tab. - * `ViewPagerTabsView`: The tabs view itself. When used in `- viewPager:colorForComponent:withDefault:` method, the returned color will be used as background color for the tab view. - * `ViewPagerContent`: Provided views goes here as content. When used in `- viewPager:colorForComponent:withDefault:` method, the returned color will be used as background color for the content view. - -## Requirements - -ViewPager supports minimum iOS 6 and uses ARC. - -Supports both iPhone and iPad. +- [ ] Auto sizing tabs +- [ ] Tab location setting support (top/bottom) +- [ ] Tab centering support (center active/selected tab) +- [ ] Polishing +- [ ] CocoaPods support +- [ ] Carthage support +- [ ] ... ## Contact -[@iltercengiz](https://twitter.com/iltercengiz) - -[Ilter Cengiz](mailto:me@iltercengiz.info) - -Note (to everyone who is interested in `ViewPager`): I cannot have much time to improve `ViewPager` for a long time, but I have some cool plans for it. So if you encounter any problems, bugs or etc. please forgive me, and send some pull requests. Thank you for your interest and support. -## Licence -ICViewPager is MIT licensed. See the LICENCE file for more info. +[Ilter Cengiz](mailto:iltercengiz@yahoo.com) / [@iltercengiz](https://twitter.com/iltercengiz) From 17f45ee932948b67782976be933a1730b26d7d4f Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Mon, 21 May 2018 23:55:27 +0400 Subject: [PATCH 22/28] Update Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 82afa45..8f2f52b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Version 2.0 is written from scratch and still under heavy development. You can c - [ ] Auto sizing tabs - [ ] Tab location setting support (top/bottom) - [ ] Tab centering support (center active/selected tab) +- [ ] Custom tab indicator color support - [ ] Polishing - [ ] CocoaPods support - [ ] Carthage support From 9faafabc592d9eadab63812e238495a972dd602e Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Tue, 22 May 2018 00:47:24 +0400 Subject: [PATCH 23/28] Add customizable color support for tab indicator --- ICViewPager.xcodeproj/project.pbxproj | 20 ++++++++--- .../Application/ApplicationDelegate.swift | 3 +- .../Tab/ActiveTabIndicatorView.swift | 30 ---------------- .../Tab/TabCollectionViewLayout.swift | 21 ++++++------ .../TabIndicator/TabIndicatorAttributes.swift | 34 +++++++++++++++++++ .../Tab/TabIndicator/TabIndicatorView.swift | 24 +++++++++++++ .../ICViewPager/ViewPagerConfiguration.swift | 5 ++- .../ICViewPager/ViewPagerController.swift | 1 + 8 files changed, 91 insertions(+), 47 deletions(-) delete mode 100644 ICViewPager/ICViewPager/Tab/ActiveTabIndicatorView.swift create mode 100644 ICViewPager/ICViewPager/Tab/TabIndicator/TabIndicatorAttributes.swift create mode 100644 ICViewPager/ICViewPager/Tab/TabIndicator/TabIndicatorView.swift diff --git a/ICViewPager.xcodeproj/project.pbxproj b/ICViewPager.xcodeproj/project.pbxproj index 34b4b25..a168750 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 365567DA20B0BD7100D5C00F /* ActiveTabIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 365567D920B0BD7100D5C00F /* ActiveTabIndicatorView.swift */; }; + 365567DA20B0BD7100D5C00F /* TabIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 365567D920B0BD7100D5C00F /* TabIndicatorView.swift */; }; 36B1150020AF91E200DA4621 /* TabCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */; }; 36B1151320AF926700DA4621 /* TabItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151220AF926700DA4621 /* TabItemView.swift */; }; 36B1151520AF92F900DA4621 /* TabCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */; }; @@ -31,10 +31,11 @@ 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */; }; 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */; }; 36F4A3C120AF4F8A000995B2 /* ViewPagerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */; }; + 36FA1A1E20B35F6D0086BCD9 /* TabIndicatorAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FA1A1D20B35F6D0086BCD9 /* TabIndicatorAttributes.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 365567D920B0BD7100D5C00F /* ActiveTabIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveTabIndicatorView.swift; sourceTree = ""; }; + 365567D920B0BD7100D5C00F /* TabIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabIndicatorView.swift; sourceTree = ""; }; 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewCell.swift; sourceTree = ""; }; 36B1151220AF926700DA4621 /* TabItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItemView.swift; sourceTree = ""; }; 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabCollectionViewDataSource.swift; sourceTree = ""; }; @@ -58,6 +59,7 @@ 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyViewController.swift; sourceTree = ""; }; 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPagerConfiguration.swift; sourceTree = ""; }; + 36FA1A1D20B35F6D0086BCD9 /* TabIndicatorAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabIndicatorAttributes.swift; sourceTree = ""; }; 7CF3D65117CE32E40021036A /* ICViewPager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ICViewPager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7CF3D65C17CE32E40021036A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ @@ -104,12 +106,12 @@ 36CB295220AF82590054261E /* Tab */ = { isa = PBXGroup; children = ( + 36FA1A1C20B35F550086BCD9 /* TabIndicator */, 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */, 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */, 36B1151220AF926700DA4621 /* TabItemView.swift */, 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */, 36B1151820AFA0CF00DA4621 /* TabCollectionViewDelegate.swift */, - 365567D920B0BD7100D5C00F /* ActiveTabIndicatorView.swift */, 36B1151620AF9FEB00DA4621 /* DefaultTabItemView.swift */, ); path = Tab; @@ -165,6 +167,15 @@ path = ICViewPager; sourceTree = ""; }; + 36FA1A1C20B35F550086BCD9 /* TabIndicator */ = { + isa = PBXGroup; + children = ( + 365567D920B0BD7100D5C00F /* TabIndicatorView.swift */, + 36FA1A1D20B35F6D0086BCD9 /* TabIndicatorAttributes.swift */, + ); + path = TabIndicator; + sourceTree = ""; + }; 7CF3D64817CE32E40021036A = { isa = PBXGroup; children = ( @@ -267,9 +278,10 @@ 36CB293620AF5A610054261E /* ContentCollectionViewLayout.swift in Sources */, 36CB294720AF628F0054261E /* ViewPagerControllerDataSource.swift in Sources */, 36B1151720AF9FEB00DA4621 /* DefaultTabItemView.swift in Sources */, + 36FA1A1E20B35F6D0086BCD9 /* TabIndicatorAttributes.swift in Sources */, 36B1151320AF926700DA4621 /* TabItemView.swift in Sources */, 36CB293420AF5A4D0054261E /* TabCollectionViewLayout.swift in Sources */, - 365567DA20B0BD7100D5C00F /* ActiveTabIndicatorView.swift in Sources */, + 365567DA20B0BD7100D5C00F /* TabIndicatorView.swift in Sources */, 36CB294020AF5F1D0054261E /* ContentCollectionViewCell.swift in Sources */, 36B1152920B0920C00DA4621 /* ScrollController.swift in Sources */, 36F4A3B620AF0EF9000995B2 /* EmptyViewController.swift in Sources */, diff --git a/ICViewPager/Application/ApplicationDelegate.swift b/ICViewPager/Application/ApplicationDelegate.swift index d4af203..c06779e 100644 --- a/ICViewPager/Application/ApplicationDelegate.swift +++ b/ICViewPager/Application/ApplicationDelegate.swift @@ -37,7 +37,8 @@ class ApplicationDelegate: UIResponder, UIApplicationDelegate, UISplitViewContro /** ViewPagerController configuration here. All the configuration properties are optional. */ let configuration = ViewPagerConfiguration(tabHeight: 48.0, - tabItemSizingPolicy: .fill) + tabItemSizingPolicy: .fill, + tabIndicatorColor: #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)) let viewPagerController = ViewPagerController(configuration: configuration) viewPagerController.dataSource = dataSource diff --git a/ICViewPager/ICViewPager/Tab/ActiveTabIndicatorView.swift b/ICViewPager/ICViewPager/Tab/ActiveTabIndicatorView.swift deleted file mode 100644 index 1391071..0000000 --- a/ICViewPager/ICViewPager/Tab/ActiveTabIndicatorView.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// ActiveTabIndicatorView.swift -// ICViewPager -// -// Created by Ilter Cengiz on 20/5/18. -// Copyright © 2018 Ilter Cengiz. All rights reserved. -// - -import UIKit - -final class ActiveTabIndicatorView: UICollectionReusableView { - - class var kind: String { - return "\(ActiveTabIndicatorView.self)" - } - - override init(frame: CGRect) { - super.init(frame: frame) - setUpUI() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - setUpUI() - } - - private func setUpUI() { - backgroundColor = .red - } -} diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift index d7e8a2b..b4d9175 100644 --- a/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift @@ -11,19 +11,20 @@ import UIKit final class TabCollectionViewLayout: UICollectionViewFlowLayout { private enum Constants { - static let indicatorIndexPath: IndexPath = IndexPath(item: 0, section: 0) static let indicatorHeight: CGFloat = 2.0 } - private var indicatorAttributes: UICollectionViewLayoutAttributes! + private var indicatorAttributes: TabIndicatorAttributes! private var invalidationContext: UICollectionViewFlowLayoutInvalidationContext = { let context = UICollectionViewFlowLayoutInvalidationContext() context.invalidateFlowLayoutAttributes = false context.invalidateFlowLayoutDelegateMetrics = false - context.invalidateDecorationElements(ofKind: ActiveTabIndicatorView.kind, at: [Constants.indicatorIndexPath]) + context.invalidateDecorationElements(ofKind: TabIndicatorView.kind, + at: [TabIndicatorAttributes.Constants.indicatorIndexPath]) return context }() + var configuration: ViewPagerConfiguration! var currentPage: Int = 0 // MARK: Init @@ -55,7 +56,7 @@ final class TabCollectionViewLayout: UICollectionViewFlowLayout { override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { - guard elementKind == ActiveTabIndicatorView.kind else { return nil } + guard elementKind == TabIndicatorView.kind else { return nil } return indicatorAttributes } @@ -108,26 +109,24 @@ private extension TabCollectionViewLayout { } func registerDecorationView() { - register(ActiveTabIndicatorView.self, - forDecorationViewOfKind: ActiveTabIndicatorView.kind) + register(TabIndicatorView.self, + forDecorationViewOfKind: TabIndicatorView.kind) } - func indicatorAttributes(for page: Int) -> UICollectionViewLayoutAttributes { + func indicatorAttributes(for page: Int) -> TabIndicatorAttributes { guard let tabItemAttributes = layoutAttributesForItem(at: IndexPath(item: page, section: 0)) else { #if DEBUG NSLog("Called `indicatorAttributes(for:)` before super did its preparations.") #endif - return UICollectionViewLayoutAttributes() + return TabIndicatorAttributes() } let tabItemFrame = tabItemAttributes.frame - let indicatorAttributes = UICollectionViewLayoutAttributes(forDecorationViewOfKind: ActiveTabIndicatorView.kind, - with: Constants.indicatorIndexPath) + let indicatorAttributes = TabIndicatorAttributes(backgroundColor: configuration.tabIndicatorColor) indicatorAttributes.frame = CGRect(x: tabItemFrame.minX, y: tabItemFrame.maxY - Constants.indicatorHeight, width: tabItemFrame.width, height: Constants.indicatorHeight) - indicatorAttributes.zIndex = Int.max return indicatorAttributes } } diff --git a/ICViewPager/ICViewPager/Tab/TabIndicator/TabIndicatorAttributes.swift b/ICViewPager/ICViewPager/Tab/TabIndicator/TabIndicatorAttributes.swift new file mode 100644 index 0000000..8966224 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabIndicator/TabIndicatorAttributes.swift @@ -0,0 +1,34 @@ +// +// TabIndicatorAttributes.swift +// ICViewPager +// +// Created by Ilter Cengiz on 22/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class TabIndicatorAttributes: UICollectionViewLayoutAttributes { + + enum Constants { + static let indicatorIndexPath: IndexPath = IndexPath(item: 0, section: 0) + } + + private(set) var backgroundColor: UIColor = .black + /** To be able to have the following `init(backgroundColor:)`, this `backgroundColor` property must have + a default value, as all the `init` functions are defined as `convenience`, except the one that's + inherited from `NSObject` which is pure `init()`. */ + + convenience init(backgroundColor: UIColor) { + self.init(forDecorationViewOfKind: TabIndicatorView.kind, + with: Constants.indicatorIndexPath) + self.backgroundColor = backgroundColor + } +} + +private extension TabIndicatorAttributes { + + func setUpAttributes() { + zIndex = .max + } +} diff --git a/ICViewPager/ICViewPager/Tab/TabIndicator/TabIndicatorView.swift b/ICViewPager/ICViewPager/Tab/TabIndicator/TabIndicatorView.swift new file mode 100644 index 0000000..cde5004 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabIndicator/TabIndicatorView.swift @@ -0,0 +1,24 @@ +// +// ActiveTabIndicatorView.swift +// ICViewPager +// +// Created by Ilter Cengiz on 20/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class TabIndicatorView: UICollectionReusableView { + + class var kind: String { + return "\(TabIndicatorView.self)" + } + + // MARK: Applying layout attributes + + override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { + super.apply(layoutAttributes) + guard let attributes = layoutAttributes as? TabIndicatorAttributes else { return } + backgroundColor = attributes.backgroundColor + } +} diff --git a/ICViewPager/ICViewPager/ViewPagerConfiguration.swift b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift index e3c236b..218e6b0 100644 --- a/ICViewPager/ICViewPager/ViewPagerConfiguration.swift +++ b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift @@ -23,10 +23,13 @@ public struct ViewPagerConfiguration { public var tabHeight: CGFloat public var tabItemSizingPolicy: TabItemSizingPolicy + public var tabIndicatorColor: UIColor public init(tabHeight: CGFloat = Constants.tabHeight, - tabItemSizingPolicy: TabItemSizingPolicy = .fixed(size: TabItemSizingPolicy.defaultTabWidth)) { + tabItemSizingPolicy: TabItemSizingPolicy = .fixed(size: TabItemSizingPolicy.defaultTabWidth), + tabIndicatorColor: UIColor = .red) { self.tabHeight = tabHeight self.tabItemSizingPolicy = tabItemSizingPolicy + self.tabIndicatorColor = tabIndicatorColor } } diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index 657c235..5b0458f 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -89,6 +89,7 @@ private extension ViewPagerController { tabCollectionViewDelegate.delegate = scrollController collectionView.dataSource = tabCollectionViewDataSource collectionView.delegate = tabCollectionViewDelegate + tabCollectionViewLayout.configuration = configuration } func applyConfiguration(_ configuration: ViewPagerConfiguration) { From 535dc6a0eedf0822ef37c7fd625dc0c3e52b055e Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Tue, 22 May 2018 00:49:49 +0400 Subject: [PATCH 24/28] Update Readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f2f52b..31dff9d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,10 @@ Version 2.0 is written from scratch and still under heavy development. You can c - [ ] Auto sizing tabs - [ ] Tab location setting support (top/bottom) - [ ] Tab centering support (center active/selected tab) -- [ ] Custom tab indicator color support +- [x] Custom tab indicator color support +- [ ] Scroll performance and experience improvements +- [ ] Better dependency management (maybe a central container?) +- [ ] Layout improvements - [ ] Polishing - [ ] CocoaPods support - [ ] Carthage support From 579d80a2a31fa7f7da311882c440a4b20b5859be Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sun, 3 Jun 2018 02:17:03 +0300 Subject: [PATCH 25/28] Fix empty data source case --- .../Content/ContentCollectionViewDataSource.swift | 6 ++++-- .../Tab/TabCollectionViewDataSource.swift | 11 +++++++++-- .../ICViewPager/Tab/TabCollectionViewLayout.swift | 14 ++++++++------ ICViewPager/ICViewPager/ViewPagerController.swift | 7 ++++++- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift index 410c34e..2ee7f5b 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift @@ -17,7 +17,9 @@ final class ContentCollectionViewDataSource: NSObject { private unowned var viewPagerController: ViewPagerController private unowned var collectionView: UICollectionView private var viewControllerCache: [Int: UIViewController] = [:] - weak var dataSource: ViewPagerControllerDataSource? + weak var dataSource: ViewPagerControllerDataSource? { + didSet { collectionView.reloadData() } + } // MARK: Init @@ -87,7 +89,7 @@ extension ContentCollectionViewDataSource: UICollectionViewDataSource { numberOfItemsInSection section: Int) -> Int { guard let dataSource = dataSource else { - fatalError("ViewPagerControllerDataSource is not provided!") + return 0 } return dataSource.numberOfViews(in: viewPagerController) diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift index 340df78..c4328d2 100644 --- a/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift @@ -16,7 +16,9 @@ final class TabCollectionViewDataSource: NSObject { private unowned var viewPagerController: ViewPagerController private unowned var collectionView: UICollectionView - weak var dataSource: ViewPagerControllerDataSource? + weak var dataSource: ViewPagerControllerDataSource? { + didSet { collectionView.reloadData() } + } var numberOfViews: Int = 0 // MARK: Init @@ -64,10 +66,15 @@ extension TabCollectionViewDataSource: UICollectionViewDataSource { numberOfItemsInSection section: Int) -> Int { guard let dataSource = dataSource else { - fatalError("ViewPagerControllerDataSource is not provided!") + return 0 } numberOfViews = dataSource.numberOfViews(in: viewPagerController) + + if let layout = collectionView.collectionViewLayout as? TabCollectionViewLayout { + layout.numberOfViews = numberOfViews + } + return numberOfViews } } diff --git a/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift index b4d9175..938d191 100644 --- a/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift @@ -26,6 +26,7 @@ final class TabCollectionViewLayout: UICollectionViewFlowLayout { var configuration: ViewPagerConfiguration! var currentPage: Int = 0 + var numberOfViews: Int = 0 // MARK: Init @@ -45,12 +46,16 @@ final class TabCollectionViewLayout: UICollectionViewFlowLayout { override func prepare() { super.prepare() - indicatorAttributes = indicatorAttributes(for: currentPage) + if numberOfViews > 0 { + indicatorAttributes = indicatorAttributes(for: currentPage) + } } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var attributes = super.layoutAttributesForElements(in: rect) - attributes?.append(indicatorAttributes) + if numberOfViews > 0 { + attributes?.append(indicatorAttributes) + } return attributes } @@ -116,10 +121,7 @@ private extension TabCollectionViewLayout { func indicatorAttributes(for page: Int) -> TabIndicatorAttributes { guard let tabItemAttributes = layoutAttributesForItem(at: IndexPath(item: page, section: 0)) else { - #if DEBUG - NSLog("Called `indicatorAttributes(for:)` before super did its preparations.") - #endif - return TabIndicatorAttributes() + fatalError("Called `indicatorAttributes(for:)` before super did its preparations.") } let tabItemFrame = tabItemAttributes.frame diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index 5b0458f..51540e5 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -23,7 +23,12 @@ final public class ViewPagerController: UIViewController { internal var tabCollectionViewDelegate: TabCollectionViewDelegate! internal var scrollController: ScrollController! - public weak var dataSource: ViewPagerControllerDataSource? + public weak var dataSource: ViewPagerControllerDataSource? { + didSet { + tabCollectionViewDataSource?.dataSource = dataSource + contentCollectionViewDataSource?.dataSource = dataSource + } + } public var configuration: ViewPagerConfiguration // MARK: Init From e0cccd6c8e46f3a1aa1a624e063714b4792a1005 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sun, 3 Jun 2018 11:35:01 +0300 Subject: [PATCH 26/28] Minor refactors --- .../ContentCollectionViewDataSource.swift | 2 +- .../ICViewPager/Tab/DefaultTabItemView.swift | 20 +++++++++++++------ .../ICViewPager/ViewPagerConfiguration.swift | 5 +++-- .../ICViewPager/ViewPagerController.swift | 14 ++++++------- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift index 2ee7f5b..eadf31f 100644 --- a/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift @@ -58,7 +58,7 @@ private extension ContentCollectionViewDataSource { } else { let topInset = viewPagerController.topLayoutGuide.length + viewPagerController.configuration.tabHeight let bottomInset = viewPagerController.bottomLayoutGuide.length - let insets = UIEdgeInsetsMake(topInset, 0.0, bottomInset, 0.0) + let insets = UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomInset, right: 0.0) viewController.adjustScrollViewInsets(insets: insets) } diff --git a/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift b/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift index a4d1689..9a439af 100644 --- a/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift +++ b/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift @@ -8,10 +8,14 @@ import UIKit -final class DefaultTabItemView: TabItemView { +public final class DefaultTabItemView: TabItemView { - override var intrinsicContentSize: CGSize { - return CGSize(width: 144.0, height: 44.0) + private enum Constants { + static let defaultTabItemSize = CGSize(width: 144.0, height: 44.0) + } + + public override var intrinsicContentSize: CGSize { + return Constants.defaultTabItemSize } private var label: UILabel @@ -21,20 +25,24 @@ final class DefaultTabItemView: TabItemView { } } - init(title: String) { + public init(title: String) { label = UILabel() self.title = title super.init(frame: .zero) setUpUI() } - required init?(coder aDecoder: NSCoder) { + required public init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } +} + +private extension DefaultTabItemView { - private func setUpUI() { + func setUpUI() { backgroundColor = .white + label.font = UIFont.boldSystemFont(ofSize: 14.0) label.text = title label.textAlignment = .center label.textColor = .black diff --git a/ICViewPager/ICViewPager/ViewPagerConfiguration.swift b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift index 218e6b0..e2612b9 100644 --- a/ICViewPager/ICViewPager/ViewPagerConfiguration.swift +++ b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift @@ -12,10 +12,11 @@ public struct ViewPagerConfiguration { public struct Constants { public static let tabHeight: CGFloat = 44.0 + fileprivate static let defaultTabSize = CGSize(width: 144.0, height: Constants.tabHeight) } public enum TabItemSizingPolicy { - public static let defaultTabWidth: CGSize = CGSize(width: 144.0, height: Constants.tabHeight) + public static let defaultTabSize: CGSize = Constants.defaultTabSize case fixed(size: CGSize) case fill @@ -26,7 +27,7 @@ public struct ViewPagerConfiguration { public var tabIndicatorColor: UIColor public init(tabHeight: CGFloat = Constants.tabHeight, - tabItemSizingPolicy: TabItemSizingPolicy = .fixed(size: TabItemSizingPolicy.defaultTabWidth), + tabItemSizingPolicy: TabItemSizingPolicy = .fixed(size: TabItemSizingPolicy.defaultTabSize), tabIndicatorColor: UIColor = .red) { self.tabHeight = tabHeight self.tabItemSizingPolicy = tabItemSizingPolicy diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index 51540e5..8236ca3 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -8,7 +8,7 @@ import UIKit -final public class ViewPagerController: UIViewController { +public final class ViewPagerController: UIViewController { @IBOutlet private weak var contentCollectionView: UICollectionView! @IBOutlet private weak var tabContainerStackView: UIStackView! @@ -17,11 +17,11 @@ final public class ViewPagerController: UIViewController { @IBOutlet private weak var tabCollectionViewLayout: TabCollectionViewLayout! @IBOutlet private weak var contentCollectionViewLayout: ContentCollectionViewLayout! - internal var contentCollectionViewDataSource: ContentCollectionViewDataSource! - internal var contentCollectionViewDelegate: ContentCollectionViewDelegate! - internal var tabCollectionViewDataSource: TabCollectionViewDataSource! - internal var tabCollectionViewDelegate: TabCollectionViewDelegate! - internal var scrollController: ScrollController! + var contentCollectionViewDataSource: ContentCollectionViewDataSource! + var contentCollectionViewDelegate: ContentCollectionViewDelegate! + var tabCollectionViewDataSource: TabCollectionViewDataSource! + var tabCollectionViewDelegate: TabCollectionViewDelegate! + var scrollController: ScrollController! public weak var dataSource: ViewPagerControllerDataSource? { didSet { @@ -64,7 +64,7 @@ private extension ViewPagerController { func adjustInsets() { if #available(iOS 11.0, *) { - additionalSafeAreaInsets = UIEdgeInsetsMake(configuration.tabHeight, 0.0, 0.0, 0.0) + additionalSafeAreaInsets = UIEdgeInsets(top: configuration.tabHeight, left: 0.0, bottom: 0.0, right: 0.0) contentCollectionView.contentInsetAdjustmentBehavior = .never } else { if let constraint = view.constraints.first(where: { $0.identifier == "tabAlignmentConstraint" }) { From d32bde206c02f96ef3d4e5d9c13530f724f2f637 Mon Sep 17 00:00:00 2001 From: Ilter Cengiz Date: Sun, 3 Jun 2018 11:36:15 +0300 Subject: [PATCH 27/28] Fix ViewPagerController init This change explicitly passes the nib name and bundle in init function fixing the case where ViewPagerController is bundled within a framework. --- ICViewPager/ICViewPager/ViewPagerController.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift index 8236ca3..ffeb860 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.swift +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -35,7 +35,8 @@ public final class ViewPagerController: UIViewController { public init(configuration: ViewPagerConfiguration = ViewPagerConfiguration()) { self.configuration = configuration - super.init(nibName: nil, bundle: nil) + super.init(nibName: "\(ViewPagerController.self)", + bundle: Bundle(for: ViewPagerController.self)) } required public init?(coder aDecoder: NSCoder) { From a6a54fe43abf552eb2e2da7c606deb4cf77d43ab Mon Sep 17 00:00:00 2001 From: "[KOP] Thuong Corleone" Date: Fri, 12 Oct 2018 17:22:30 +0700 Subject: [PATCH 28/28] fix iphone xr --- ICViewPager/ICViewPager/ViewPagerController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICViewPager/ICViewPager/ViewPagerController.m b/ICViewPager/ICViewPager/ViewPagerController.m index 2c3400a..01f4580 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.m +++ b/ICViewPager/ICViewPager/ViewPagerController.m @@ -205,7 +205,7 @@ - (void)layoutSubviews { CGFloat topLayoutGuide = 0.0; CGFloat bottomLayoutGuide = 0.0; if (IOS_VERSION_7) { - if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone && ((int)[[UIScreen mainScreen] nativeBounds].size.height) == 2436) { + if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone && ( (((int)[[UIScreen mainScreen] nativeBounds].size.height) == 2436) || (((int)[[UIScreen mainScreen] nativeBounds].size.height) == 1624)) ) { topLayoutGuide = 44.0f; if (@available(iOS 11.0, *)) { UIWindow *window = UIApplication.sharedApplication.keyWindow;