From 0354211b8f46e382381dbd310e13d3f95ada8c48 Mon Sep 17 00:00:00 2001 From: Nishan Date: Thu, 1 Jun 2017 21:19:45 +0545 Subject: [PATCH] Add features & fixes 1. Feature to programatically move to any view controller is added 2. Feature to update the tabs is added 3. Readme is updated & function comments are updated to support latest xcode version --- Readme.md | 14 +++ .../Core/ViewPagerController.swift | 103 +++++++++--------- ViewPager-Swift/Core/ViewPagerTab.swift | 4 +- ViewPager-Swift/MainViewController.swift | 10 +- 4 files changed, 73 insertions(+), 58 deletions(-) diff --git a/Readme.md b/Readme.md index 7bf4d6f..c21abc8 100644 --- a/Readme.md +++ b/Readme.md @@ -105,6 +105,20 @@ called when transiton to another view controller is completed ``` optional func didMoveToControllerAtIndex(index:Int) ``` + +**Additional** + +You can also change the page programatically. Suppose you want to display 3rd page. +``` +viewpager.displayViewController(atIndex: 2) // Since index starts from 0 +``` + +Also, you can update any of the viewpager tab. Just update the ViewPagerTab array which you are providing through the datasource. and then call +``` +viewpager.invalidateTabs() +``` + + ## Customization ## You can perform lots of customization. If you want to look under the hoods, all the **public variables** inside ViewPagerOptions.swift file is customizable. diff --git a/ViewPager-Swift/Core/ViewPagerController.swift b/ViewPager-Swift/Core/ViewPagerController.swift index bdd6c30..1eef33e 100644 --- a/ViewPager-Swift/Core/ViewPagerController.swift +++ b/ViewPager-Swift/Core/ViewPagerController.swift @@ -17,16 +17,16 @@ import UIKit @objc protocol ViewPagerControllerDataSource { - // Number of pages to be displayed + /// Number of pages to be displayed func numberOfPages() -> Int - // ViewController for required page position + /// ViewController for required page position func viewControllerAtPosition(position:Int) -> UIViewController - // Tab structure of the pages + /// Tab structure of the pages func tabsForPages() -> [ViewPagerTab] - //ViewController to start from + /// ViewController to start from @objc optional func startViewPagerAtIndex()->Int } @@ -59,9 +59,7 @@ class ViewPagerController:UIViewController { MARK:- Viewpager tab setup ---------------------------*/ - /** - * Prepares the container for holding all the tabviews. - */ + /// Prepares the container for holding all the tabviews. fileprivate func setupTabContainerView() { // Creating container for Tab View @@ -87,9 +85,7 @@ class ViewPagerController:UIViewController { } - /** - * Creates and adds each tabs according to the options provided in tabcontainer. - */ + ///Creates and adds each tabs according to the options provided in tabcontainer. fileprivate func setupTabs() { var totalWidth:CGFloat = 0 @@ -154,15 +150,14 @@ class ViewPagerController:UIViewController { } } - /** - * Sets up indicator for the page if enabled in ViewPagerOption. This method shows either tabIndicator - * or Highlights current tab or both. - */ - func setupCurrentPageIndicator(currentIndex: Int, previousIndex: Int) { + + /// Sets up indicator for the page if enabled in ViewPagerOption. This method shows either tabIndicator or Highlights current tab or both. + fileprivate func setupCurrentPageIndicator(currentIndex: Int, previousIndex: Int) { if options.isTabHighlightAvailable! { self.tabsViewList[previousIndex].removeHighlight(options: self.options) + UIView.animate(withDuration: 0.8, animations: { self.tabsViewList[currentIndex].addHighlight(options: self.options) @@ -190,6 +185,8 @@ class ViewPagerController:UIViewController { isIndicatorAdded = true } + self.tabContainer.bringSubview(toFront: tabIndicator) + UIView.animate(withDuration: 0.5, animations: { self.tabContainer.scrollRectToVisible(tabIndicatorFrame, animated: false) @@ -203,9 +200,7 @@ class ViewPagerController:UIViewController { MARK:- Tab setup helpers ---------------------------*/ - /** - * Gesture recognizer for determining which tabview was tapped - */ + /// Gesture recognizer for determining which tabview was tapped func tabContainerTapped(_ recognizer:UITapGestureRecognizer) { let tapLocation = recognizer.location(in: self.tabContainer) @@ -215,15 +210,11 @@ class ViewPagerController:UIViewController { if tabViewIndex != currentPageIndex { - let prev = currentPageIndex - setupCurrentPageIndicator(currentIndex: tabViewIndex ?? 0, previousIndex: currentPageIndex) - displayViewController(atIndex: tabViewIndex ?? 0, inForwardDirection: tabViewIndex ?? 0 > prev) + displayViewController(atIndex: tabViewIndex ?? 0) } } - /** - * Determines the orientation change and sets up the tab size and its indicator size accordingly. - */ + /// Determines the orientation change and sets up the tab size and its indicator size accordingly. override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { DispatchQueue.main.async { @@ -249,9 +240,7 @@ class ViewPagerController:UIViewController { } - /** - * Determines maximum width between two provided value and returns it - */ + /// Determines maximum width between two provided value and returns it fileprivate func getMaximumWidth(maxWidth:CGFloat, withWidth currentWidth:CGFloat) -> CGFloat { return (maxWidth > currentWidth) ? maxWidth : currentWidth @@ -289,12 +278,10 @@ class ViewPagerController:UIViewController { } - /** - * Returns UIViewController for page at provided index. - */ + /// Returns UIViewController for page at provided index. fileprivate func getPageItemViewController(atIndex index:Int) -> UIViewController? { - if index < dataSource.numberOfPages() { + if index >= 0 && index < dataSource.numberOfPages() { let pageItemViewController = dataSource.viewControllerAtPosition(position: index) pageItemViewController.view.tag = index @@ -304,35 +291,54 @@ class ViewPagerController:UIViewController { return nil } - /** - * Sets the visible view controller with the view controller at provided index. - */ - fileprivate func displayViewController(atIndex index:Int,inForwardDirection:Bool) { + + /// Displays the UIViewController provided at given index in datasource. + /// + /// - Parameter index: position of the view controller to be displayed. 0 is first UIViewController + func displayViewController(atIndex index:Int) { let chosenViewController = getPageItemViewController(atIndex: index)! delegate?.willMoveToControllerAtIndex?(index: index) - pageViewController!.setViewControllers([chosenViewController], direction: inForwardDirection ? .forward : .reverse, animated: true, completion: { (isCompleted) in + + let previousIndex = currentPageIndex + let direction:UIPageViewControllerNavigationDirection = (index > previousIndex ) ? .forward : .reverse + setupCurrentPageIndicator(currentIndex: index, previousIndex: currentPageIndex) + + pageViewController!.setViewControllers([chosenViewController], direction: direction, animated: true, completion: { (isCompleted) in if isCompleted { self.delegate?.didMoveToControllerAtIndex?(index: index) } }) + } + + /// Invalidate the current tabs shown and reloads the new tabs provided in datasource. + func invalidateTabs() { + // Removing all the tabs from tabContainer + _ = tabsViewList.map({ $0.removeFromSuperview() }) + tabsList.removeAll() + tabsViewList.removeAll() + + setupTabs() + setupCurrentPageIndicator(currentIndex: currentPageIndex, previousIndex: currentPageIndex) } } +// MARK:- UIPageViewController Delegates + extension ViewPagerController: UIPageViewControllerDelegate { func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { - if completed { + if completed && finished { + let pageIndex = pageViewController.viewControllers?.first?.view.tag setupCurrentPageIndicator(currentIndex: pageIndex!, previousIndex: currentPageIndex) delegate?.didMoveToControllerAtIndex?(index: pageIndex!) } - } func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { @@ -341,31 +347,22 @@ extension ViewPagerController: UIPageViewControllerDelegate { delegate?.willMoveToControllerAtIndex?(index: pageIndex!) } - } +// MARK:- UIPageViewController Datasource + extension ViewPagerController:UIPageViewControllerDataSource { - /** - * ViewController the user will navigate to in backward direction - */ + /* ViewController the user will navigate to in backward direction */ func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { - if viewController.view.tag > 0 { - return getPageItemViewController(atIndex: viewController.view.tag - 1) - } - return nil + return getPageItemViewController(atIndex: viewController.view.tag - 1) } - /** - * ViewController the user will navigate to in forward direction - */ + /* ViewController the user will navigate to in forward direction */ func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { - if viewController.view.tag + 1 < dataSource.numberOfPages() { - return getPageItemViewController(atIndex: viewController.view.tag + 1) - } - return nil + return getPageItemViewController(atIndex: viewController.view.tag + 1) } } diff --git a/ViewPager-Swift/Core/ViewPagerTab.swift b/ViewPager-Swift/Core/ViewPagerTab.swift index 5bca22d..436724b 100644 --- a/ViewPager-Swift/Core/ViewPagerTab.swift +++ b/ViewPager-Swift/Core/ViewPagerTab.swift @@ -17,8 +17,8 @@ enum ViewPagerTabType { class ViewPagerTab:NSObject { - let title:String! - let image:UIImage? + var title:String! + var image:UIImage? init(title:String, image:UIImage?) { self.title = title diff --git a/ViewPager-Swift/MainViewController.swift b/ViewPager-Swift/MainViewController.swift index ec4fbf3..6978625 100644 --- a/ViewPager-Swift/MainViewController.swift +++ b/ViewPager-Swift/MainViewController.swift @@ -31,7 +31,7 @@ class MainViewController: UIViewController { ViewPagerTab(title: "Water", image: UIImage(named: "water")) ] - let tabs = [ + var tabs = [ ViewPagerTab(title: "Fries", image: UIImage(named: "fries")), ViewPagerTab(title: "Hamburger", image: UIImage(named: "hamburger")), ViewPagerTab(title: "Beer", image: UIImage(named: "pint")), @@ -40,6 +40,7 @@ class MainViewController: UIViewController { ViewPagerTab(title: "Sandwich", image: UIImage(named: "sandwich")) ] + var viewPager:ViewPagerController! override func viewDidLoad() { super.viewDidLoad() @@ -56,7 +57,7 @@ class MainViewController: UIViewController { options.tabViewPaddingRight = 20 options.isTabHighlightAvailable = true - let viewPager = ViewPagerController() + viewPager = ViewPagerController() viewPager.options = options viewPager.dataSource = self viewPager.delegate = self @@ -65,7 +66,6 @@ class MainViewController: UIViewController { self.view.addSubview(viewPager.view) viewPager.didMove(toParentViewController: self) } - } @@ -84,6 +84,10 @@ extension MainViewController: ViewPagerControllerDataSource { func tabsForPages() -> [ViewPagerTab] { return tabs } + + func startViewPagerAtIndex() -> Int { + return 0 + } } extension MainViewController: ViewPagerControllerDelegate {