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 4046009..a168750 100644 --- a/ICViewPager.xcodeproj/project.pbxproj +++ b/ICViewPager.xcodeproj/project.pbxproj @@ -3,48 +3,65 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; 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 */; }; + 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 */; }; + 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 */; }; + 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 */; }; + 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 */; }; + 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 */ - 7C115E001816DED1000BCE63 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 7CEC17A817DA1EC000E4A439 /* iPad.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = iPad.storyboard; 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 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; }; - 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 = ""; }; - 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 = ""; }; - 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 = ""; }; + 7CF3D65C17CE32E40021036A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -52,85 +69,137 @@ 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 = { + 36CB294120AF60370054261E /* Extensions */ = { isa = PBXGroup; children = ( - 7CF3D65A17CE32E40021036A /* ICViewPager */, - 7CF3D65317CE32E40021036A /* Frameworks */, - 7CF3D65217CE32E40021036A /* Products */, + 36CB294220AF60440054261E /* UIView+Embed.swift */, + 36CB294F20AF80270054261E /* UIViewController+Insets.swift */, ); + path = Extensions; sourceTree = ""; }; - 7CF3D65217CE32E40021036A /* Products */ = { + 36CB294C20AF6C140054261E /* Example */ = { isa = PBXGroup; children = ( - 7CF3D65117CE32E40021036A /* ICViewPager.app */, + 36CB294D20AF6C2D0054261E /* ExampleViewPagerControllerDataSource.swift */, ); - name = Products; + path = Example; sourceTree = ""; }; - 7CF3D65317CE32E40021036A /* Frameworks */ = { + 36CB295120AF824F0054261E /* Content */ = { isa = PBXGroup; children = ( - 7CF3D65417CE32E40021036A /* UIKit.framework */, - 7CF3D65617CE32E40021036A /* Foundation.framework */, - 7CF3D65817CE32E40021036A /* CoreGraphics.framework */, + 36CB293520AF5A610054261E /* ContentCollectionViewLayout.swift */, + 36CB293F20AF5F1D0054261E /* ContentCollectionViewCell.swift */, + 36CB294420AF622F0054261E /* ContentCollectionViewDataSource.swift */, + 36CB294820AF687C0054261E /* ContentCollectionViewDelegate.swift */, ); - name = Frameworks; + path = Content; sourceTree = ""; }; - 7CF3D65A17CE32E40021036A /* ICViewPager */ = { + 36CB295220AF82590054261E /* Tab */ = { + isa = PBXGroup; + children = ( + 36FA1A1C20B35F550086BCD9 /* TabIndicator */, + 36CB293320AF5A4D0054261E /* TabCollectionViewLayout.swift */, + 36B114FE20AF91E200DA4621 /* TabCollectionViewCell.swift */, + 36B1151220AF926700DA4621 /* TabItemView.swift */, + 36B1151420AF92F900DA4621 /* TabCollectionViewDataSource.swift */, + 36B1151820AFA0CF00DA4621 /* TabCollectionViewDelegate.swift */, + 36B1151620AF9FEB00DA4621 /* DefaultTabItemView.swift */, + ); + path = Tab; + sourceTree = ""; + }; + 36F4A3B020AF0675000995B2 /* Application */ = { + isa = PBXGroup; + children = ( + 36F4A3B120AF0685000995B2 /* ApplicationDelegate.swift */, + ); + path = Application; + sourceTree = ""; + }; + 36F4A3B320AF0E1D000995B2 /* Scenes */ = { + isa = PBXGroup; + children = ( + 36F4A3B420AF0EB1000995B2 /* Empty */, + ); + path = Scenes; + sourceTree = ""; + }; + 36F4A3B420AF0EB1000995B2 /* Empty */ = { isa = PBXGroup; children = ( - 7CF3D66317CE32E40021036A /* AppDelegate.h */, - 7CF3D66417CE32E40021036A /* AppDelegate.m */, - 7CF3D67117CE332F0021036A /* iPhone.storyboard */, - 7CEC17A817DA1EC000E4A439 /* iPad.storyboard */, - 7CF3D67B17CE33C80021036A /* ICViewPager */, - 7CF3D67A17CE33C80021036A /* Controller */, - 7C115E001816DED1000BCE63 /* Images.xcassets */, - 7CF3D65B17CE32E40021036A /* Supporting Files */, + 36F4A3B520AF0EF9000995B2 /* EmptyViewController.swift */, + 36CB294A20AF6AC20054261E /* EmptyViewController.xib */, + ); + path = Empty; + sourceTree = ""; + }; + 36F4A3BB20AF0FC4000995B2 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 7CF3D65C17CE32E40021036A /* Info.plist */, + 36F4A3B820AF0FA4000995B2 /* LaunchScreen.storyboard */, + ); + path = "Supporting Files"; + sourceTree = ""; + }; + 36F4A3BC20AF184E000995B2 /* ICViewPager */ = { + isa = PBXGroup; + children = ( + 36CB292F20AF5A370054261E /* ViewPagerController.swift */, + 36CB293020AF5A370054261E /* ViewPagerController.xib */, + 36CB294620AF628F0054261E /* ViewPagerControllerDataSource.swift */, + 36F4A3C020AF4F8A000995B2 /* ViewPagerConfiguration.swift */, + 36B1152820B0920C00DA4621 /* ScrollController.swift */, + 36E1376D20B2245D0021F3EF /* ScrollDirection.swift */, + 36CB295220AF82590054261E /* Tab */, + 36CB295120AF824F0054261E /* Content */, + 36CB294120AF60370054261E /* Extensions */, ); path = ICViewPager; sourceTree = ""; }; - 7CF3D65B17CE32E40021036A /* Supporting Files */ = { + 36FA1A1C20B35F550086BCD9 /* TabIndicator */ = { isa = PBXGroup; children = ( - 7CF3D65C17CE32E40021036A /* ICViewPager-Info.plist */, - 7CF3D65D17CE32E40021036A /* InfoPlist.strings */, - 7CF3D66017CE32E40021036A /* main.m */, - 7CF3D66217CE32E40021036A /* ICViewPager-Prefix.pch */, - 7CF3D67817CE336E0021036A /* Localization.strings */, + 365567D920B0BD7100D5C00F /* TabIndicatorView.swift */, + 36FA1A1D20B35F6D0086BCD9 /* TabIndicatorAttributes.swift */, ); - name = "Supporting Files"; + path = TabIndicator; sourceTree = ""; }; - 7CF3D67A17CE33C80021036A /* Controller */ = { + 7CF3D64817CE32E40021036A = { isa = PBXGroup; children = ( - 7CF3D67F17CE33EC0021036A /* HostViewController.h */, - 7CF3D68017CE33EC0021036A /* HostViewController.m */, - 7CF3D68317CE3F5B0021036A /* ContentViewController.h */, - 7CF3D68417CE3F5B0021036A /* ContentViewController.m */, + 7CF3D65A17CE32E40021036A /* ICViewPager */, + 7CF3D65217CE32E40021036A /* Products */, ); - path = Controller; sourceTree = ""; }; - 7CF3D67B17CE33C80021036A /* ICViewPager */ = { + 7CF3D65217CE32E40021036A /* Products */ = { isa = PBXGroup; children = ( - 7CF3D67C17CE33E10021036A /* ViewPagerController.h */, - 7CF3D67D17CE33E10021036A /* ViewPagerController.m */, + 7CF3D65117CE32E40021036A /* ICViewPager.app */, + ); + name = Products; + sourceTree = ""; + }; + 7CF3D65A17CE32E40021036A /* ICViewPager */ = { + isa = PBXGroup; + children = ( + 36F4A3B020AF0675000995B2 /* Application */, + 36CB294C20AF6C140054261E /* Example */, + 36F4A3B320AF0E1D000995B2 /* Scenes */, + 36F4A3BC20AF184E000995B2 /* ICViewPager */, + 36F4A3BB20AF0FC4000995B2 /* Supporting Files */, ); path = ICViewPager; sourceTree = ""; @@ -161,11 +230,16 @@ 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 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -187,11 +261,9 @@ 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 */, + 36CB294B20AF6AC20054261E /* EmptyViewController.xib in Resources */, + 36CB293220AF5A370054261E /* ViewPagerController.xib in Resources */, + 36F4A3B920AF0FA4000995B2 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -202,64 +274,79 @@ 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 */, + 36CB294920AF687C0054261E /* ContentCollectionViewDelegate.swift in Sources */, + 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 /* TabIndicatorView.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 */, + 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; }; /* 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 +357,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 +401,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 +422,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/AppDelegate.h b/ICViewPager/AppDelegate.h deleted file mode 100644 index cf72238..0000000 --- a/ICViewPager/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/AppDelegate.m b/ICViewPager/AppDelegate.m deleted file mode 100644 index 453922b..0000000 --- a/ICViewPager/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/Application/ApplicationDelegate.swift b/ICViewPager/Application/ApplicationDelegate.swift new file mode 100644 index 0000000..c06779e --- /dev/null +++ b/ICViewPager/Application/ApplicationDelegate.swift @@ -0,0 +1,57 @@ +// +// 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? + private let dataSource = ExampleViewPagerControllerDataSource() + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + + + + window = UIWindow(frame: UIScreen.main.bounds) + + /** To test different container scenarios, enable one option. */ + window?.rootViewController = viewPagerController() +// window?.rootViewController = navigationController() +// window?.rootViewController = tabBarController() + + window?.makeKeyAndVisible() + + return true + } + + // MARK: Functions for test purposes + + private func viewPagerController() -> ViewPagerController { + + /** ViewPagerController configuration here. All the configuration properties are optional. */ + let configuration = ViewPagerConfiguration(tabHeight: 48.0, + tabItemSizingPolicy: .fill, + tabIndicatorColor: #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)) + + let viewPagerController = ViewPagerController(configuration: configuration) + 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/Controller/ContentViewController.h b/ICViewPager/Controller/ContentViewController.h deleted file mode 100644 index f77a6c6..0000000 --- a/ICViewPager/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/Controller/ContentViewController.m b/ICViewPager/Controller/ContentViewController.m deleted file mode 100644 index 40d2b28..0000000 --- a/ICViewPager/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/Controller/HostViewController.h b/ICViewPager/Controller/HostViewController.h deleted file mode 100644 index 613038b..0000000 --- a/ICViewPager/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/Controller/HostViewController.m b/ICViewPager/Controller/HostViewController.m deleted file mode 100644 index b113549..0000000 --- a/ICViewPager/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/Example/ExampleViewPagerControllerDataSource.swift b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift new file mode 100644 index 0000000..9e01d33 --- /dev/null +++ b/ICViewPager/Example/ExampleViewPagerControllerDataSource.swift @@ -0,0 +1,56 @@ +// +// 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), 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) + ] +} + +extension ExampleViewPagerControllerDataSource: ViewPagerControllerDataSource { + + func viewPagerController(_ controller: ViewPagerController, + viewControllerAt index: Int) -> UIViewController { + return viewControllers[index] + } + + func viewPagerController(_ controller: ViewPagerController, + 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 { + + /** 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-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/ICViewPager/Content/ContentCollectionViewCell.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift new file mode 100644 index 0000000..6df4551 --- /dev/null +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewCell.swift @@ -0,0 +1,38 @@ +// +// 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 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() + } +} diff --git a/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift b/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift new file mode 100644 index 0000000..eadf31f --- /dev/null +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDataSource.swift @@ -0,0 +1,97 @@ +// +// 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? { + didSet { collectionView.reloadData() } + } + + // 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 = UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomInset, right: 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 { + return 0 + } + + 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..aff6c23 --- /dev/null +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewDelegate.swift @@ -0,0 +1,108 @@ +// +// ContentCollectionViewDelegate.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +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) +} + +final class ContentCollectionViewDelegate: NSObject { + + private unowned var viewPagerController: ViewPagerController + private unowned var collectionView: UICollectionView + weak var delegate: ContentCollectionViewDelegateProtocol? + + public private(set) var currentPage: Int = 0 + private var contentOffsetBeforeDragging: CGPoint = .zero + private var shouldResetContentOffsetBeforeDragging: Bool = true + + // MARK: Init + + init(viewPagerController: ViewPagerController, collectionView: UICollectionView) { + self.viewPagerController = viewPagerController + self.collectionView = collectionView + 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: UIScrollViewDelegate + +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) + } + + func scrollViewDidEndDragging(_ scrollView: UIScrollView, + 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.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 new file mode 100644 index 0000000..19c60b1 --- /dev/null +++ b/ICViewPager/ICViewPager/Content/ContentCollectionViewLayout.swift @@ -0,0 +1,59 @@ +// +// 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() + scrollDirection = .horizontal + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + scrollDirection = .horizontal + } + + 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 + } + + 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) + } +} 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/ScrollController.swift b/ICViewPager/ICViewPager/ScrollController.swift new file mode 100644 index 0000000..247a546 --- /dev/null +++ b/ICViewPager/ICViewPager/ScrollController.swift @@ -0,0 +1,63 @@ +// +// 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 + private unowned var tabCollectionViewLayout: TabCollectionViewLayout + + // MARK: Init + + init(viewPagerController: ViewPagerController, + contentCollectionView: UICollectionView, + tabCollectionView: UICollectionView) { + 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 + } + + func contentCollectionViewDidEndDragging(_ collectionView: UICollectionView) { + tabCollectionView.isUserInteractionEnabled = true + } + + func contentCollectionView(_ collectionView: UICollectionView, didScrollToPageAt index: Int) { + tabCollectionViewLayout.currentPage = index + tabCollectionView.scrollToItem(at: IndexPath(item: index, section: 0), + at: .left, + animated: 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/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/DefaultTabItemView.swift b/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift new file mode 100644 index 0000000..9a439af --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/DefaultTabItemView.swift @@ -0,0 +1,52 @@ +// +// DefaultTabItemView.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +public final class DefaultTabItemView: TabItemView { + + 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 + public var title: String { + didSet { + label.text = title + } + } + + public init(title: String) { + label = UILabel() + self.title = title + super.init(frame: .zero) + setUpUI() + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension DefaultTabItemView { + + func setUpUI() { + backgroundColor = .white + + label.font = UIFont.boldSystemFont(ofSize: 14.0) + 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..c4328d2 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewDataSource.swift @@ -0,0 +1,80 @@ +// +// 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? { + didSet { collectionView.reloadData() } + } + var numberOfViews: Int = 0 + + // 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 collectionView(_ collectionView: UICollectionView, + numberOfItemsInSection section: Int) -> Int { + + guard let dataSource = dataSource else { + 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/TabCollectionViewDelegate.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift new file mode 100644 index 0000000..4e6433f --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewDelegate.swift @@ -0,0 +1,57 @@ +// +// TabCollectionViewDelegate.swift +// ICViewPager +// +// Created by Ilter Cengiz on 19/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +protocol TabCollectionViewDelegateProtocol: class { + + func tabCollectionView(_ collectionView: UICollectionView, didSelectItemAt index: Int) +} + +final class TabCollectionViewDelegate: NSObject { + + private unowned var viewPagerController: ViewPagerController + private lazy var numberOfItems: Int = self.viewPagerController.tabCollectionViewDataSource.numberOfViews + weak var delegate: TabCollectionViewDelegateProtocol? + + // MARK: Init + + init(viewPagerController: ViewPagerController) { + self.viewPagerController = viewPagerController + super.init() + } +} + +// MARK: UICollectionViewDelegate + +extension TabCollectionViewDelegate: UICollectionViewDelegate { + + func collectionView(_ collectionView: UICollectionView, + didSelectItemAt indexPath: IndexPath) { + delegate?.tabCollectionView(collectionView, didSelectItemAt: indexPath.item) + } +} + +// MARK: UICollectionViewDelegateFlowLayout + +extension TabCollectionViewDelegate: UICollectionViewDelegateFlowLayout { + + public func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + + 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/Tab/TabCollectionViewLayout.swift b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift new file mode 100644 index 0000000..938d191 --- /dev/null +++ b/ICViewPager/ICViewPager/Tab/TabCollectionViewLayout.swift @@ -0,0 +1,134 @@ +// +// TabCollectionViewLayout.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +final class TabCollectionViewLayout: UICollectionViewFlowLayout { + + private enum Constants { + static let indicatorHeight: CGFloat = 2.0 + } + + private var indicatorAttributes: TabIndicatorAttributes! + private var invalidationContext: UICollectionViewFlowLayoutInvalidationContext = { + let context = UICollectionViewFlowLayoutInvalidationContext() + context.invalidateFlowLayoutAttributes = false + context.invalidateFlowLayoutDelegateMetrics = false + context.invalidateDecorationElements(ofKind: TabIndicatorView.kind, + at: [TabIndicatorAttributes.Constants.indicatorIndexPath]) + return context + }() + + var configuration: ViewPagerConfiguration! + var currentPage: Int = 0 + var numberOfViews: 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() + if numberOfViews > 0 { + indicatorAttributes = indicatorAttributes(for: currentPage) + } + } + + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + var attributes = super.layoutAttributesForElements(in: rect) + if numberOfViews > 0 { + attributes?.append(indicatorAttributes) + } + return attributes + } + + override func layoutAttributesForDecorationView(ofKind elementKind: String, + at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + guard elementKind == TabIndicatorView.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) + } +} + +private extension TabCollectionViewLayout { + + func setUpLayout() { + scrollDirection = .horizontal + minimumInteritemSpacing = 0.0 + minimumLineSpacing = 0.0 + } + + func registerDecorationView() { + register(TabIndicatorView.self, + forDecorationViewOfKind: TabIndicatorView.kind) + } + + func indicatorAttributes(for page: Int) -> TabIndicatorAttributes { + + guard let tabItemAttributes = layoutAttributesForItem(at: IndexPath(item: page, section: 0)) else { + fatalError("Called `indicatorAttributes(for:)` before super did its preparations.") + } + + let tabItemFrame = tabItemAttributes.frame + + let indicatorAttributes = TabIndicatorAttributes(backgroundColor: configuration.tabIndicatorColor) + indicatorAttributes.frame = CGRect(x: tabItemFrame.minX, y: tabItemFrame.maxY - Constants.indicatorHeight, + width: tabItemFrame.width, height: Constants.indicatorHeight) + 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/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/ViewPagerConfiguration.swift b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift new file mode 100644 index 0000000..e2612b9 --- /dev/null +++ b/ICViewPager/ICViewPager/ViewPagerConfiguration.swift @@ -0,0 +1,36 @@ +// +// 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 + fileprivate static let defaultTabSize = CGSize(width: 144.0, height: Constants.tabHeight) + } + + public enum TabItemSizingPolicy { + public static let defaultTabSize: CGSize = Constants.defaultTabSize + + case fixed(size: CGSize) + case fill + } + + public var tabHeight: CGFloat + public var tabItemSizingPolicy: TabItemSizingPolicy + public var tabIndicatorColor: UIColor + + public init(tabHeight: CGFloat = Constants.tabHeight, + tabItemSizingPolicy: TabItemSizingPolicy = .fixed(size: TabItemSizingPolicy.defaultTabSize), + tabIndicatorColor: UIColor = .red) { + self.tabHeight = tabHeight + self.tabItemSizingPolicy = tabItemSizingPolicy + self.tabIndicatorColor = tabIndicatorColor + } +} diff --git a/ICViewPager/ICViewPager/ViewPagerController.h b/ICViewPager/ICViewPager/ViewPagerController.h deleted file mode 100644 index 37218a3..0000000 --- a/ICViewPager/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/ICViewPager/ViewPagerController.m b/ICViewPager/ICViewPager/ViewPagerController.m index 7c3ceb4..01f4580 100644 --- a/ICViewPager/ICViewPager/ViewPagerController.m +++ b/ICViewPager/ICViewPager/ViewPagerController.m @@ -203,8 +203,17 @@ - (void)didReceiveMemoryWarning { - (void)layoutSubviews { CGFloat topLayoutGuide = 0.0; + CGFloat bottomLayoutGuide = 0.0; if (IOS_VERSION_7) { - topLayoutGuide = 20.0; + 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; + bottomLayoutGuide = window.safeAreaInsets.bottom; + } + } else { + topLayoutGuide = 20.0f; + } if (self.navigationController && !self.navigationController.navigationBarHidden) { topLayoutGuide += self.navigationController.navigationBar.frame.size.height; } @@ -221,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)) - (self.tabBarController.tabBar.hidden ? 0 : 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; } @@ -236,7 +245,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]; } } @@ -573,12 +582,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; @@ -586,9 +590,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; @@ -599,12 +600,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 { @@ -876,7 +871,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; @@ -969,7 +964,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 diff --git a/ICViewPager/ICViewPager/ViewPagerController.swift b/ICViewPager/ICViewPager/ViewPagerController.swift new file mode 100644 index 0000000..ffeb860 --- /dev/null +++ b/ICViewPager/ICViewPager/ViewPagerController.swift @@ -0,0 +1,110 @@ +// +// ViewPagerController.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +public final 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! + + var contentCollectionViewDataSource: ContentCollectionViewDataSource! + var contentCollectionViewDelegate: ContentCollectionViewDelegate! + var tabCollectionViewDataSource: TabCollectionViewDataSource! + var tabCollectionViewDelegate: TabCollectionViewDelegate! + var scrollController: ScrollController! + + public weak var dataSource: ViewPagerControllerDataSource? { + didSet { + tabCollectionViewDataSource?.dataSource = dataSource + contentCollectionViewDataSource?.dataSource = dataSource + } + } + public var configuration: ViewPagerConfiguration + + // MARK: Init + + public init(configuration: ViewPagerConfiguration = ViewPagerConfiguration()) { + self.configuration = configuration + super.init(nibName: "\(ViewPagerController.self)", + bundle: Bundle(for: ViewPagerController.self)) + } + + required public init?(coder aDecoder: NSCoder) { + configuration = ViewPagerConfiguration() + super.init(coder: aDecoder) + } + + // MARK: View life cycle + + public override func viewDidLoad() { + super.viewDidLoad() + setUpScrollController() + setUpUI() + } +} + +private extension ViewPagerController { + + func setUpUI() { + view.backgroundColor = .black + adjustInsets() + setUpContentCollectionView(contentCollectionView) + setUpTabCollectionView(tabCollectionView) + applyConfiguration(configuration) + } + + func adjustInsets() { + if #available(iOS 11.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" }) { + view.removeConstraint(constraint) + } + topLayoutGuide.bottomAnchor.constraint(equalTo: tabContainerStackView.topAnchor).isActive = true + automaticallyAdjustsScrollViewInsets = false + } + } + + func setUpContentCollectionView(_ collectionView: UICollectionView) { + contentCollectionViewDataSource = ContentCollectionViewDataSource(viewPagerController: self, + collectionView: collectionView) + contentCollectionViewDataSource.dataSource = dataSource + contentCollectionViewDelegate = ContentCollectionViewDelegate(viewPagerController: self, + collectionView: collectionView) + contentCollectionViewDelegate.delegate = scrollController + collectionView.dataSource = contentCollectionViewDataSource + collectionView.delegate = contentCollectionViewDelegate + } + + func setUpTabCollectionView(_ collectionView: UICollectionView) { + tabCollectionViewDataSource = TabCollectionViewDataSource(viewPagerController: self, + collectionView: collectionView) + tabCollectionViewDataSource.dataSource = dataSource + tabCollectionViewDelegate = TabCollectionViewDelegate(viewPagerController: self) + tabCollectionViewDelegate.delegate = scrollController + collectionView.dataSource = tabCollectionViewDataSource + collectionView.delegate = tabCollectionViewDelegate + tabCollectionViewLayout.configuration = configuration + } + + func applyConfiguration(_ configuration: ViewPagerConfiguration) { + tabCollectionViewHeightConstraint.constant = configuration.tabHeight + } + + func setUpScrollController() { + scrollController = ScrollController(viewPagerController: self, + contentCollectionView: contentCollectionView, + tabCollectionView: tabCollectionView) + } +} diff --git a/ICViewPager/ICViewPager/ViewPagerController.xib b/ICViewPager/ICViewPager/ViewPagerController.xib new file mode 100644 index 0000000..4638bf6 --- /dev/null +++ b/ICViewPager/ICViewPager/ViewPagerController.xib @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift b/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift new file mode 100644 index 0000000..0bc7720 --- /dev/null +++ b/ICViewPager/ICViewPager/ViewPagerControllerDataSource.swift @@ -0,0 +1,21 @@ +// +// 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, + tabItemViewAt index: Int, + reusingTabItemView tabItemView: TabItemView?) -> TabItemView + + func numberOfViews(in controller: ViewPagerController) -> Int +} 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 97ebcca..0000000 Binary files a/ICViewPager/Images.xcassets/AppIcon.appiconset/Icon-1.png and /dev/null differ diff --git a/ICViewPager/Images.xcassets/AppIcon.appiconset/Icon.png b/ICViewPager/Images.xcassets/AppIcon.appiconset/Icon.png deleted file mode 100644 index 9ae76d1..0000000 Binary files a/ICViewPager/Images.xcassets/AppIcon.appiconset/Icon.png and /dev/null differ 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 0891b7a..0000000 Binary files a/ICViewPager/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png and /dev/null differ diff --git a/ICViewPager/Scenes/Empty/EmptyViewController.swift b/ICViewPager/Scenes/Empty/EmptyViewController.swift new file mode 100644 index 0000000..4d3e11a --- /dev/null +++ b/ICViewPager/Scenes/Empty/EmptyViewController.swift @@ -0,0 +1,38 @@ +// +// EmptyViewController.swift +// ICViewPager +// +// Created by Ilter Cengiz on 18/5/18. +// Copyright © 2018 Ilter Cengiz. All rights reserved. +// + +import UIKit + +class EmptyViewController: UIViewController { + + var backgroundColor: UIColor + var number: Int + @IBOutlet weak var numberLabel: UILabel! + + // MARK: Init + + 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) + } + + // MARK: View life cycle + + 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 new file mode 100644 index 0000000..8e1d47b --- /dev/null +++ b/ICViewPager/Scenes/Empty/EmptyViewController.xib @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/iPad.storyboard b/ICViewPager/iPad.storyboard deleted file mode 100644 index c425f6c..0000000 --- a/ICViewPager/iPad.storyboard +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ICViewPager/iPhone.storyboard b/ICViewPager/iPhone.storyboard deleted file mode 100644 index e35b3ad..0000000 --- a/ICViewPager/iPhone.storyboard +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file 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. -*/ diff --git a/README.md b/README.md index 18466d6..31dff9d 100644 --- a/README.md +++ b/README.md @@ -1,151 +1,24 @@ -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) +- [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 +- [ ] ... ## 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) diff --git a/Resources/Screenshot.jpg b/Resources/Screenshot.jpg deleted file mode 100644 index bc79d17..0000000 Binary files a/Resources/Screenshot.jpg and /dev/null differ