fix: pr issue. Add animators

This commit is contained in:
Boyko Mihail 2021-06-22 13:39:27 +03:00
parent 1b58ff5aaa
commit c873366e7f
11 changed files with 174 additions and 89 deletions

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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,

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -0,0 +1,8 @@
import UIKit
public protocol TransitioningHandler: UIScrollViewDelegate {
var animator: CollapsibleViewsAnimator? { get set }
init(container: CollapsibleViewsContainer,
animator: CollapsibleViewsAnimator?)
}