Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Kazuhiro Hayashi committed Jul 2, 2017
0 parents commit 44d16ac
Show file tree
Hide file tree
Showing 11 changed files with 1,109 additions and 0 deletions.
436 changes: 436 additions & 0 deletions PagingKit.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
99 changes: 99 additions & 0 deletions PagingKit.xcodeproj/xcshareddata/xcschemes/PagingKit.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0830"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6EC140BA1F0940F40054B514"
BuildableName = "PagingKit.framework"
BlueprintName = "PagingKit"
ReferencedContainer = "container:PagingKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6EC140C31F0940F40054B514"
BuildableName = "PagingKitTests.xctest"
BlueprintName = "PagingKitTests"
ReferencedContainer = "container:PagingKit.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6EC140BA1F0940F40054B514"
BuildableName = "PagingKit.framework"
BlueprintName = "PagingKit"
ReferencedContainer = "container:PagingKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6EC140BA1F0940F40054B514"
BuildableName = "PagingKit.framework"
BlueprintName = "PagingKit"
ReferencedContainer = "container:PagingKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6EC140BA1F0940F40054B514"
BuildableName = "PagingKit.framework"
BlueprintName = "PagingKit"
ReferencedContainer = "container:PagingKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>PagingKit.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>6EC140BA1F0940F40054B514</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>6EC140C31F0940F40054B514</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
24 changes: 24 additions & 0 deletions PagingKit/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
179 changes: 179 additions & 0 deletions PagingKit/PagingContentViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//
// PagingContentViewController.swift
// PagingViewController
//
// Created by Kazuhiro Hayashi on 7/2/17.
// Copyright © 2017 Kazuhiro Hayashi. All rights reserved.
//

import UIKit

public protocol PagingContentViewControllerDelegate: class {

func contentViewController(viewController: PagingContentViewController, willBeginScrollFrom index: Int)
func contentViewController(viewController: PagingContentViewController, didScrollOn index: Int?, percent: CGFloat)
func contentViewController(viewController: PagingContentViewController, didEndScrollFrom previousIndex: Int, to nextIndex: Int, transitionComplete: Bool)
}

extension PagingContentViewControllerDelegate {

func contentViewController(viewController: PagingContentViewController, willBeginScrollFrom index: Int){}
func contentViewController(viewController: PagingContentViewController, didScrollOn index: Int?, percent: CGFloat) {}
func contentViewController(viewController: PagingContentViewController, didEndScrollFrom previousIndex: Int, to nextIndex: Int, transitionComplete: Bool) {}
}

public protocol PagingContentViewControllerDataSource: class {
func numberOfItemForContentViewController(viewController: PagingContentViewController) -> Int
func contentViewController(viewController: PagingContentViewController, viewControllerAt Index: Int) -> UIViewController
}

public class PagingContentViewController: UIViewController {
private var cachedViewControllers = [UIViewController?]()

public weak var delegate: PagingContentViewControllerDelegate?
public weak var dataSource: PagingContentViewControllerDataSource?

public var contentOffsetRatio: CGFloat {
return scrollView.contentOffset.x / (scrollView.contentSize.width - scrollView.bounds.width)
}

public var pagingPercent: CGFloat {
return scrollView.contentOffset.x.truncatingRemainder(dividingBy: scrollView.bounds.width) / scrollView.bounds.width
}

public func scroll(to page: Int, animated: Bool) {
isProgramaticallyScrolling = true
let offsetX = scrollView.bounds.width * CGFloat(page)
let offset = CGPoint(x: offsetX, y: 0)
loadPagesIfNeeded(page: page)
scrollView.setContentOffset(offset, animated: animated)
if !animated {
isProgramaticallyScrolling = false
}
}

fileprivate var numberOfPages: Int = 0

fileprivate var lastContentOffset = CGPoint.zero
fileprivate var leftSidePageIndex = 0
fileprivate(set) var isProgramaticallyScrolling = false

fileprivate let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.isPagingEnabled = true
scrollView.bounces = false
scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleLeftMargin]
scrollView.translatesAutoresizingMaskIntoConstraints = true
return scrollView
}()

override public func viewDidLoad() {
super.viewDidLoad()

scrollView.frame = view.bounds
scrollView.delegate = self
view.addSubview(scrollView)
}

override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

if cachedViewControllers.isEmpty {
initialLoad(with: 0)
}
}

override public func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: view.bounds.size.width * CGFloat(numberOfPages), height: view.bounds.size.height)
cachedViewControllers.enumerated().forEach { (offset, vc) in
vc?.view.frame = scrollView.bounds
vc?.view.frame.origin.x = scrollView.bounds.width * CGFloat(offset)
}
}

override public func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

override public func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)

let currentIndex = Int(scrollView.contentOffset.x / scrollView.bounds.width)
coordinator.animate(alongsideTransition: { [weak self] (context) in
guard let _self = self else { return }
_self.initialLoad(with: currentIndex)

let point = CGPoint(x: _self.scrollView.bounds.width * CGFloat(currentIndex), y: 0)
_self.scrollView.setContentOffset(point, animated: false)
}) { (context) in }
}

fileprivate func initialLoad(with page: Int) {
scrollView.subviews.forEach { $0.removeFromSuperview() }
childViewControllers.forEach { $0.removeFromParentViewController() }

numberOfPages = dataSource?.numberOfItemForContentViewController(viewController: self) ?? 0
cachedViewControllers = Array(repeating: nil, count: numberOfPages)

loadScrollView(with: page - 1)
loadScrollView(with: page)
loadScrollView(with: page + 1)
}

fileprivate func loadScrollView(with page: Int) {
guard (0..<cachedViewControllers.count) ~= page else { return }

if case nil = cachedViewControllers[page], let dataSource = dataSource {
let vc = dataSource.contentViewController(viewController: self, viewControllerAt: page)
addChildViewController(vc)
vc.view.frame = scrollView.bounds
vc.view.frame.origin.x = scrollView.bounds.width * CGFloat(page)
scrollView.addSubview(vc.view)
vc.didMove(toParentViewController: self)
cachedViewControllers[page] = vc
}
}
}

extension PagingContentViewController: UIScrollViewDelegate {
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
guard !isProgramaticallyScrolling else { return }

delegate?.contentViewController(viewController: self, willBeginScrollFrom: leftSidePageIndex)
}

public func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard !isProgramaticallyScrolling else { return }

let leftSideContentOffset = CGFloat(leftSidePageIndex) * scrollView.bounds.width
let percent = (scrollView.contentOffset.x - leftSideContentOffset) / scrollView.bounds.width

delegate?.contentViewController(viewController: self, didScrollOn: leftSidePageIndex, percent: min(max(0, percent), 1))

lastContentOffset = scrollView.contentOffset
leftSidePageIndex = Int(scrollView.contentOffset.x / scrollView.bounds.width)
}

public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
loadPagesIfNeeded()
}

public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
loadPagesIfNeeded()
}
}

public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
isProgramaticallyScrolling = false
}

fileprivate func loadPagesIfNeeded(page: Int? = nil) {
let currentIndex = Int(scrollView.contentOffset.x / scrollView.bounds.width)
let loadingPage = page ?? currentIndex
loadScrollView(with: loadingPage - 1)
loadScrollView(with: loadingPage)
loadScrollView(with: loadingPage + 1)
}
}
19 changes: 19 additions & 0 deletions PagingKit/PagingKit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// PagingKit.h
// PagingKit
//
// Created by Kazuhiro Hayashi on 7/2/17.
// Copyright © 2017 Kazuhiro Hayashi. All rights reserved.
//

#import <UIKit/UIKit.h>

//! Project version number for PagingKit.
FOUNDATION_EXPORT double PagingKitVersionNumber;

//! Project version string for PagingKit.
FOUNDATION_EXPORT const unsigned char PagingKitVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <PagingKit/PublicHeader.h>


Loading

0 comments on commit 44d16ac

Please sign in to comment.