Commit 1fd7ceeb by Daniel Dahan

development: updated FABMenuItem to hide titleLabel when title value is empty

parent 5a438b88
...@@ -101,7 +101,7 @@ ...@@ -101,7 +101,7 @@
965E810B1DD4D5C800D61E4B /* RobotoFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7941CB40DC500C806FE /* RobotoFont.swift */; }; 965E810B1DD4D5C800D61E4B /* RobotoFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7941CB40DC500C806FE /* RobotoFont.swift */; };
965E810C1DD4D5C800D61E4B /* DynamicFontType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9628645E1D540AF300690B69 /* DynamicFontType.swift */; }; 965E810C1DD4D5C800D61E4B /* DynamicFontType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9628645E1D540AF300690B69 /* DynamicFontType.swift */; };
965E810D1DD4D5C800D61E4B /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB78E1CB40DC500C806FE /* Menu.swift */; }; 965E810D1DD4D5C800D61E4B /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB78E1CB40DC500C806FE /* Menu.swift */; };
965E810E1DD4D5C800D61E4B /* MenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9697F7B61D8F22A4004741EC /* MenuItem.swift */; }; 965E810E1DD4D5C800D61E4B /* FABMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9697F7B61D8F22A4004741EC /* FABMenuItem.swift */; };
965E810F1DD4D5C800D61E4B /* MenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB78F1CB40DC500C806FE /* MenuController.swift */; }; 965E810F1DD4D5C800D61E4B /* MenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB78F1CB40DC500C806FE /* MenuController.swift */; };
965E81101DD4D5C800D61E4B /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7901CB40DC500C806FE /* NavigationBar.swift */; }; 965E81101DD4D5C800D61E4B /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7901CB40DC500C806FE /* NavigationBar.swift */; };
965E81111DD4D5C800D61E4B /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7911CB40DC500C806FE /* NavigationController.swift */; }; 965E81111DD4D5C800D61E4B /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7911CB40DC500C806FE /* NavigationController.swift */; };
...@@ -135,7 +135,7 @@ ...@@ -135,7 +135,7 @@
9697F7C11D8F2572004741EC /* Material+Array.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96C1C8801D42C62800E6608F /* Material+Array.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 9697F7C11D8F2572004741EC /* Material+Array.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96C1C8801D42C62800E6608F /* Material+Array.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9697F7C21D8F2572004741EC /* Material+UIWindow.swift in Headers */ = {isa = PBXBuildFile; fileRef = 962864591D53FE3E00690B69 /* Material+UIWindow.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 9697F7C21D8F2572004741EC /* Material+UIWindow.swift in Headers */ = {isa = PBXBuildFile; fileRef = 962864591D53FE3E00690B69 /* Material+UIWindow.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9697F7C31D8F2572004741EC /* DynamicFontType.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9628645E1D540AF300690B69 /* DynamicFontType.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 9697F7C31D8F2572004741EC /* DynamicFontType.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9628645E1D540AF300690B69 /* DynamicFontType.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9697F7C51D8F2573004741EC /* MenuItem.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9697F7B61D8F22A4004741EC /* MenuItem.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 9697F7C51D8F2573004741EC /* FABMenuItem.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9697F7B61D8F22A4004741EC /* FABMenuItem.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9697F7CB1D8F2573004741EC /* Snackbar.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963FBEFC1D669510008F8512 /* Snackbar.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 9697F7CB1D8F2573004741EC /* Snackbar.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963FBEFC1D669510008F8512 /* Snackbar.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9697F7CC1D8F2573004741EC /* SnackbarController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 961EFC571D738FF600E84652 /* SnackbarController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 9697F7CC1D8F2573004741EC /* SnackbarController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 961EFC571D738FF600E84652 /* SnackbarController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9697F7CD1D8F2582004741EC /* Color.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9661222D1D3EC414008BB4CB /* Color.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 9697F7CD1D8F2582004741EC /* Color.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9661222D1D3EC414008BB4CB /* Color.swift */; settings = {ATTRIBUTES = (Public, ); }; };
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
967887881C9777CB0037F6C9 /* MaterialViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialViewTests.swift; sourceTree = "<group>"; }; 967887881C9777CB0037F6C9 /* MaterialViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialViewTests.swift; sourceTree = "<group>"; };
967A48181D0F425A00B8CEB7 /* StatusBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarController.swift; sourceTree = "<group>"; }; 967A48181D0F425A00B8CEB7 /* StatusBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarController.swift; sourceTree = "<group>"; };
968C99461D377849000074FF /* Offset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Offset.swift; sourceTree = "<group>"; }; 968C99461D377849000074FF /* Offset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Offset.swift; sourceTree = "<group>"; };
9697F7B61D8F22A4004741EC /* MenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuItem.swift; sourceTree = "<group>"; }; 9697F7B61D8F22A4004741EC /* FABMenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FABMenuItem.swift; sourceTree = "<group>"; };
96A183621E0C6CE200083C30 /* FABMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FABMenu.swift; sourceTree = "<group>"; }; 96A183621E0C6CE200083C30 /* FABMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FABMenu.swift; sourceTree = "<group>"; };
96A183641E0C6DD400083C30 /* FABMenuController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FABMenuController.swift; sourceTree = "<group>"; }; 96A183641E0C6DD400083C30 /* FABMenuController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FABMenuController.swift; sourceTree = "<group>"; };
96A183661E0C6DE100083C30 /* FABToToolbarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FABToToolbarController.swift; sourceTree = "<group>"; }; 96A183661E0C6DE100083C30 /* FABToToolbarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FABToToolbarController.swift; sourceTree = "<group>"; };
...@@ -549,9 +549,9 @@ ...@@ -549,9 +549,9 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
96BCB78E1CB40DC500C806FE /* Menu.swift */, 96BCB78E1CB40DC500C806FE /* Menu.swift */,
9697F7B61D8F22A4004741EC /* MenuItem.swift */,
96BCB78F1CB40DC500C806FE /* MenuController.swift */, 96BCB78F1CB40DC500C806FE /* MenuController.swift */,
96A183621E0C6CE200083C30 /* FABMenu.swift */, 96A183621E0C6CE200083C30 /* FABMenu.swift */,
9697F7B61D8F22A4004741EC /* FABMenuItem.swift */,
96A183641E0C6DD400083C30 /* FABMenuController.swift */, 96A183641E0C6DD400083C30 /* FABMenuController.swift */,
96A183661E0C6DE100083C30 /* FABToToolbarController.swift */, 96A183661E0C6DE100083C30 /* FABToToolbarController.swift */,
); );
...@@ -932,7 +932,7 @@ ...@@ -932,7 +932,7 @@
9697F7C11D8F2572004741EC /* Material+Array.swift in Headers */, 9697F7C11D8F2572004741EC /* Material+Array.swift in Headers */,
9697F7C21D8F2572004741EC /* Material+UIWindow.swift in Headers */, 9697F7C21D8F2572004741EC /* Material+UIWindow.swift in Headers */,
9697F7C31D8F2572004741EC /* DynamicFontType.swift in Headers */, 9697F7C31D8F2572004741EC /* DynamicFontType.swift in Headers */,
9697F7C51D8F2573004741EC /* MenuItem.swift in Headers */, 9697F7C51D8F2573004741EC /* FABMenuItem.swift in Headers */,
9697F7CB1D8F2573004741EC /* Snackbar.swift in Headers */, 9697F7CB1D8F2573004741EC /* Snackbar.swift in Headers */,
9697F7CC1D8F2573004741EC /* SnackbarController.swift in Headers */, 9697F7CC1D8F2573004741EC /* SnackbarController.swift in Headers */,
9617B07D1DFCA8CF00410F8F /* Application.swift in Headers */, 9617B07D1DFCA8CF00410F8F /* Application.swift in Headers */,
...@@ -1171,7 +1171,7 @@ ...@@ -1171,7 +1171,7 @@
965E810B1DD4D5C800D61E4B /* RobotoFont.swift in Sources */, 965E810B1DD4D5C800D61E4B /* RobotoFont.swift in Sources */,
965E810C1DD4D5C800D61E4B /* DynamicFontType.swift in Sources */, 965E810C1DD4D5C800D61E4B /* DynamicFontType.swift in Sources */,
965E810D1DD4D5C800D61E4B /* Menu.swift in Sources */, 965E810D1DD4D5C800D61E4B /* Menu.swift in Sources */,
965E810E1DD4D5C800D61E4B /* MenuItem.swift in Sources */, 965E810E1DD4D5C800D61E4B /* FABMenuItem.swift in Sources */,
965E810F1DD4D5C800D61E4B /* MenuController.swift in Sources */, 965E810F1DD4D5C800D61E4B /* MenuController.swift in Sources */,
96A183651E0C6DD400083C30 /* FABMenuController.swift in Sources */, 96A183651E0C6DD400083C30 /* FABMenuController.swift in Sources */,
965E81101DD4D5C800D61E4B /* NavigationBar.swift in Sources */, 965E81101DD4D5C800D61E4B /* NavigationBar.swift in Sources */,
......
...@@ -41,28 +41,28 @@ public enum FABMenuDirection: Int { ...@@ -41,28 +41,28 @@ public enum FABMenuDirection: Int {
@objc(FABMenuDelegate) @objc(FABMenuDelegate)
public protocol FABMenuDelegate { public protocol FABMenuDelegate {
/** /**
A delegation method that is execited when the menu will open. A delegation method that is execited when the fabMenu will open.
- Parameter fabMenu: A FABMenu. - Parameter fabMenu: A FABMenu.
*/ */
@objc @objc
optional func fabMenuWillOpen(fabMenu: FABMenu) optional func fabMenuWillOpen(fabMenu: FABMenu)
/** /**
A delegation method that is execited when the menu did open. A delegation method that is execited when the fabMenu did open.
- Parameter fabMenu: A FABMenu. - Parameter fabMenu: A FABMenu.
*/ */
@objc @objc
optional func fabMenuDidOpen(fabMenu: FABMenu) optional func fabMenuDidOpen(fabMenu: FABMenu)
/** /**
A delegation method that is execited when the menu will close. A delegation method that is execited when the fabMenu will close.
- Parameter fabMenu: A FABMenu. - Parameter fabMenu: A FABMenu.
*/ */
@objc @objc
optional func fabMenuWillClose(fabMenu: FABMenu) optional func fabMenuWillClose(fabMenu: FABMenu)
/** /**
A delegation method that is execited when the menu did close. A delegation method that is execited when the fabMenu did close.
- Parameter fabMenu: A FABMenu. - Parameter fabMenu: A FABMenu.
*/ */
@objc @objc
...@@ -203,7 +203,21 @@ extension FABMenu { ...@@ -203,7 +203,21 @@ extension FABMenu {
- Parameter completion: A completion block to execute on each view's animation. - Parameter completion: A completion block to execute on each view's animation.
*/ */
fileprivate func open(duration: TimeInterval = 0.15, delay: TimeInterval = 0, usingSpringWithDamping: CGFloat = 0.5, initialSpringVelocity: CGFloat = 0, options: UIViewAnimationOptions = [], animations: ((UIView) -> Void)? = nil, completion: ((UIView) -> Void)? = nil) { fileprivate func open(duration: TimeInterval = 0.15, delay: TimeInterval = 0, usingSpringWithDamping: CGFloat = 0.5, initialSpringVelocity: CGFloat = 0, options: UIViewAnimationOptions = [], animations: ((UIView) -> Void)? = nil, completion: ((UIView) -> Void)? = nil) {
spring.expand(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: completion) delegate?.fabMenuWillOpen?(fabMenu: self)
spring.expand(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations) { [weak self, completion = completion] (view) in
guard let s = self else {
return
}
(view as? FABMenuItem)?.showTitleLabel()
if view == s.items.last {
s.delegate?.fabMenuDidOpen?(fabMenu: s)
}
completion?(view)
}
} }
/** /**
...@@ -217,7 +231,21 @@ extension FABMenu { ...@@ -217,7 +231,21 @@ extension FABMenu {
- Parameter completion: A completion block to execute on each view's animation. - Parameter completion: A completion block to execute on each view's animation.
*/ */
fileprivate func close(duration: TimeInterval = 0.15, delay: TimeInterval = 0, usingSpringWithDamping: CGFloat = 0.5, initialSpringVelocity: CGFloat = 0, options: UIViewAnimationOptions = [], animations: ((UIView) -> Void)? = nil, completion: ((UIView) -> Void)? = nil) { fileprivate func close(duration: TimeInterval = 0.15, delay: TimeInterval = 0, usingSpringWithDamping: CGFloat = 0.5, initialSpringVelocity: CGFloat = 0, options: UIViewAnimationOptions = [], animations: ((UIView) -> Void)? = nil, completion: ((UIView) -> Void)? = nil) {
spring.contract(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: completion) delegate?.fabMenuWillClose?(fabMenu: self)
spring.contract(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations) { [weak self, completion = completion] (view) in
guard let s = self else {
return
}
(view as? FABMenuItem)?.hideTitleLabel()
if view == s.items.last {
s.delegate?.fabMenuDidClose?(fabMenu: s)
}
completion?(view)
}
} }
} }
...@@ -243,7 +271,7 @@ extension FABMenu { ...@@ -243,7 +271,7 @@ extension FABMenu {
delegate?.fabMenu?(fabMenu: self, tappedAt: point, isOutside: true) delegate?.fabMenu?(fabMenu: self, tappedAt: point, isOutside: true)
closeMenu() close()
return self.hitTest(point, with: event) return self.hitTest(point, with: event)
} }
...@@ -257,46 +285,10 @@ extension FABMenu { ...@@ -257,46 +285,10 @@ extension FABMenu {
@objc @objc
fileprivate func handleToggleMenu(button: UIButton) { fileprivate func handleToggleMenu(button: UIButton) {
guard isOpened else { guard isOpened else {
openMenu() open()
return return
} }
closeMenu() close()
}
}
extension FABMenu {
/// Opens the menu and reveals the FABMenuItems.
open func openMenu() {
delegate?.fabMenuWillOpen?(fabMenu: self)
open { [weak self] (view) in
guard let s = self else {
return
}
(view as? FABMenuItem)?.showTitleLabel()
if view == s.items.last {
s.delegate?.fabMenuDidOpen?(fabMenu: s)
}
}
}
/// Closes the menu and hides the FABMenuItems.
open func closeMenu() {
delegate?.fabMenuWillClose?(fabMenu: self)
close { [weak self] (view) in
guard let s = self else {
return
}
(view as? FABMenuItem)?.hideTitleLabel()
if view == s.items.last {
s.delegate?.fabMenuDidClose?(fabMenu: s)
}
}
} }
} }
...@@ -59,10 +59,24 @@ open class FABMenuItem: View { ...@@ -59,10 +59,24 @@ open class FABMenuItem: View {
} }
set(value) { set(value) {
titleLabel.text = value titleLabel.text = value
hideTitleLabel() layoutSubviews()
} }
} }
open override func layoutSubviews() {
super.layoutSubviews()
guard let t = title, 0 < t.utf16.count else {
titleLabel.removeFromSuperview()
return
}
if nil == titleLabel.superview {
addSubview(titleLabel)
}
}
}
extension FABMenuItem {
/// Shows the titleLabel. /// Shows the titleLabel.
open func showTitleLabel() { open func showTitleLabel() {
let interimSpace = InterimSpacePresetToValue(preset: .interimSpace6) let interimSpace = InterimSpacePresetToValue(preset: .interimSpace6)
...@@ -88,19 +102,20 @@ open class FABMenuItem: View { ...@@ -88,19 +102,20 @@ open class FABMenuItem: View {
open func hideTitleLabel() { open func hideTitleLabel() {
titleLabel.isHidden = true titleLabel.isHidden = true
} }
}
extension FABMenuItem {
/// Prepares the button. /// Prepares the button.
private func prepareButton() { fileprivate func prepareButton() {
layout(button).edges() layout(button).edges()
} }
/// Prepares the titleLabel. /// Prepares the titleLabel.
private func prepareTitleLabel() { fileprivate func prepareTitleLabel() {
titleLabel.font = RobotoFont.regular(with: 14) titleLabel.font = RobotoFont.regular(with: 14)
titleLabel.textAlignment = .center titleLabel.textAlignment = .center
titleLabel.backgroundColor = .white titleLabel.backgroundColor = .white
titleLabel.depthPreset = button.depthPreset titleLabel.depthPreset = button.depthPreset
titleLabel.cornerRadiusPreset = .cornerRadius1 titleLabel.cornerRadiusPreset = .cornerRadius1
addSubview(titleLabel)
} }
} }
...@@ -41,7 +41,36 @@ public enum MenuDirection: Int { ...@@ -41,7 +41,36 @@ public enum MenuDirection: Int {
@objc(MenuDelegate) @objc(MenuDelegate)
public protocol MenuDelegate { public protocol MenuDelegate {
/** /**
Gets called when the user taps while the menu is opened. A delegation method that is execited when the menu will open.
- Parameter menu: A Menu.
*/
@objc
optional func menuWillOpen(menu: Menu)
/**
A delegation method that is execited when the menu did open.
- Parameter menu: A Menu.
*/
@objc
optional func menuDidOpen(menu: Menu)
/**
A delegation method that is execited when the menu will close.
- Parameter menu: A Menu.
*/
@objc
optional func menuWillClose(menu: Menu)
/**
A delegation method that is execited when the menu did close.
- Parameter menu: A Menu.
*/
@objc
optional func menuDidClose(menu: Menu)
/**
A delegation method that is executed when the user taps while
the menu is opened.
- Parameter menu: A Menu. - Parameter menu: A Menu.
- Parameter tappedAt point: A CGPoint. - Parameter tappedAt point: A CGPoint.
- Parameter isOutside: A boolean indicating whether the tap - Parameter isOutside: A boolean indicating whether the tap
...@@ -57,9 +86,6 @@ open class Menu: View, SpringableMotion { ...@@ -57,9 +86,6 @@ open class Menu: View, SpringableMotion {
/// A reference to the SpringMotion object. /// A reference to the SpringMotion object.
internal let spring = SpringMotion() internal let spring = SpringMotion()
/// An optional delegation handler.
open weak var delegate: MenuDelegate?
/// The direction in which the animation opens the menu. /// The direction in which the animation opens the menu.
open var springDirection = SpringDirection.up { open var springDirection = SpringDirection.up {
didSet { didSet {
...@@ -67,15 +93,132 @@ open class Menu: View, SpringableMotion { ...@@ -67,15 +93,132 @@ open class Menu: View, SpringableMotion {
} }
} }
/// A reference to the base UIButton.
open var button: UIButton? {
didSet {
oldValue?.removeFromSuperview()
guard let v = button else {
return
}
addSubview(v)
v.addTarget(self, action: #selector(handleToggleMenu(button:)), for: .touchUpInside)
}
}
/// Size of MenuItems.
open var itemSize: CGSize {
get {
return spring.itemSize
}
set(value) {
spring.itemSize = value
}
}
/// A preset wrapper around interimSpace.
open var interimSpacePreset: InterimSpacePreset {
get {
return spring.interimSpacePreset
}
set(value) {
spring.interimSpacePreset = value
}
}
/// The space between views.
open var interimSpace: InterimSpace {
get {
return spring.interimSpace
}
set(value) {
spring.interimSpace = value
}
}
/// A boolean indicating if the menu is open or not.
open var isOpened: Bool {
get {
return spring.isOpened
}
set(value) {
spring.isOpened = value
}
}
/// A boolean indicating if the menu is enabled.
open var isEnabled: Bool {
get {
return spring.isEnabled
}
set(value) {
spring.isEnabled = value
}
}
/// An optional delegation handler.
open weak var delegate: MenuDelegate?
/// A reference to the MenuItems /// A reference to the MenuItems
open var views: [UIView] { open var items: [UIView] {
get { get {
return spring.views return spring.views as! [UIView]
} }
set(value) { set(value) {
for v in spring.views {
v.removeFromSuperview()
}
for v in value {
addSubview(v)
}
spring.views = value spring.views = value
} }
} }
open override func layoutSubviews() {
super.layoutSubviews()
button?.frame.size = bounds.size
spring.baseSize = bounds.size
}
open override func prepare() {
super.prepare()
backgroundColor = nil
interimSpacePreset = .interimSpace6
}
}
extension Menu {
/**
Open the Menu component with animation options.
- Parameter duration: The time for each view's animation.
- Parameter delay: A delay time for each view's animation.
- Parameter usingSpringWithDamping: A damping ratio for the animation.
- Parameter initialSpringVelocity: The initial velocity for the animation.
- Parameter options: Options to pass to the animation.
- Parameter animations: An animation block to execute on each view's animation.
- Parameter completion: A completion block to execute on each view's animation.
*/
fileprivate func open(duration: TimeInterval = 0.15, delay: TimeInterval = 0, usingSpringWithDamping: CGFloat = 0.5, initialSpringVelocity: CGFloat = 0, options: UIViewAnimationOptions = [], animations: ((UIView) -> Void)? = nil, completion: ((UIView) -> Void)? = nil) {
spring.expand(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: completion)
}
/**
Close the Menu component with animation options.
- Parameter duration: The time for each view's animation.
- Parameter delay: A delay time for each view's animation.
- Parameter usingSpringWithDamping: A damping ratio for the animation.
- Parameter initialSpringVelocity: The initial velocity for the animation.
- Parameter options: Options to pass to the animation.
- Parameter animations: An animation block to execute on each view's animation.
- Parameter completion: A completion block to execute on each view's animation.
*/
fileprivate func close(duration: TimeInterval = 0.15, delay: TimeInterval = 0, usingSpringWithDamping: CGFloat = 0.5, initialSpringVelocity: CGFloat = 0, options: UIViewAnimationOptions = [], animations: ((UIView) -> Void)? = nil, completion: ((UIView) -> Void)? = nil) {
spring.contract(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: completion)
}
} }
extension Menu { extension Menu {
...@@ -86,7 +229,7 @@ extension Menu { ...@@ -86,7 +229,7 @@ extension Menu {
- Returns: An optional UIView. - Returns: An optional UIView.
*/ */
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard spring.isOpened, spring.isEnabled else { guard isOpened, isEnabled else {
return super.hitTest(point, with: event) return super.hitTest(point, with: event)
} }
...@@ -100,36 +243,24 @@ extension Menu { ...@@ -100,36 +243,24 @@ extension Menu {
delegate?.menu?(menu: self, tappedAt: point, isOutside: true) delegate?.menu?(menu: self, tappedAt: point, isOutside: true)
close()
return self.hitTest(point, with: event) return self.hitTest(point, with: event)
} }
} }
extension Menu { extension Menu {
/** /**
Open the Menu component with animation options. Handler to toggle the Menu open or close.
- Parameter duration: The time for each view's animation. - Parameter button: A UIButton.
- Parameter delay: A delay time for each view's animation.
- Parameter usingSpringWithDamping: A damping ratio for the animation.
- Parameter initialSpringVelocity: The initial velocity for the animation.
- Parameter options: Options to pass to the animation.
- Parameter animations: An animation block to execute on each view's animation.
- Parameter completion: A completion block to execute on each view's animation.
*/
open func open(duration: TimeInterval = 0.15, delay: TimeInterval = 0, usingSpringWithDamping: CGFloat = 0.5, initialSpringVelocity: CGFloat = 0, options: UIViewAnimationOptions = [], animations: ((UIView) -> Void)? = nil, completion: ((UIView) -> Void)? = nil) {
spring.expand(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: completion)
}
/**
Close the Menu component with animation options.
- Parameter duration: The time for each view's animation.
- Parameter delay: A delay time for each view's animation.
- Parameter usingSpringWithDamping: A damping ratio for the animation.
- Parameter initialSpringVelocity: The initial velocity for the animation.
- Parameter options: Options to pass to the animation.
- Parameter animations: An animation block to execute on each view's animation.
- Parameter completion: A completion block to execute on each view's animation.
*/ */
open func close(duration: TimeInterval = 0.15, delay: TimeInterval = 0, usingSpringWithDamping: CGFloat = 0.5, initialSpringVelocity: CGFloat = 0, options: UIViewAnimationOptions = [], animations: ((UIView) -> Void)? = nil, completion: ((UIView) -> Void)? = nil) { @objc
spring.contract(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: completion) fileprivate func handleToggleMenu(button: UIButton) {
guard isOpened else {
open()
return
}
close()
} }
} }
...@@ -30,6 +30,11 @@ ...@@ -30,6 +30,11 @@
import UIKit import UIKit
public enum MenuBacking {
case fade
case blur
}
extension UIViewController { extension UIViewController {
/** /**
A convenience property that provides access to the MenuController. A convenience property that provides access to the MenuController.
...@@ -53,6 +58,15 @@ open class MenuController: RootController { ...@@ -53,6 +58,15 @@ open class MenuController: RootController {
@IBInspectable @IBInspectable
open let menu = Menu() open let menu = Menu()
/// A MenuBacking value type.
open var menuBacking = MenuBacking.blur
/// The menuBacking UIBlurEffectStyle.
open var menuBackingBlurEffectStyle = UIBlurEffectStyle.light
/// A reference to the blurView.
open fileprivate(set) var blurView: UIView?
open override func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
rootViewController.view.frame = view.bounds rootViewController.view.frame = view.bounds
...@@ -72,61 +86,112 @@ open class MenuController: RootController { ...@@ -72,61 +86,112 @@ open class MenuController: RootController {
} }
extension MenuController { extension MenuController {
/// Prepares the Menu. /// Prepares the menu.
fileprivate func prepareMenu() { fileprivate func prepareMenu() {
menu.delegate = self
menu.zPosition = 1000 menu.zPosition = 1000
view.addSubview(menu) view.addSubview(menu)
} }
} }
extension MenuController { extension MenuController {
/** /// Shows the menuBacking.
Opens the menu with a callback. fileprivate func showFabMenuBacking() {
- Parameter completion: An Optional callback that is executed when showFade()
all menu items have been opened. showBlurView()
*/ }
open func openMenu(completion: ((UIView) -> Void)? = nil) {
if true == isUserInteractionEnabled { /// Hides the menuBacking.
isUserInteractionEnabled = false fileprivate func hideFabMenuBacking() {
hideFade()
UIView.animate(withDuration: 0.15, animations: { [weak self] in hideBlurView()
guard let s = self else { }
return
} /// Shows the blurView.
s.rootViewController.view.alpha = 0.15 fileprivate func showBlurView() {
}) guard .blur == menuBacking else {
return
menu.open(usingSpringWithDamping: 0) { [completion = completion] (view) in }
completion?(view)
} guard !menu.isOpened, menu.isEnabled else {
return
}
guard nil == blurView else {
return
} }
let blur = UIVisualEffectView(effect: UIBlurEffect(style: menuBackingBlurEffectStyle))
blurView = UIView()
blurView?.layout(blur).edges()
view.layout(blurView!).edges()
view.bringSubview(toFront: menu)
} }
/** /// Hides the blurView.
Opens the menu with a callback. fileprivate func hideBlurView() {
- Parameter completion: An Optional callback that is executed when guard menu.isOpened, menu.isEnabled else {
all menu items have been closed. return
*/ }
open func closeMenu(completion: ((UIView) -> Void)? = nil) {
if false == isUserInteractionEnabled { blurView?.removeFromSuperview()
UIView.animate(withDuration: 0.15, animations: { [weak self] in blurView = nil
guard let s = self else { }
return
} /// Shows the fade.
s.rootViewController.view.alpha = 1 fileprivate func showFade() {
}) guard .fade == menuBacking else {
return
menu.close(usingSpringWithDamping: 0) { [weak self] (view) in }
guard let s = self else {
return guard !menu.isOpened, menu.isEnabled else {
} return
}
completion?(view)
UIView.animate(withDuration: 0.15, animations: { [weak self] in
if view == s.menu.views.last { self?.rootViewController.view.alpha = 0.15
s.isUserInteractionEnabled = true })
} }
}
/// Hides the fade.
fileprivate func hideFade() {
guard menu.isOpened, menu.isEnabled else {
return
}
UIView.animate(withDuration: 0.15, animations: { [weak self] in
self?.rootViewController.view.alpha = 1
})
}
}
extension MenuController: MenuDelegate {
@objc
open func menuWillOpen(menu: Menu) {
isUserInteractionEnabled = false
showFabMenuBacking()
}
@objc
open func menuDidOpen(menu: Menu) {
isUserInteractionEnabled = true
}
@objc
open func menuWillClose(menu: Menu) {
isUserInteractionEnabled = false
hideFabMenuBacking()
}
@objc
open func menuDidClose(menu: Menu) {
isUserInteractionEnabled = true
}
@objc
open func menu(menu: Menu, tappedAt point: CGPoint, isOutside: Bool) {
guard isOutside else {
return
} }
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment