Skip to content
This repository was archived by the owner on Jun 17, 2018. It is now read-only.

Adding Free scroll option #380

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions PagingMenuController.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0640;
LastUpgradeCheck = 0940;
ORGANIZATIONNAME = kitasuke;
TargetAttributes = {
ECE530661B6DEB18001CF201 = {
Expand Down Expand Up @@ -194,20 +194,31 @@
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";
COPY_PHASE_STRIP = NO;
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;
Expand Down Expand Up @@ -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";
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -289,17 +312,19 @@
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;
};
ECE5307F1B6DEB18001CF201 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
Expand All @@ -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;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0640"
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down Expand Up @@ -37,10 +37,10 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
Expand All @@ -62,15 +62,18 @@
ReferencedContainer = "container:PagingMenuController.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
Expand All @@ -85,10 +88,10 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
Expand Down
2 changes: 1 addition & 1 deletion PagingMenuController/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.yusuke.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
Expand Down
4 changes: 2 additions & 2 deletions Pod/Classes/MenuItemView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down Expand Up @@ -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 {
Expand Down
90 changes: 69 additions & 21 deletions Pod/Classes/MenuView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -129,19 +177,16 @@ 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 }

// relayout menu item views dynamically
if case .infinite = self!.menuOptions.displayMode {
self!.relayoutMenuItemViews()
}
if self!.menuOptions.selectedItemCenter {
self!.positionMenuItemViews()
}
self!.positionMenuItemViews()

self!.setNeedsLayout()
self!.layoutIfNeeded()

Expand All @@ -163,7 +208,7 @@ open class MenuView: UIScrollView {
}
setNeedsLayout()
layoutIfNeeded()

animateUnderlineViewIfNeeded()
animateRoundRectViewIfNeeded()
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -340,7 +388,7 @@ open class MenuView: UIScrollView {
self.currentMenuItemView = $0
}
}

// make selected item foreground
sortedMenuItemViews.forEach { $0.layer.zPosition = isSelected($0) ? 0 : -1 }

Expand All @@ -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) {
Expand Down
Loading