From c873366e7f8403428268e678b93c1979fed4fcd7 Mon Sep 17 00:00:00 2001 From: Boyko Mihail Date: Tue, 22 Jun 2021 13:39:27 +0300 Subject: [PATCH] fix: pr issue. Add animators --- .../DefaultAnimators/ParalaxAnimator.swift | 37 ++++++++ .../ParalaxWithScaleAnimator.swift | 23 +++++ .../ParalaxWithTransitionAnimator .swift | 23 +++++ .../DefaultAnimators/ScaleAnimator.swift | 14 +++ .../DefaultAnimators/TransitionAnimator.swift | 13 +++ .../UIViewController+FixedTopOffet.swift | 23 +++++ .../Helpers/HeaderTransitionDelegate.swift | 87 +++++-------------- .../Helpers/ParallaxTableHeaderView.swift | 1 - .../Protocols/CollapsibleViewsAnimator.swift | 8 ++ .../Protocols/CollapsibleViewsContainer.swift | 26 +----- .../Protocols/TransitioningHandler.swift | 8 ++ 11 files changed, 174 insertions(+), 89 deletions(-) create mode 100644 TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxAnimator.swift create mode 100644 TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxWithScaleAnimator.swift create mode 100644 TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxWithTransitionAnimator .swift create mode 100644 TIUIElements/Sources/Helpers/DefaultAnimators/ScaleAnimator.swift create mode 100644 TIUIElements/Sources/Helpers/DefaultAnimators/TransitionAnimator.swift create mode 100644 TIUIElements/Sources/Helpers/Extensions/UIViewController+FixedTopOffet.swift create mode 100644 TIUIElements/Sources/Helpers/Protocols/CollapsibleViewsAnimator.swift create mode 100644 TIUIElements/Sources/Helpers/Protocols/TransitioningHandler.swift diff --git a/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxAnimator.swift b/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxAnimator.swift new file mode 100644 index 00000000..fb8a03a4 --- /dev/null +++ b/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxAnimator.swift @@ -0,0 +1,37 @@ +import UIKit + +class ParalaxAnimator: CollapsibleViewsAnimator { + var fractionComplete: CGFloat = 0 + var isWithAlphaAnimate = true + + init(isWithAlphaAnimate: Bool = true) { + self.isWithAlphaAnimate = isWithAlphaAnimate + } + + func setupView(container: CollapsibleViewsContainer) { + guard let largeHeaderView = container.bottomHeaderView else { + return + } + + container.navBar?.topItem?.titleView?.alpha = 0 + + let tableHeaderView = ParallaxTableHeaderView(subView: largeHeaderView) + + container.tableView.tableHeaderView = tableHeaderView + } + + func animate(container: CollapsibleViewsContainer) { + paralax(container: container) + if isWithAlphaAnimate { + container.navBar?.topItem?.titleView?.alpha = fractionComplete == 1 ? 1 : 0 + } + } + + private func paralax(container: CollapsibleViewsContainer) { + guard let header = container.tableView.tableHeaderView as? ParallaxTableHeaderView else { + return + } + + header.layoutForContentOffset(container.tableView.contentOffset) + } +} diff --git a/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxWithScaleAnimator.swift b/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxWithScaleAnimator.swift new file mode 100644 index 00000000..0f54ce5e --- /dev/null +++ b/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxWithScaleAnimator.swift @@ -0,0 +1,23 @@ +import UIKit + +class ParalaxWithScaleAnimator: CollapsibleViewsAnimator { + private let paralaxAnimator = ParalaxAnimator(isWithAlphaAnimate: false) + private let scaleAnimator = ScaleAnimator() + + var fractionComplete: CGFloat = 0 { + didSet { + paralaxAnimator.fractionComplete = fractionComplete + scaleAnimator.fractionComplete = fractionComplete + } + } + + func setupView(container: CollapsibleViewsContainer) { + paralaxAnimator.setupView(container: container) + scaleAnimator.setupView(container: container) + } + + func animate(container: CollapsibleViewsContainer) { + paralaxAnimator.animate(container: container) + scaleAnimator.animate(container: container) + } +} diff --git a/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxWithTransitionAnimator .swift b/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxWithTransitionAnimator .swift new file mode 100644 index 00000000..487f185a --- /dev/null +++ b/TIUIElements/Sources/Helpers/DefaultAnimators/ParalaxWithTransitionAnimator .swift @@ -0,0 +1,23 @@ +import UIKit + +class ParalaxWithTransitionAnimator: CollapsibleViewsAnimator { + private let paralaxAnimator = ParalaxAnimator(isWithAlphaAnimate: false) + private let transitionAnimator = TransitionAnimator() + + var fractionComplete: CGFloat = 0 { + didSet { + paralaxAnimator.fractionComplete = fractionComplete + transitionAnimator.fractionComplete = fractionComplete + } + } + + func setupView(container: CollapsibleViewsContainer) { + paralaxAnimator.setupView(container: container) + transitionAnimator.setupView(container: container) + } + + func animate(container: CollapsibleViewsContainer) { + paralaxAnimator.animate(container: container) + transitionAnimator.animate(container: container) + } +} diff --git a/TIUIElements/Sources/Helpers/DefaultAnimators/ScaleAnimator.swift b/TIUIElements/Sources/Helpers/DefaultAnimators/ScaleAnimator.swift new file mode 100644 index 00000000..ae792d2f --- /dev/null +++ b/TIUIElements/Sources/Helpers/DefaultAnimators/ScaleAnimator.swift @@ -0,0 +1,14 @@ +import UIKit + +class ScaleAnimator: CollapsibleViewsAnimator { + var fractionComplete: CGFloat = 0 + + func setupView(container: CollapsibleViewsContainer) { + container.navBar?.topItem?.titleView?.alpha = 0 + container.navBar?.topItem?.titleView?.transform = CGAffineTransform(scaleX: -0.5, y: 0.5) + } + + func animate(container: CollapsibleViewsContainer) { + container.navBar?.topItem?.titleView?.scale(alpha: fractionComplete) + } +} diff --git a/TIUIElements/Sources/Helpers/DefaultAnimators/TransitionAnimator.swift b/TIUIElements/Sources/Helpers/DefaultAnimators/TransitionAnimator.swift new file mode 100644 index 00000000..c5ff1a06 --- /dev/null +++ b/TIUIElements/Sources/Helpers/DefaultAnimators/TransitionAnimator.swift @@ -0,0 +1,13 @@ +import UIKit + +class TransitionAnimator: CollapsibleViewsAnimator { + var fractionComplete: CGFloat = 0 + + func setupView(container: CollapsibleViewsContainer) { + container.navBar?.topItem?.titleView?.alpha = 0 + } + + func animate(container: CollapsibleViewsContainer) { + container.navBar?.topItem?.titleView?.transition(to: fractionComplete) + } +} diff --git a/TIUIElements/Sources/Helpers/Extensions/UIViewController+FixedTopOffet.swift b/TIUIElements/Sources/Helpers/Extensions/UIViewController+FixedTopOffet.swift new file mode 100644 index 00000000..9cbf63dc --- /dev/null +++ b/TIUIElements/Sources/Helpers/Extensions/UIViewController+FixedTopOffet.swift @@ -0,0 +1,23 @@ +import UIKit + +public extension UIViewController { + + var fixedTopOffet: CGFloat { // status bar + nav bar height calculate for UIViewController + let navigationBar = navigationController?.navigationBar + let window = view.window + let prefersLargeTitles = navigationBar?.prefersLargeTitles ?? false + + let statusBarHeight: CGFloat + if #available(iOS 13.0, *) { + statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 + } else { + statusBarHeight = UIApplication.shared.statusBarFrame.height + } + + let navigationBarHeight = navigationBar?.bounds.height ?? 0 + + return prefersLargeTitles + ? navigationBarHeight - statusBarHeight + : 0 + } +} diff --git a/TIUIElements/Sources/Helpers/HeaderTransitionDelegate.swift b/TIUIElements/Sources/Helpers/HeaderTransitionDelegate.swift index 3e328e5c..7f5cbdfb 100644 --- a/TIUIElements/Sources/Helpers/HeaderTransitionDelegate.swift +++ b/TIUIElements/Sources/Helpers/HeaderTransitionDelegate.swift @@ -1,14 +1,10 @@ import Foundation import UIKit -open class HeaderTransitionDelegate: NSObject, UIScrollViewDelegate { - - public enum HeaderAnimationType { - case onlyParalax, paralaxWithTransition, transition, scale, paralaxWithScale, none - } +open class HeaderTransitionDelegate: NSObject, TransitioningHandler { + public var animator: CollapsibleViewsAnimator? private weak var headerViewHandler: CollapsibleViewsContainer? - private let headerAnimationType: HeaderAnimationType private var startOffset: CGFloat = 0 private var navigationBarOffset: CGFloat = 0 @@ -32,10 +28,10 @@ open class HeaderTransitionDelegate: NSObject, UIScrollViewDelegate { } } - public init(headerViewHandler: CollapsibleViewsContainer, - headerAnimationType: HeaderAnimationType = .none) { - self.headerViewHandler = headerViewHandler - self.headerAnimationType = headerAnimationType + required public init(container: CollapsibleViewsContainer, + animator: CollapsibleViewsAnimator?) { + self.headerViewHandler = container + self.animator = animator super.init() initialUpdateHeaderView() @@ -62,29 +58,32 @@ open class HeaderTransitionDelegate: NSObject, UIScrollViewDelegate { var alpha = offsetY / (largeHeaderView.frame.height + navigationBarOffset) alpha = alpha > 1 ? 1 : alpha - animate(headerAnimation: headerAnimationType, alpha: alpha) + guard let headerViewHandler = headerViewHandler, + var animator = animator else { + titleView?.alpha = alpha == 1 ? 1 : 0 + return + } + + animator.fractionComplete = alpha + animator.animate(container: headerViewHandler) } private func setupView() { - switch headerAnimationType { - case .scale, .paralaxWithScale: - titleView?.transform = CGAffineTransform(scaleX: -0.5, y: 0.5) - - case .paralaxWithTransition, .transition: - break - - default: - titleView?.alpha = 1 - titleView?.isHidden = true + titleView?.alpha = animator == nil ? 0 : 1 + + guard let headerViewHandler = headerViewHandler, + let animator = animator else { + return } + + animator.setupView(container: headerViewHandler) } private func initialUpdateHeaderView() { titleView = headerViewHandler?.topHeaderView - titleView?.alpha = 0 setLargeHeader() - + setupView() } @@ -93,46 +92,6 @@ open class HeaderTransitionDelegate: NSObject, UIScrollViewDelegate { return } - switch headerAnimationType { - case .paralaxWithScale, .paralaxWithTransition, .onlyParalax: - tableHeaderView = ParallaxTableHeaderView(subView: largeHeaderView) - - default: - tableHeaderView = largeHeaderView - } - } - - private func animate(headerAnimation: HeaderAnimationType, alpha: CGFloat) { - switch headerAnimation { - case .paralaxWithTransition: - titleView?.transition(to: alpha) - paralax() - - case .transition: - titleView?.transition(to: alpha) - - case .onlyParalax: - paralax() - titleView?.isHidden = alpha != 1 - - case .scale: - titleView?.scale(alpha: alpha) - - case .paralaxWithScale: - titleView?.scale(alpha: alpha) - paralax() - - default: - titleView?.isHidden = alpha != 1 - } - } - - private func paralax() { - guard let tableView = headerViewHandler?.tableView, - let header = tableView.tableHeaderView as? ParallaxTableHeaderView else { - return - } - - header.layoutForContentOffset(tableView.contentOffset) + tableHeaderView = largeHeaderView } } diff --git a/TIUIElements/Sources/Helpers/ParallaxTableHeaderView.swift b/TIUIElements/Sources/Helpers/ParallaxTableHeaderView.swift index 05e5f502..9c721bea 100644 --- a/TIUIElements/Sources/Helpers/ParallaxTableHeaderView.swift +++ b/TIUIElements/Sources/Helpers/ParallaxTableHeaderView.swift @@ -7,7 +7,6 @@ open class ParallaxTableHeaderView: UIView { public init(subView: UIView) { container = UIView(frame: subView.frame) super.init(frame: CGRect(x: 0, y: 0, width: subView.frame.size.width, height: subView.frame.size.height)) - subView.autoresizingMask = [ .flexibleLeftMargin, .flexibleRightMargin, diff --git a/TIUIElements/Sources/Helpers/Protocols/CollapsibleViewsAnimator.swift b/TIUIElements/Sources/Helpers/Protocols/CollapsibleViewsAnimator.swift new file mode 100644 index 00000000..f73ad7ea --- /dev/null +++ b/TIUIElements/Sources/Helpers/Protocols/CollapsibleViewsAnimator.swift @@ -0,0 +1,8 @@ +import UIKit + +public protocol CollapsibleViewsAnimator { + var fractionComplete: CGFloat { get set } // progress of animation + + func setupView(container: CollapsibleViewsContainer) + func animate(container: CollapsibleViewsContainer) +} diff --git a/TIUIElements/Sources/Helpers/Protocols/CollapsibleViewsContainer.swift b/TIUIElements/Sources/Helpers/Protocols/CollapsibleViewsContainer.swift index 210b80af..3e252531 100644 --- a/TIUIElements/Sources/Helpers/Protocols/CollapsibleViewsContainer.swift +++ b/TIUIElements/Sources/Helpers/Protocols/CollapsibleViewsContainer.swift @@ -1,32 +1,10 @@ import UIKit public protocol CollapsibleViewsContainer: class, - TableViewHandler, - NavigationBarHandler { + TableViewHandler, + NavigationBarHandler { var topHeaderView: UIView? { get } // titleView var bottomHeaderView: UIView? { get } // tableHeaderView var fixedTopOffet: CGFloat { get } // status bar + nav bar height } - -public extension UIViewController { - - var defaultTopOffet: CGFloat { // status bar + nav bar height calculate for UIViewController - let navigationBar = navigationController?.navigationBar - let window = view.window - let prefersLargeTitles = navigationBar?.prefersLargeTitles ?? false - - let statusBarHeight: CGFloat - if #available(iOS 13.0, *) { - statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 - } else { - statusBarHeight = UIApplication.shared.statusBarFrame.height - } - - let navigationBarHeight = navigationBar?.bounds.height ?? 0 - - return prefersLargeTitles - ? navigationBarHeight - statusBarHeight - : 0 - } -} diff --git a/TIUIElements/Sources/Helpers/Protocols/TransitioningHandler.swift b/TIUIElements/Sources/Helpers/Protocols/TransitioningHandler.swift new file mode 100644 index 00000000..74751adf --- /dev/null +++ b/TIUIElements/Sources/Helpers/Protocols/TransitioningHandler.swift @@ -0,0 +1,8 @@ +import UIKit + +public protocol TransitioningHandler: UIScrollViewDelegate { + var animator: CollapsibleViewsAnimator? { get set } + + init(container: CollapsibleViewsContainer, + animator: CollapsibleViewsAnimator?) +}