From fa87eb416132572a2431771d99bf2ebf77f16855 Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Fri, 2 Jul 2021 12:29:05 +0200 Subject: [PATCH 1/9] First proposal to animate HoverButton image when it's expanded --- Hover/UI/HoverButton.swift | 11 +++++++++++ Hover/UI/HoverView.swift | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Hover/UI/HoverButton.swift b/Hover/UI/HoverButton.swift index 3b830fd..c8457cd 100644 --- a/Hover/UI/HoverButton.swift +++ b/Hover/UI/HoverButton.swift @@ -18,6 +18,7 @@ class HoverButton: UIControl { static let animationDuration = 0.5 static let animationDamping: CGFloat = 0.4 static let highlightColor = UIColor.white.withAlphaComponent(0.2) + static let rotationTransform = CGAffineTransform(rotationAngle: .pi * -0.25) } // MARK: Outlets @@ -49,6 +50,16 @@ class HoverButton: UIControl { }.startAnimation() } } + + var isExpanded: Bool = false { + didSet { + let transform: CGAffineTransform = isExpanded ? Constant.rotationTransform : .identity + + UIViewPropertyAnimator(duration: Constant.animationDuration, dampingRatio: Constant.animationDamping) { + self.imageView.transform = transform + }.startAnimation() + } + } // MARK: Lifecycle init(with color: HoverColor, image: UIImage?, imageSizeRatio: CGFloat) { diff --git a/Hover/UI/HoverView.swift b/Hover/UI/HoverView.swift index 254dcde..9bd0cce 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 @@ -251,6 +250,7 @@ private extension HoverView { private func animate(isOpening: Bool, anchor: Anchor, completion: (() -> Void)? = nil) { itemsStackView.isUserInteractionEnabled = isOpening + button.isExpanded = isOpening UIViewPropertyAnimator(duration: Constant.animationDuration, curve: .easeInOut) { self.dimView.alpha = isOpening ? 1.0 : 0.0 From 932e4c55030a928e6303a02e8e8dfbcbc2ba66c6 Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Fri, 2 Jul 2021 13:15:02 +0200 Subject: [PATCH 2/9] Considering the X orientation for the animation --- Hover/UI/HoverButton.swift | 7 +++++-- Hover/UI/HoverView.swift | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Hover/UI/HoverButton.swift b/Hover/UI/HoverButton.swift index c8457cd..1e70ed5 100644 --- a/Hover/UI/HoverButton.swift +++ b/Hover/UI/HoverButton.swift @@ -18,7 +18,6 @@ class HoverButton: UIControl { static let animationDuration = 0.5 static let animationDamping: CGFloat = 0.4 static let highlightColor = UIColor.white.withAlphaComponent(0.2) - static let rotationTransform = CGAffineTransform(rotationAngle: .pi * -0.25) } // MARK: Outlets @@ -53,13 +52,17 @@ class HoverButton: UIControl { var isExpanded: Bool = false { didSet { - let transform: CGAffineTransform = isExpanded ? Constant.rotationTransform : .identity + let rotationValue: CGFloat = (.pi * 0.25) * (orientation == .leftToRight ? 1 : -1) + let rotationTransform = CGAffineTransform(rotationAngle: rotationValue) + let transform: CGAffineTransform = isExpanded ? rotationTransform: .identity UIViewPropertyAnimator(duration: Constant.animationDuration, dampingRatio: Constant.animationDamping) { self.imageView.transform = transform }.startAnimation() } } + + var orientation: Orientation.X = .rightToLeft // MARK: Lifecycle init(with color: HoverColor, image: UIImage?, imageSizeRatio: CGFloat) { diff --git a/Hover/UI/HoverView.swift b/Hover/UI/HoverView.swift index 9bd0cce..5a832b3 100644 --- a/Hover/UI/HoverView.swift +++ b/Hover/UI/HoverView.swift @@ -302,5 +302,6 @@ private extension HoverView { NSLayoutConstraint.activate([stackViewXConstraint, stackViewYConstraint]) itemViews.forEach { $0.orientation = currentAnchor.position.xOrientation } + button.orientation = currentAnchor.position.xOrientation } } From e453f4416eb63284cab045ffcde8ba4c04b1aaf1 Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Fri, 2 Jul 2021 13:43:45 +0200 Subject: [PATCH 3/9] Added way to animation the expading animation via HoverConfiguration. --- Hover/Model/HoverConfiguration.swift | 16 ++++++++++++- Hover/UI/HoverButton.swift | 18 ++------------- Hover/UI/HoverView.swift | 34 +++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/Hover/Model/HoverConfiguration.swift b/Hover/Model/HoverConfiguration.swift index 70e06a7..9bf5646 100644 --- a/Hover/Model/HoverConfiguration.swift +++ b/Hover/Model/HoverConfiguration.swift @@ -36,6 +36,8 @@ public struct HoverConfiguration { public var initialPosition: HoverPosition /// Allowed positions in which the floating button can be placed public var allowedPositions: Set + /// Define the animation of the HoverButton's image when expding items + public var imageExpandAnimation: ImageExpandAnimation var itemConfiguration: HoverItemConfiguration { return HoverItemConfiguration(size: size * Constant.itemSizeRatio, @@ -54,7 +56,8 @@ public struct HoverConfiguration { font: UIFont? = nil, dimColor: UIColor = UIColor.black.withAlphaComponent(0.75), initialPosition: HoverPosition = .bottomRight, - allowedPositions: Set = .all) { + allowedPositions: Set = .all, + imageExpandAnimation: ImageExpandAnimation = .none) { self.color = color self.image = image @@ -65,6 +68,7 @@ public struct HoverConfiguration { self.dimColor = dimColor self.initialPosition = initialPosition self.allowedPositions = allowedPositions + self.imageExpandAnimation = imageExpandAnimation } } @@ -78,3 +82,13 @@ 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 1e70ed5..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 @@ -49,20 +49,6 @@ class HoverButton: UIControl { }.startAnimation() } } - - var isExpanded: Bool = false { - didSet { - let rotationValue: CGFloat = (.pi * 0.25) * (orientation == .leftToRight ? 1 : -1) - let rotationTransform = CGAffineTransform(rotationAngle: rotationValue) - let transform: CGAffineTransform = isExpanded ? rotationTransform: .identity - - UIViewPropertyAnimator(duration: Constant.animationDuration, dampingRatio: Constant.animationDamping) { - self.imageView.transform = transform - }.startAnimation() - } - } - - var orientation: Orientation.X = .rightToLeft // MARK: Lifecycle init(with color: HoverColor, image: UIImage?, imageSizeRatio: CGFloat) { diff --git a/Hover/UI/HoverView.swift b/Hover/UI/HoverView.swift index 5a832b3..7760a12 100644 --- a/Hover/UI/HoverView.swift +++ b/Hover/UI/HoverView.swift @@ -247,14 +247,18 @@ private extension HoverView { } } } - + private func animate(isOpening: Bool, anchor: Anchor, completion: (() -> Void)? = nil) { itemsStackView.isUserInteractionEnabled = isOpening - button.isExpanded = isOpening UIViewPropertyAnimator(duration: Constant.animationDuration, curve: .easeInOut) { self.dimView.alpha = isOpening ? 1.0 : 0.0 }.startAnimation() + + let transform = imageExpandTransform(isOpening: isOpening) + UIViewPropertyAnimator(duration: Constant.animationDuration, dampingRatio: Constant.animationDamping) { + self.button.imageView.transform = transform + }.startAnimation() anchor.position.yOrientation.reverseArrayIfNeeded(itemsStackView.arrangedSubviews).enumerated().forEach { (index, view) in let translationTransform = Calculator.translation(for: index, anchor: anchor) @@ -274,6 +278,31 @@ 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 @@ -302,6 +331,5 @@ private extension HoverView { NSLayoutConstraint.activate([stackViewXConstraint, stackViewYConstraint]) itemViews.forEach { $0.orientation = currentAnchor.position.xOrientation } - button.orientation = currentAnchor.position.xOrientation } } From 76d2f49051068535de11613632b98e2560217ae1 Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Fri, 2 Jul 2021 19:34:23 +0200 Subject: [PATCH 4/9] Update Hover/Model/HoverConfiguration.swift Co-authored-by: Pedro Carrasco <26525777+pedrommcarrasco@users.noreply.github.com> --- Hover/Model/HoverConfiguration.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Hover/Model/HoverConfiguration.swift b/Hover/Model/HoverConfiguration.swift index 9bf5646..cacf5cc 100644 --- a/Hover/Model/HoverConfiguration.swift +++ b/Hover/Model/HoverConfiguration.swift @@ -84,11 +84,10 @@ struct HoverItemConfiguration { // MARK: - ImageExpandAnimation public enum ImageExpandAnimation { - // No animation + /// No animation case none // Rotate considering the radian value. // It considers the X and Y orientation when animating. case rotate(_ radian: CGFloat) } - From 81ebb6adf75a68b0dfdeb5e1417e6993c6d39c01 Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Fri, 2 Jul 2021 19:34:43 +0200 Subject: [PATCH 5/9] Update Hover/Model/HoverConfiguration.swift Co-authored-by: Pedro Carrasco <26525777+pedrommcarrasco@users.noreply.github.com> --- Hover/Model/HoverConfiguration.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Hover/Model/HoverConfiguration.swift b/Hover/Model/HoverConfiguration.swift index cacf5cc..3996947 100644 --- a/Hover/Model/HoverConfiguration.swift +++ b/Hover/Model/HoverConfiguration.swift @@ -87,7 +87,6 @@ public enum ImageExpandAnimation { /// No animation case none - // Rotate considering the radian value. - // It considers the X and Y orientation when animating. + /// Rotate considering the radian value. It considers the X and Y orientation when animating. case rotate(_ radian: CGFloat) } From d63cee43b3199fb1ea63a5d51c667aae66a29427 Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Fri, 2 Jul 2021 19:34:59 +0200 Subject: [PATCH 6/9] Update Hover/UI/HoverView.swift Co-authored-by: Pedro Carrasco <26525777+pedrommcarrasco@users.noreply.github.com> --- Hover/UI/HoverView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Hover/UI/HoverView.swift b/Hover/UI/HoverView.swift index 7760a12..a9be369 100644 --- a/Hover/UI/HoverView.swift +++ b/Hover/UI/HoverView.swift @@ -285,7 +285,6 @@ private extension HoverView { return .identity case .rotate(let radianValue): - let factor: CGFloat switch (currentAnchor.position.xOrientation, currentAnchor.position.yOrientation) { From e77cddebe29245ff4ce33cccfd0d22c733ec9d9f Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Fri, 2 Jul 2021 21:33:57 +0200 Subject: [PATCH 7/9] Minor changes --- Hover/Model/HoverConfiguration.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Hover/Model/HoverConfiguration.swift b/Hover/Model/HoverConfiguration.swift index 3996947..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) @@ -36,8 +38,6 @@ public struct HoverConfiguration { public var initialPosition: HoverPosition /// Allowed positions in which the floating button can be placed public var allowedPositions: Set - /// Define the animation of the HoverButton's image when expding items - public var imageExpandAnimation: ImageExpandAnimation var itemConfiguration: HoverItemConfiguration { return HoverItemConfiguration(size: size * Constant.itemSizeRatio, @@ -49,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, @@ -56,11 +57,11 @@ public struct HoverConfiguration { font: UIFont? = nil, dimColor: UIColor = UIColor.black.withAlphaComponent(0.75), initialPosition: HoverPosition = .bottomRight, - allowedPositions: Set = .all, - imageExpandAnimation: ImageExpandAnimation = .none) { + allowedPositions: Set = .all) { self.color = color self.image = image + self.imageExpandAnimation = imageExpandAnimation self.size = size self.imageSizeRatio = imageSizeRatio self.spacing = spacing @@ -68,7 +69,6 @@ public struct HoverConfiguration { self.dimColor = dimColor self.initialPosition = initialPosition self.allowedPositions = allowedPositions - self.imageExpandAnimation = imageExpandAnimation } } From e8d6c43b09963affa1c8059db88310e22f8f848a Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Fri, 2 Jul 2021 21:45:47 +0200 Subject: [PATCH 8/9] Minor change --- Hover/UI/HoverView.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Hover/UI/HoverView.swift b/Hover/UI/HoverView.swift index a9be369..52494b7 100644 --- a/Hover/UI/HoverView.swift +++ b/Hover/UI/HoverView.swift @@ -250,13 +250,10 @@ private extension HoverView { private func animate(isOpening: Bool, anchor: Anchor, completion: (() -> Void)? = nil) { itemsStackView.isUserInteractionEnabled = isOpening - - UIViewPropertyAnimator(duration: Constant.animationDuration, curve: .easeInOut) { - self.dimView.alpha = isOpening ? 1.0 : 0.0 - }.startAnimation() 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() From 41c1c1e68fe1b4978fb560770c4af9b41f473089 Mon Sep 17 00:00:00 2001 From: Bruno Guidolim Date: Thu, 8 Jul 2021 16:26:52 +0200 Subject: [PATCH 9/9] Updated podspec --- Hover.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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' }