diff --git a/Hover.podspec b/Hover.podspec index 702aa0d..f571a68 100644 --- a/Hover.podspec +++ b/Hover.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'Hover' - spec.version = '1.4.0' + spec.version = '1.5.0' spec.license = { :type => 'MIT', :file => 'LICENSE' } spec.homepage = 'https://github.com/pedrommcarrasco/Hover' spec.authors = { 'Pedro Carrasco' => 'https://twitter.com/pedrommcarrasco' } diff --git a/Hover/Model/HoverConfiguration.swift b/Hover/Model/HoverConfiguration.swift index 70e06a7..21c7975 100644 --- a/Hover/Model/HoverConfiguration.swift +++ b/Hover/Model/HoverConfiguration.swift @@ -22,6 +22,8 @@ public struct HoverConfiguration { public var color: HoverColor /// Image displayed in the floating button public var image: UIImage? + /// Define the animation of the HoverButton's image when expding items + public var imageExpandAnimation: ImageExpandAnimation /// Size of the floating button public var size: CGFloat /// Dictates the size of the image shown in any button (imageSize = size * imageSizeRatio) @@ -47,6 +49,7 @@ public struct HoverConfiguration { // MARK: Init public init(image: UIImage? = nil, + imageExpandAnimation: ImageExpandAnimation = .none, color: HoverColor = .color(.blue), size: CGFloat = 60.0, imageSizeRatio: CGFloat = 0.4, @@ -58,6 +61,7 @@ public struct HoverConfiguration { self.color = color self.image = image + self.imageExpandAnimation = imageExpandAnimation self.size = size self.imageSizeRatio = imageSizeRatio self.spacing = spacing @@ -78,3 +82,11 @@ struct HoverItemConfiguration { let initialXOrientation: Orientation.X } +// MARK: - ImageExpandAnimation +public enum ImageExpandAnimation { + /// No animation + case none + + /// Rotate considering the radian value. It considers the X and Y orientation when animating. + case rotate(_ radian: CGFloat) +} diff --git a/Hover/UI/HoverButton.swift b/Hover/UI/HoverButton.swift index 3b830fd..7b94554 100644 --- a/Hover/UI/HoverButton.swift +++ b/Hover/UI/HoverButton.swift @@ -21,11 +21,11 @@ class HoverButton: UIControl { } // MARK: Outlets - private var gradientLayer: CAGradientLayer? - private let imageView: UIImageView = .create { + let imageView: UIImageView = .create { $0.contentMode = .scaleAspectFit $0.isUserInteractionEnabled = false } + private var gradientLayer: CAGradientLayer? private let hightlightView: UIView = .create { $0.backgroundColor = Constant.highlightColor $0.isUserInteractionEnabled = false diff --git a/Hover/UI/HoverView.swift b/Hover/UI/HoverView.swift index 254dcde..52494b7 100644 --- a/Hover/UI/HoverView.swift +++ b/Hover/UI/HoverView.swift @@ -21,7 +21,6 @@ public class HoverView: UIView { static let interItemSpacing: CGFloat = 12.0 static let disabledAlpha: CGFloat = 0.75 static let disabledTransform = CGAffineTransform(scaleX: 0.9, y: 0.9) - } // MARK: State @@ -248,12 +247,14 @@ private extension HoverView { } } } - + private func animate(isOpening: Bool, anchor: Anchor, completion: (() -> Void)? = nil) { itemsStackView.isUserInteractionEnabled = isOpening - - UIViewPropertyAnimator(duration: Constant.animationDuration, curve: .easeInOut) { + + let transform = imageExpandTransform(isOpening: isOpening) + UIViewPropertyAnimator(duration: Constant.animationDuration, dampingRatio: Constant.animationDamping) { self.dimView.alpha = isOpening ? 1.0 : 0.0 + self.button.imageView.transform = transform }.startAnimation() anchor.position.yOrientation.reverseArrayIfNeeded(itemsStackView.arrangedSubviews).enumerated().forEach { (index, view) in @@ -274,6 +275,30 @@ private extension HoverView { animator.startAnimation(afterDelay: Calculator.delay(for: index)) } } + + private func imageExpandTransform(isOpening: Bool) -> CGAffineTransform { + switch configuration.imageExpandAnimation { + case .none: + return .identity + + case .rotate(let radianValue): + let factor: CGFloat + + switch (currentAnchor.position.xOrientation, currentAnchor.position.yOrientation) { + case (.leftToRight, .bottomToTop), + (.rightToLeft, .topToBottom): + factor = 1 + case (.leftToRight, .topToBottom), + (.rightToLeft, .bottomToTop): + factor = -1 + } + + let rotationValue: CGFloat = radianValue * factor + let rotationTransform = CGAffineTransform(rotationAngle: rotationValue) + + return isOpening ? rotationTransform : .identity + } + } } // MARK: - Conditional Constraints