LeadKit/TIUIElements/Sources/Helpers/HeaderTransitionDelegate.swift

155 lines
4.6 KiB
Swift

import Foundation
import UIKit
open class HeaderTransitionDelegate: NSObject, UIScrollViewDelegate {
public enum HeaderAnimationType {
case onlyParalax, paralaxWithTransition, transition, scale, paralaxWithScale, none
}
private weak var headerViewHandler: HeaderViewHandlerProtocol?
private let headerAnimationType: HeaderAnimationType
private var startOffset: CGFloat = 0
private var navigationBarOffset: CGFloat = 0
private var isFirstScroll = true
private var titleView: UIView? {
get {
headerViewHandler?.navigationBar?.topItem?.titleView
}
set {
headerViewHandler?.navigationBar?.topItem?.titleView = newValue
}
}
private var tableHeaderView: UIView? {
get {
headerViewHandler?.tableView.tableHeaderView
}
set {
headerViewHandler?.tableView.tableHeaderView = newValue
}
}
public init(headerViewHandler: HeaderViewHandlerProtocol,
headerAnimationType: HeaderAnimationType = .paralaxWithTransition) {
self.headerViewHandler = headerViewHandler
self.headerAnimationType = headerAnimationType
super.init()
initialUpdateHeaderView()
}
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollViewDidScrollHandler(scrollView)
}
open func scrollViewDidScrollHandler(_ scrollView: UIScrollView) {
guard let headerHandler = headerViewHandler,
let largeHeaderView = headerHandler.largeHeaderView else {
titleView?.isHidden = false
return
}
if isFirstScroll {
startOffset = headerViewHandler?.startOffset ?? 0
navigationBarOffset = headerViewHandler?.navigationBarOffset ?? 0
isFirstScroll = false
}
let offsetY = scrollView.contentOffset.y + startOffset
var alpha = offsetY / (largeHeaderView.frame.height + navigationBarOffset)
alpha = alpha > 1 ? 1 : alpha
animate(headerAnimation: headerAnimationType, alpha: alpha)
}
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
}
}
private func initialUpdateHeaderView() {
titleView = headerViewHandler?.headerView
titleView?.alpha = 0
setLargeHeader()
setupView()
}
private func setLargeHeader() {
guard let largeHeaderView = headerViewHandler?.largeHeaderView else {
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:
transition(alpha: alpha)
paralax()
case .transition:
transition(alpha: alpha)
case .onlyParalax:
paralax()
titleView?.isHidden = alpha != 1
case .scale:
scale(alpha: alpha)
case .paralaxWithScale:
scale(alpha: alpha)
paralax()
default:
titleView?.isHidden = alpha != 1
}
}
private func paralax() {
guard let tableView = headerViewHandler?.tableView,
let header: ParallaxTableHeaderView = tableView.tableHeaderView as? ParallaxTableHeaderView else {
return
}
header.layoutForContentOffset(tableView.contentOffset)
}
private func transition(alpha: CGFloat) {
UIView.animate(withDuration: 0.2) { [weak self] in
self?.titleView?.alpha = alpha
self?.titleView?.transform = CGAffineTransform(translationX: 0, y: -alpha*10)
}
}
private func scale(alpha: CGFloat) {
UIView.animate(withDuration: 0.2){ [weak self] in
self?.titleView?.alpha = alpha
self?.titleView?.transform = CGAffineTransform(scaleX: alpha, y: alpha)
}
}
}