Last active
August 25, 2018 17:28
-
-
Save mspvirajpatel/58dac2fae0d3b4077a0cb6122def6570 to your computer and use it in GitHub Desktop.
Smooth UIScrollView with custom paging in Swift 3.0.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
public protocol ContainerViewControllerDelegate { | |
func outerScrollViewShouldScroll() -> Bool | |
} | |
public class BaseScrollViewController: UIViewController, UIScrollViewDelegate { | |
public var topVc: UIViewController? | |
public var leftVc: UIViewController! | |
public var middleVc: UIViewController! | |
public var rightVc: UIViewController! | |
public var bottomVc: UIViewController? | |
public var directionLockDisabled: Bool! | |
public var horizontalViews = [UIViewController]() | |
public var veritcalViews = [UIViewController]() | |
public var initialContentOffset = CGPoint() // scrollView initial offset | |
public var maximumWidthFirstView : CGFloat = 0 | |
public var middleVertScrollVc: BaseVerticalScrollViewController! | |
public var scrollView: UIScrollView! | |
public var delegate: ContainerViewControllerDelegate? | |
public class func containerViewWith(_ leftVC: UIViewController, | |
middleVC: UIViewController, | |
rightVC: UIViewController, | |
topVC: UIViewController?=nil, | |
bottomVC: UIViewController?=nil, | |
directionLockDisabled: Bool?=false) -> BaseScrollViewViewController { | |
let container = BaseScrollViewViewController() | |
container.directionLockDisabled = directionLockDisabled | |
container.topVc = topVC | |
container.leftVc = leftVC | |
container.middleVc = middleVC | |
container.rightVc = rightVC | |
container.bottomVc = bottomVC | |
return container | |
} | |
override public func viewDidLoad() { | |
super.viewDidLoad() | |
setupVerticalScrollView() | |
setupHorizontalScrollView() | |
} | |
func setupVerticalScrollView() { | |
middleVertScrollVc = BaseVerticalScrollViewController.verticalScrollVcWith(middleVc: middleVc, | |
topVc: topVc, | |
bottomVc: bottomVc) | |
delegate = middleVertScrollVc | |
} | |
func setupHorizontalScrollView() { | |
scrollView = UIScrollView() | |
scrollView.isPagingEnabled = true | |
scrollView.showsHorizontalScrollIndicator = false | |
scrollView.bounces = false | |
let view = ( | |
x: self.view.bounds.origin.x, | |
y: self.view.bounds.origin.y, | |
width: self.view.bounds.width, | |
height: self.view.bounds.height | |
) | |
scrollView.frame = CGRect(x: view.x, | |
y: view.y, | |
width: view.width, | |
height: view.height | |
) | |
self.view.addSubview(scrollView) | |
let scrollWidth = 3 * view.width | |
let scrollHeight = view.height | |
scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight) | |
leftVc.view.frame = CGRect(x: 0, | |
y: 0, | |
width: view.width, | |
height: view.height | |
) | |
middleVertScrollVc.view.frame = CGRect(x: view.width, | |
y: 0, | |
width: view.width, | |
height: view.height | |
) | |
rightVc.view.frame = CGRect(x: 2 * view.width, | |
y: 0, | |
width: view.width, | |
height: view.height | |
) | |
addChildViewController(leftVc) | |
addChildViewController(middleVertScrollVc) | |
addChildViewController(rightVc) | |
scrollView.addSubview(leftVc.view) | |
scrollView.addSubview(middleVertScrollVc.view) | |
scrollView.addSubview(rightVc.view) | |
leftVc.didMove(toParentViewController: self) | |
middleVertScrollVc.didMove(toParentViewController: self) | |
rightVc.didMove(toParentViewController: self) | |
scrollView.contentOffset.x = middleVertScrollVc.view.frame.origin.x | |
scrollView.delegate = self | |
} | |
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { | |
self.initialContentOffset = scrollView.contentOffset | |
} | |
public func scrollViewDidScroll(_ scrollView: UIScrollView) { | |
if delegate != nil && !delegate!.outerScrollViewShouldScroll() && !directionLockDisabled { | |
let newOffset = CGPoint(x: self.initialContentOffset.x, y: self.initialContentOffset.y) | |
self.scrollView!.setContentOffset(newOffset, animated: false) | |
} | |
if maximumWidthFirstView != 0 | |
{ | |
if scrollView.contentOffset.x < maximumWidthFirstView | |
{ | |
scrollView.isScrollEnabled = false | |
let newOffset = CGPoint(x: maximumWidthFirstView, y: self.initialContentOffset.y) | |
self.scrollView!.setContentOffset(newOffset, animated: false) | |
scrollView.isScrollEnabled = true | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
public class BaseVerticalScrollViewController: UIViewController, ContainerViewControllerDelegate { | |
public var topVc: UIViewController! | |
public var middleVc: UIViewController! | |
public var bottomVc: UIViewController! | |
public var scrollView: UIScrollView! | |
public class func verticalScrollVcWith(middleVc: UIViewController, | |
topVc: UIViewController?=nil, | |
bottomVc: UIViewController?=nil) -> BaseVerticalScrollViewController { | |
let middleScrollVc = BaseVerticalScrollViewController() | |
middleScrollVc.topVc = topVc | |
middleScrollVc.middleVc = middleVc | |
middleScrollVc.bottomVc = bottomVc | |
return middleScrollVc | |
} | |
override public func viewDidLoad() { | |
super.viewDidLoad() | |
// Do any additional setup after loading the view: | |
setupScrollView() | |
} | |
func setupScrollView() { | |
scrollView = UIScrollView() | |
scrollView.isPagingEnabled = true | |
scrollView.showsVerticalScrollIndicator = false | |
scrollView.bounces = false | |
let view = ( | |
x: self.view.bounds.origin.x, | |
y: self.view.bounds.origin.y, | |
width: self.view.bounds.width, | |
height: self.view.bounds.height | |
) | |
scrollView.frame = CGRect(x: view.x, y: view.y, width: view.width, height: view.height) | |
self.view.addSubview(scrollView) | |
let scrollWidth: CGFloat = view.width | |
var scrollHeight: CGFloat | |
switch (topVc, bottomVc) { | |
case (nil, nil): | |
scrollHeight = view.height | |
middleVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height) | |
addChildViewController(middleVc) | |
scrollView.addSubview(middleVc.view) | |
middleVc.didMove(toParentViewController: self) | |
case (_?, nil): | |
scrollHeight = 2 * view.height | |
topVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height) | |
middleVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height) | |
addChildViewController(topVc) | |
addChildViewController(middleVc) | |
scrollView.addSubview(topVc.view) | |
scrollView.addSubview(middleVc.view) | |
topVc.didMove(toParentViewController: self) | |
middleVc.didMove(toParentViewController: self) | |
scrollView.contentOffset.y = middleVc.view.frame.origin.y | |
case (nil, _?): | |
scrollHeight = 2 * view.height | |
middleVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height) | |
bottomVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height) | |
addChildViewController(middleVc) | |
addChildViewController(bottomVc) | |
scrollView.addSubview(middleVc.view) | |
scrollView.addSubview(bottomVc.view) | |
middleVc.didMove(toParentViewController: self) | |
bottomVc.didMove(toParentViewController: self) | |
scrollView.contentOffset.y = 0 | |
default: | |
scrollHeight = 3 * view.height | |
topVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height) | |
middleVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height) | |
bottomVc.view.frame = CGRect(x: 0, y: 2 * view.height, width: view.width, height: view.height) | |
addChildViewController(topVc) | |
addChildViewController(middleVc) | |
addChildViewController(bottomVc) | |
scrollView.addSubview(topVc.view) | |
scrollView.addSubview(middleVc.view) | |
scrollView.addSubview(bottomVc.view) | |
topVc.didMove(toParentViewController: self) | |
middleVc.didMove(toParentViewController: self) | |
bottomVc.didMove(toParentViewController: self) | |
scrollView.contentOffset.y = middleVc.view.frame.origin.y | |
} | |
scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight) | |
} | |
// MARK: - ContainerViewControllerDelegate Methods | |
public func outerScrollViewShouldScroll() -> Bool { | |
if scrollView.contentOffset.y < middleVc.view.frame.origin.y || scrollView.contentOffset.y > 2*middleVc.view.frame.origin.y { | |
return false | |
} else { | |
return true | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Using storyboard | |
let storyboard = UIStoryboard(name: "Main", bundle: nil) | |
let left = storyboard.instantiateViewController(withIdentifier: "left") | |
let middle = storyboard.instantiateViewController(withIdentifier: "middle") | |
let right = storyboard.instantiateViewController(withIdentifier: "right") | |
let top = storyboard.instantiateViewController(withIdentifier: "top") | |
let bottom = storyboard.instantiateViewController(withIdentifier: "bottom") | |
let container = BaseScrollViewController.containerViewWith(left,middleVC: middle,rightVC: right,topVC: top,bottomVC: bottom) | |
container.maximumWidthFirstView = 125 | |
//without Using storyboard (Programmatically) | |
let left = LeftController() | |
let middle = MiddleController() | |
let right = rightController() | |
let top = TopController() | |
let bottom = BottomController() | |
let container = BaseScrollViewController.containerViewWith(left,middleVC: middle,rightVC: right,topVC: top,bottomVC: bottom) | |
container.maximumWidthFirstView = 125 | |
Author
mspvirajpatel
commented
Sep 14, 2017
•
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment