fix: pr issue. Add animators
This commit is contained in:
parent
1b58ff5aaa
commit
c873366e7f
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
import UIKit
|
||||
|
||||
public protocol TransitioningHandler: UIScrollViewDelegate {
|
||||
var animator: CollapsibleViewsAnimator? { get set }
|
||||
|
||||
init(container: CollapsibleViewsContainer,
|
||||
animator: CollapsibleViewsAnimator?)
|
||||
}
|
||||
Loading…
Reference in New Issue