Commit 63d8d3af by Daniel Dahan

development: working FABMenu with MotionSpring

parent abd72e41
......@@ -190,9 +190,9 @@ open class Button: UIButton, MotionPulseable {
open func pulse(point: CGPoint? = nil) {
let p = point ?? center
pulse.expandAnimation(point: p)
pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in
self?.pulse.contractAnimation()
self?.pulse.contract()
}
}
......@@ -204,7 +204,7 @@ open class Button: UIButton, MotionPulseable {
*/
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
pulse.expandAnimation(point: layer.convert(touches.first!.location(in: self), from: layer))
pulse.expand(point: layer.convert(touches.first!.location(in: self), from: layer))
}
/**
......@@ -215,7 +215,7 @@ open class Button: UIButton, MotionPulseable {
*/
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......@@ -226,7 +226,7 @@ open class Button: UIButton, MotionPulseable {
*/
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
open func bringImageViewToFront() {
......
......@@ -239,9 +239,9 @@ open class CollectionReusableView: UICollectionReusableView, MotionPulseable {
open func pulse(point: CGPoint? = nil) {
let p = point ?? center
pulse.expandAnimation(point: p)
pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in
self?.pulse.contractAnimation()
self?.pulse.contract()
}
}
......@@ -253,7 +253,7 @@ open class CollectionReusableView: UICollectionReusableView, MotionPulseable {
*/
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
pulse.expandAnimation(point: layer.convert(touches.first!.location(in: self), from: layer))
pulse.expand(point: layer.convert(touches.first!.location(in: self), from: layer))
}
/**
......@@ -264,7 +264,7 @@ open class CollectionReusableView: UICollectionReusableView, MotionPulseable {
*/
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......@@ -275,7 +275,7 @@ open class CollectionReusableView: UICollectionReusableView, MotionPulseable {
*/
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......
......@@ -200,9 +200,9 @@ open class CollectionViewCell: UICollectionViewCell, MotionPulseable {
open func pulse(point: CGPoint? = nil) {
let p = point ?? center
pulse.expandAnimation(point: p)
pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in
self?.pulse.contractAnimation()
self?.pulse.contract()
}
}
......@@ -214,7 +214,7 @@ open class CollectionViewCell: UICollectionViewCell, MotionPulseable {
*/
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
pulse.expandAnimation(point: layer.convert(touches.first!.location(in: self), from: layer))
pulse.expand(point: layer.convert(touches.first!.location(in: self), from: layer))
}
/**
......@@ -225,7 +225,7 @@ open class CollectionViewCell: UICollectionViewCell, MotionPulseable {
*/
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......@@ -236,7 +236,7 @@ open class CollectionViewCell: UICollectionViewCell, MotionPulseable {
*/
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......
......@@ -53,26 +53,99 @@ public protocol FABMenuDelegate {
@objc(FABMenu)
open class FABMenu: Menu {
/// An optional delegation handler.
open weak var delegate: FABMenuDelegate?
open class FABMenu: View, MotionSpringable {
/// A reference to the MotionSpring object.
internal let spring = MotionSpring()
/// The direction in which the animation opens the menu.
open var direction = SpringDirection.up {
open var springDirection = MotionSpringDirection.up {
didSet {
layoutSubviews()
}
}
/// A reference to the MenuItems
open var buttons: [MenuItem] {
open var baseSize: CGSize {
get {
return spring.baseSize
}
set(value) {
spring.baseSize = value
}
}
open var itemSize: CGSize {
get {
return spring.itemSize
}
set(value) {
spring.itemSize = value
}
}
open var isOpened: Bool {
get {
return views as! [MenuItem]
return spring.isOpened
}
set(value) {
views = value
spring.isOpened = value
}
}
open var isEnable: Bool {
get {
return spring.isEnabled
}
set(value) {
spring.isEnabled = 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
}
}
/// An optional delegation handler.
open weak var delegate: FABMenuDelegate?
/// A reference to the FABMenuItems
open var items: [FABMenuItem] {
get {
return spring.views as! [FABMenuItem]
}
set(value) {
for v in spring.views {
v.removeFromSuperview()
}
for v in value {
addSubview(v)
}
spring.views = value
}
}
open override func prepare() {
super.prepare()
backgroundColor = nil
interimSpacePreset = .interimSpace6
}
}
extension FABMenu {
......@@ -83,7 +156,7 @@ extension FABMenu {
- Returns: An optional UIView.
*/
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard isOpened, isEnabled else {
guard spring.isOpened, spring.isEnabled else {
return super.hitTest(point, with: event)
}
......@@ -100,3 +173,33 @@ extension FABMenu {
return self.hitTest(point, with: event)
}
}
extension FABMenu {
/**
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.
*/
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) {
spring.contract(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: completion)
}
}
......@@ -89,12 +89,14 @@ extension FABMenuController {
open func openMenu(completion: ((UIView) -> Void)? = nil) {
if true == isUserInteractionEnabled {
isUserInteractionEnabled = false
UIView.animate(withDuration: 0.15, animations: { [weak self] in
guard let s = self else {
return
}
s.rootViewController.view.alpha = 0.15
})
menu.open { [completion = completion] (view) in
completion?(view)
}
......@@ -114,6 +116,7 @@ extension FABMenuController {
}
s.rootViewController.view.alpha = 1
})
menu.close { [weak self] (view) in
guard let s = self else {
return
......@@ -121,7 +124,7 @@ extension FABMenuController {
completion?(view)
if view == s.menu.views.last {
if view == s.menu.items.last {
s.isUserInteractionEnabled = true
}
}
......
......@@ -30,10 +30,44 @@
import UIKit
@objc(menu)
@objc(MenuDirection)
public enum MenuDirection: Int {
case up
case down
case left
case right
}
@objc(MenuDelegate)
public protocol MenuDelegate {
/**
Gets called when the user taps while the menu is opened.
- Parameter menu: A Menu.
- Parameter tappedAt point: A CGPoint.
- Parameter isOutside: A boolean indicating whether the tap
was outside the menu button area.
*/
@objc
optional func menu(menu: Menu, tappedAt point: CGPoint, isOutside: Bool)
}
@objc(Menu)
open class Menu: View, MotionSpringable {
internal let spring = Spring()
/// A reference to the MotionSpring object.
internal let spring = MotionSpring()
/// An optional delegation handler.
open weak var delegate: MenuDelegate?
/// The direction in which the animation opens the menu.
open var springDirection = MotionSpringDirection.up {
didSet {
layoutSubviews()
}
}
/// A reference to the MenuItems
open var views: [UIView] {
get {
return spring.views
......@@ -42,6 +76,60 @@ open class Menu: View, MotionSpringable {
spring.views = value
}
}
}
extension Menu {
/**
Handles the hit test for the Menu and views outside of the Menu bounds.
- Parameter _ point: A CGPoint.
- Parameter with event: An optional UIEvent.
- Returns: An optional UIView.
*/
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard spring.isOpened, spring.isEnabled else {
return super.hitTest(point, with: event)
}
for v in subviews {
let p = v.convert(point, from: self)
if v.bounds.contains(p) {
delegate?.menu?(menu: self, tappedAt: point, isOutside: false)
return v.hitTest(p, with: event)
}
}
delegate?.menu?(menu: self, tappedAt: point, isOutside: true)
return self.hitTest(point, with: event)
}
}
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.
*/
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)
}
open var springDirection = SpringDirection.up
/**
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) {
spring.contract(duration: duration, delay: delay, usingSpringWithDamping: usingSpringWithDamping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: completion)
}
}
......@@ -51,7 +51,7 @@ extension UIViewController {
open class MenuController: RootController {
/// Reference to the MenuView.
@IBInspectable
open let menu = FABMenu()
open let menu = Menu()
open override func layoutSubviews() {
super.layoutSubviews()
......@@ -88,12 +88,14 @@ extension MenuController {
open func openMenu(completion: ((UIView) -> Void)? = nil) {
if true == isUserInteractionEnabled {
isUserInteractionEnabled = false
UIView.animate(withDuration: 0.15, animations: { [weak self] in
guard let s = self else {
return
}
s.rootViewController.view.alpha = 0.15
})
menu.open(usingSpringWithDamping: 0) { [completion = completion] (view) in
completion?(view)
}
......@@ -113,6 +115,7 @@ extension MenuController {
}
s.rootViewController.view.alpha = 1
})
menu.close(usingSpringWithDamping: 0) { [weak self] (view) in
guard let s = self else {
return
......
......@@ -30,7 +30,7 @@
import UIKit
open class MenuItem: View {
open class FABMenuItem: View {
/// A reference to the titleLabel.
open let titleLabel = UILabel()
......
......@@ -64,7 +64,7 @@ public struct MotionPulse {
fileprivate var layers = [CAShapeLayer]()
/// A reference to the MotionPulseAnimation.
public var animation = MotionMotionPulseAnimation.pointWithBacking
public var animation = MotionPulseAnimation.pointWithBacking
/// A UIColor.
public var color = Color.grey.base
......@@ -88,7 +88,7 @@ extension MotionPulse {
Triggers the expanding animation.
- Parameter point: A point to pulse from.
*/
public mutating func expandAnimation(point: CGPoint) {
public mutating func expand(point: CGPoint) {
guard let view = pulseView else {
return
}
......@@ -163,7 +163,7 @@ extension MotionPulse {
extension MotionPulse {
/// Triggers the contracting animation.
public mutating func contractAnimation() {
public mutating func contract() {
guard let bLayer = layers.popLast() else {
return
}
......
......@@ -74,9 +74,9 @@ open class PulseView: View, MotionPulseable {
open func pulse(point: CGPoint? = nil) {
let p = point ?? center
pulse.expandAnimation(point: p)
pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in
self?.pulse.contractAnimation()
self?.pulse.contract()
}
}
......@@ -88,7 +88,7 @@ open class PulseView: View, MotionPulseable {
*/
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
pulse.expandAnimation(point: layer.convert(touches.first!.location(in: self), from: layer))
pulse.expand(point: layer.convert(touches.first!.location(in: self), from: layer))
}
/**
......@@ -99,7 +99,7 @@ open class PulseView: View, MotionPulseable {
*/
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......@@ -110,7 +110,7 @@ open class PulseView: View, MotionPulseable {
*/
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......
......@@ -116,9 +116,9 @@ open class TableViewCell: UITableViewCell, MotionPulseable {
open func pulse(point: CGPoint? = nil) {
let p = point ?? center
pulse.expandAnimation(point: p)
pulse.expand(point: p)
Motion.delay(time: 0.35) { [weak self] in
self?.pulse.contractAnimation()
self?.pulse.contract()
}
}
......@@ -130,7 +130,7 @@ open class TableViewCell: UITableViewCell, MotionPulseable {
*/
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
pulse.expandAnimation(point: layer.convert(touches.first!.location(in: self), from: layer))
pulse.expand(point: layer.convert(touches.first!.location(in: self), from: layer))
}
/**
......@@ -141,7 +141,7 @@ open class TableViewCell: UITableViewCell, MotionPulseable {
*/
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......@@ -152,7 +152,7 @@ open class TableViewCell: UITableViewCell, MotionPulseable {
*/
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
pulse.contractAnimation()
pulse.contract()
}
/**
......
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