diff --git a/PagingMenuController.xcodeproj/project.pbxproj b/PagingMenuController.xcodeproj/project.pbxproj
index 24d3a90e..963bc06c 100644
--- a/PagingMenuController.xcodeproj/project.pbxproj
+++ b/PagingMenuController.xcodeproj/project.pbxproj
@@ -132,7 +132,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
- LastUpgradeCheck = 0640;
+ LastUpgradeCheck = 0940;
ORGANIZATIONNAME = kitasuke;
TargetAttributes = {
ECE530661B6DEB18001CF201 = {
@@ -194,13 +194,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
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_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
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_OBJC_ROOT_CLASS = YES_ERROR;
+ 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";
@@ -208,6 +218,7 @@
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@@ -243,13 +254,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
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_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
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_OBJC_ROOT_CLASS = YES_ERROR;
+ 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";
@@ -269,6 +290,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
@@ -281,6 +303,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -289,10 +312,11 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.yusuke.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 4.0;
};
name = Debug;
};
@@ -300,6 +324,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -308,9 +333,10 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.yusuke.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 4.0;
};
name = Release;
};
diff --git a/PagingMenuController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PagingMenuController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 00000000..18d98100
--- /dev/null
+++ b/PagingMenuController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/PagingMenuController.xcodeproj/xcshareddata/xcschemes/PagingMenuController.xcscheme b/PagingMenuController.xcodeproj/xcshareddata/xcschemes/PagingMenuController.xcscheme
index 4a4595cd..a9d5489f 100644
--- a/PagingMenuController.xcodeproj/xcshareddata/xcschemes/PagingMenuController.xcscheme
+++ b/PagingMenuController.xcodeproj/xcshareddata/xcschemes/PagingMenuController.xcscheme
@@ -1,6 +1,6 @@
+ shouldUseLaunchSchemeArgsEnv = "YES">
@@ -62,15 +62,18 @@
ReferencedContainer = "container:PagingMenuController.xcodeproj">
+
+
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
- com.yusuke.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
diff --git a/Pod/Classes/MenuItemView.swift b/Pod/Classes/MenuItemView.swift
index 44e92278..54827c7c 100644
--- a/Pod/Classes/MenuItemView.swift
+++ b/Pod/Classes/MenuItemView.swift
@@ -58,7 +58,7 @@ open class MenuItemView: UIView {
return imageView
}()
- fileprivate var menuOptions: MenuViewCustomizable!
+ fileprivate(set) var menuOptions: MenuViewCustomizable!
fileprivate var menuItemOptions: MenuItemViewCustomizable!
fileprivate var widthConstraint: NSLayoutConstraint!
fileprivate var descriptionWidthConstraint: NSLayoutConstraint!
@@ -303,7 +303,7 @@ extension MenuItemView {
fileprivate func estimatedLabelSize(_ label: UILabel) -> CGSize {
guard let text = label.text else { return .zero }
- return NSString(string: text).boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: label.font], context: nil).size
+ return NSString(string: text).boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [kCTFontAttributeName as NSAttributedStringKey: label.font], context: nil).size
}
fileprivate func calculateLabelSize(_ label: UILabel, maxWidth: CGFloat) -> CGSize {
diff --git a/Pod/Classes/MenuView.swift b/Pod/Classes/MenuView.swift
index 6eba4054..de1bf445 100644
--- a/Pod/Classes/MenuView.swift
+++ b/Pod/Classes/MenuView.swift
@@ -11,10 +11,10 @@ import UIKit
open class MenuView: UIScrollView {
public fileprivate(set) var currentMenuItemView: MenuItemView!
- internal fileprivate(set) var menuItemViews = [MenuItemView]()
+ public fileprivate(set) var menuItemViews = [MenuItemView]()
internal var onMove: ((MenuMoveState) -> Void)?
- fileprivate var menuOptions: MenuViewCustomizable!
+ public var menuOptions: MenuViewCustomizable!
fileprivate var sortedMenuItemViews = [MenuItemView]()
fileprivate let contentView: UIView = {
$0.translatesAutoresizingMaskIntoConstraints = false
@@ -30,16 +30,29 @@ open class MenuView: UIScrollView {
fileprivate var menuViewBounces: Bool {
switch menuOptions.displayMode {
case .standard(_, _, .scrollEnabledAndBouces),
- .infinite(_, .scrollEnabledAndBouces): return true
+ .standard(_, _, .freeScroll),
+ .infinite(_, .scrollEnabledAndBouces),
+ .infinite(_, .freeScroll): return true
default: return false
}
}
+ var freescroll:Bool {
+ switch menuOptions.displayMode {
+ case .standard(_, _, .freeScroll),
+ .infinite(_, .freeScroll):
+ return true
+ default:
+ return false
+ }
+ }
fileprivate var menuViewScrollEnabled: Bool {
switch menuOptions.displayMode {
case .standard(_, _, .scrollEnabledAndBouces),
.standard(_, _, .scrollEnabled),
+ .standard(_, _, .freeScroll),
.infinite(_, .scrollEnabledAndBouces),
- .infinite(_, .scrollEnabled): return true
+ .infinite(_, .scrollEnabled),
+ .infinite(_, .freeScroll): return true
default: return false
}
}
@@ -78,7 +91,7 @@ open class MenuView: UIScrollView {
fileprivate var currentIndex: Int = 0
// MARK: - Lifecycle
- internal init(menuOptions: MenuViewCustomizable) {
+ public init(menuOptions: MenuViewCustomizable) {
super.init(frame: CGRect(x: 0, y: 0, width: 0, height: menuOptions.height))
self.menuOptions = menuOptions
@@ -108,8 +121,43 @@ open class MenuView: UIScrollView {
}
// MARK: - Internal method
+ public func scrollBetween(toPage: Int, percent:CGFloat){
+ guard toPage >= 0 && toPage < menuItemViews.count else {
+ return
+ }
+ guard case .underline(_, _, let horizontalPadding, _) = menuOptions.focusMode else { return }
+ let previousMenuItem = menuItemViews[currentPage]
+ let previousFrame = previousMenuItem.frame
+ let targetMenuItem = menuItemViews[toPage]
+ let targetFrame = targetMenuItem.frame
+ let differencePos = ((targetFrame.minX - previousFrame.minX)*percent)
+ let differenceSize = (previousFrame.width*(1-percent) + targetFrame.width*percent)
+ underlineView.frame.origin.x = previousFrame.minX + differencePos + horizontalPadding
+ underlineView.frame.size.width = differenceSize - horizontalPadding * 2
+
+ guard case .text(let title) = menuOptions.itemsOptions[0].displayMode else { return }
+ previousMenuItem.titleLabel.textColor = addColor(multiplyColor(title.selectedColor, by: (1-percent)), with: multiplyColor(title.color, by: percent))
+ targetMenuItem.titleLabel.textColor = addColor(multiplyColor(title.selectedColor, by: percent), with: multiplyColor(title.color, by: (1-percent)))
+ }
+ ///simply put coloe function in here.
+ private func addColor(_ color1: UIColor, with color2: UIColor) -> UIColor {
+ var (r1, g1, b1, a1) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
+ var (r2, g2, b2, a2) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
+
+ color1.getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
+ color2.getRed(&r2, green: &g2, blue: &b2, alpha: &a2)
+
+ // add the components, but don't let them go above 1.0
+ return UIColor(red: min(r1 + r2, 1), green: min(g1 + g2, 1), blue: min(b1 + b2, 1), alpha: (a1 + a2) / 2)
+ }
- internal func move(toPage page: Int, animated: Bool = true) {
+ private func multiplyColor(_ color: UIColor, by multiplier: CGFloat) -> UIColor {
+ var (r, g, b, a) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
+ color.getRed(&r, green: &g, blue: &b, alpha: &a)
+ return UIColor(red: r * multiplier, green: g * multiplier, blue: b * multiplier, alpha: a)
+ }
+
+ public func move(toPage page: Int, animated: Bool = true) {
// hide menu view when constructing itself
if !animated {
alpha = 0
@@ -129,9 +177,7 @@ open class MenuView: UIScrollView {
let duration = animated ? menuOptions.animationDuration : 0
UIView.animate(withDuration: duration, animations: { [unowned self] () -> Void in
self.focusMenuItem()
- if self.menuOptions.selectedItemCenter {
- self.positionMenuItemViews()
- }
+ self.positionMenuItemViews()
}) { [weak self] (_) in
guard let _ = self else { return }
@@ -139,9 +185,8 @@ open class MenuView: UIScrollView {
if case .infinite = self!.menuOptions.displayMode {
self!.relayoutMenuItemViews()
}
- if self!.menuOptions.selectedItemCenter {
- self!.positionMenuItemViews()
- }
+ self!.positionMenuItemViews()
+
self!.setNeedsLayout()
self!.layoutIfNeeded()
@@ -163,7 +208,7 @@ open class MenuView: UIScrollView {
}
setNeedsLayout()
layoutIfNeeded()
-
+
animateUnderlineViewIfNeeded()
animateRoundRectViewIfNeeded()
}
@@ -205,7 +250,7 @@ open class MenuView: UIScrollView {
contentView.heightAnchor.constraint(equalTo: heightAnchor)
])
}
-
+
fileprivate func constructMenuItemViews(_ menuOptions: MenuViewCustomizable) {
constructMenuItemViews({
return MenuItemView(menuOptions: menuOptions, menuItemOptions: menuOptions.itemsOptions[$0], addDiveder: $1)
@@ -302,14 +347,17 @@ open class MenuView: UIScrollView {
roundRectView.frame.origin.x = targetFrame.minX + horizontalPadding
roundRectView.frame.size.width = targetFrame.width - horizontalPadding * 2
}
-
+
fileprivate func relayoutMenuItemViews() {
sortMenuItemViews()
layoutMenuItemViews()
}
-
+
fileprivate func positionMenuItemViews() {
- contentOffset.x = contentOffsetX
+ let item = self.currentMenuItemView.frame
+ if self.menuOptions.selectedItemCenter || !bounds.contains(item) {
+ contentOffset.x = contentOffsetX
+ }
animateUnderlineViewIfNeeded()
animateRoundRectViewIfNeeded()
}
@@ -340,7 +388,7 @@ open class MenuView: UIScrollView {
self.currentMenuItemView = $0
}
}
-
+
// make selected item foreground
sortedMenuItemViews.forEach { $0.layer.zPosition = isSelected($0) ? 0 : -1 }
@@ -350,13 +398,13 @@ open class MenuView: UIScrollView {
}
extension MenuView: Pagable {
- var currentPage: Int {
+ public var currentPage: Int {
return currentIndex
}
- var previousPage: Int {
+ public var previousPage: Int {
return currentPage - 1 < 0 ? menuItemCount - 1 : currentPage - 1
}
- var nextPage: Int {
+ public var nextPage: Int {
return currentPage + 1 > menuItemCount - 1 ? 0 : currentPage + 1
}
func update(currentPage page: Int) {
diff --git a/Pod/Classes/PagingMenuController.swift b/Pod/Classes/PagingMenuController.swift
index e8344a5f..a5d9a9b7 100644
--- a/Pod/Classes/PagingMenuController.swift
+++ b/Pod/Classes/PagingMenuController.swift
@@ -16,6 +16,7 @@ public enum MenuMoveState {
case didMoveController(to: UIViewController, from: UIViewController)
case willMoveItem(to: MenuItemView, from: MenuItemView)
case didMoveItem(to: MenuItemView, from: MenuItemView)
+ case scrollingView(toPage:Int, percent:CGFloat)
case didScrollStart
case didScrollEnd
}
@@ -24,6 +25,8 @@ internal let MinimumSupportedViewCount = 1
internal let VisiblePagingViewNumber = 3
open class PagingMenuController: UIViewController {
+ var initialOffset:CGPoint = .zero
+
public fileprivate(set) var menuView: MenuView? {
didSet {
guard let menuView = menuView else { return }
@@ -138,8 +141,9 @@ open class PagingMenuController: UIViewController {
constructPagingViewController()
layoutPagingViewController()
}
-
+ var movingPageAutomatically = false
open func move(toPage page: Int, animated: Bool = true) {
+ movingPageAutomatically = true
switch options.componentType {
case .menuView, .all:
// ignore an unexpected page number
@@ -184,11 +188,12 @@ open class PagingMenuController: UIViewController {
}
let completionClosure = { [weak self] (_: Bool) -> Void in
pagingViewController.relayoutPagingViewControllers()
-
+
// show paging views
self?.showPagingMenuControllers()
-
+
self?.onMove?(.didMoveController(to: nextPagingViewController, from: previousPagingViewController))
+ self?.movingPageAutomatically = false
}
if duration > 0 {
UIView.animate(withDuration: duration, animations: animationClosure, completion: completionClosure)
@@ -242,7 +247,7 @@ open class PagingMenuController: UIViewController {
menuView.setNeedsLayout()
menuView.layoutIfNeeded()
}
-
+
fileprivate func constructPagingViewController() {
let viewControllers: [UIViewController]
switch options.componentType {
@@ -253,7 +258,7 @@ open class PagingMenuController: UIViewController {
pagingViewController = PagingViewController(viewControllers: viewControllers, options: options)
}
-
+
fileprivate func layoutPagingViewController() {
guard let pagingViewController = pagingViewController else { return }
@@ -314,31 +319,52 @@ extension PagingMenuController: UIScrollViewDelegate {
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
onMove?(.didScrollEnd)
+ var contentScrollView:Bool = false
let nextPage: Int
switch (scrollView, pagingViewController, menuView) {
case let (scrollView, pagingViewController?, _) where scrollView.isEqual(pagingViewController.contentScrollView):
nextPage = nextPageFromCurrentPosition
+ contentScrollView = true
case let (scrollView, _, menuView?) where scrollView.isEqual(menuView):
nextPage = nextPageFromCurrentPoint
default: return
}
-
- move(toPage: nextPage)
+ if !(menuView?.freescroll ?? false) || contentScrollView {
+ move(toPage: nextPage)
+ }
}
-
+
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
+ self.initialOffset = scrollView.contentOffset
+ self.movingPageAutomatically = false
onMove?(.didScrollStart)
}
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
switch (scrollView, decelerate) {
- case (let scrollView, false) where scrollView.isEqual(menuView): break
+ case (let scrollView, false) where scrollView.isEqual(menuView) && !(menuView?.freescroll ?? false): break
default: return
}
let nextPage = nextPageFromCurrentPoint
move(toPage: nextPage)
}
+
+ public func scrollViewDidScroll(_ scrollView: UIScrollView) {
+ guard scrollView != self.menuView else {return}
+ let percent:CGFloat
+ let page:Int
+ if initialOffset.x > scrollView.contentOffset.x {
+ page = movingPageAutomatically ? currentPage : currentPage - 1
+ percent = (initialOffset.x - scrollView.contentOffset.x)/self.view.frame.width
+ }else {
+ page = movingPageAutomatically ? currentPage : currentPage + 1
+ percent = (scrollView.contentOffset.x - initialOffset.x)/self.view.frame.width
+ }
+ // print(page, percent)
+ menuView?.scrollBetween(toPage: page, percent: percent)
+ onMove?(.scrollingView(toPage: page, percent:percent))
+ }
}
extension PagingMenuController: Pagable {
@@ -478,7 +504,7 @@ extension PagingMenuController {
menuView?.addGestureRecognizer(rightSwipeGestureRecognizer)
}
- internal func handleTapGesture(_ recognizer: UITapGestureRecognizer) {
+ @objc internal func handleTapGesture(_ recognizer: UITapGestureRecognizer) {
guard let menuItemView = recognizer.view as? MenuItemView,
let menuView = menuView,
let page = menuView.menuItemViews.index(of: menuItemView),
@@ -503,7 +529,7 @@ extension PagingMenuController {
move(toPage: newPage)
}
- internal func handleSwipeGesture(_ recognizer: UISwipeGestureRecognizer) {
+ @objc internal func handleSwipeGesture(_ recognizer: UISwipeGestureRecognizer) {
guard let menuView = recognizer.view as? MenuView,
let menuOptions = menuOptions else { return }
diff --git a/Pod/Classes/Protocols/MenuViewCustomizable.swift b/Pod/Classes/Protocols/MenuViewCustomizable.swift
index 376006b0..07db5d3c 100644
--- a/Pod/Classes/Protocols/MenuViewCustomizable.swift
+++ b/Pod/Classes/Protocols/MenuViewCustomizable.swift
@@ -74,6 +74,7 @@ public enum MenuScrollingMode {
case scrollEnabled
case scrollEnabledAndBouces
case pagingEnabled
+ case freeScroll
}
public enum MenuFocusMode {