Swiftgram/Display/ListViewItemHeader.swift
2017-02-11 17:02:35 +03:00

118 lines
4.1 KiB
Swift

import Foundation
import AsyncDisplayKit
public enum ListViewItemHeaderStickDirection {
case top
case bottom
}
public protocol ListViewItemHeader: class {
var id: Int64 { get }
var stickDirection: ListViewItemHeaderStickDirection { get }
var height: CGFloat { get }
func node() -> ListViewItemHeaderNode
}
open class ListViewItemHeaderNode: ASDisplayNode {
private final var spring: ListViewItemSpring?
let wantsScrollDynamics: Bool
let isRotated: Bool
final private(set) var internalStickLocationDistanceFactor: CGFloat = 0.0
final var internalStickLocationDistance: CGFloat = 0.0
private var isFlashingOnScrolling = false
func updateInternalStickLocationDistanceFactor(_ factor: CGFloat, animated: Bool) {
self.internalStickLocationDistanceFactor = factor
}
final func updateFlashingOnScrollingInternal(_ isFlashingOnScrolling: Bool, animated: Bool) {
if self.isFlashingOnScrolling != isFlashingOnScrolling {
self.isFlashingOnScrolling = isFlashingOnScrolling
self.updateFlashingOnScrolling(isFlashingOnScrolling, animated: animated)
}
/*if self.isFlashing {
if self.alpha.isZero {
self.alpha = 1.0
if animated {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
}
}
} else {
if !self.alpha.isZero {
self.alpha = 0.0
if animated {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
}
}
}*/
}
open func updateFlashingOnScrolling(_ isFlashingOnScrolling: Bool, animated: Bool) {
}
public init(dynamicBounce: Bool = false, isRotated: Bool = false) {
self.wantsScrollDynamics = dynamicBounce
self.isRotated = isRotated
if dynamicBounce {
self.spring = ListViewItemSpring(stiffness: -280.0, damping: -24.0, mass: 0.85)
}
super.init()
}
open func updateStickDistanceFactor(_ factor: CGFloat, transition: ContainedViewLayoutTransition) {
}
final func addScrollingOffset(_ scrollingOffset: CGFloat) {
if self.spring != nil && internalStickLocationDistanceFactor.isZero {
let bounds = self.bounds
self.bounds = CGRect(origin: CGPoint(x: 0.0, y: bounds.origin.y + scrollingOffset), size: bounds.size)
}
}
public func animate(_ timestamp: Double) -> Bool {
var continueAnimations = false
if let _ = self.spring {
let bounds = self.bounds
var offset = bounds.origin.y
let currentOffset = offset
let frictionConstant: CGFloat = testSpringFriction
let springConstant: CGFloat = testSpringConstant
let time: CGFloat = 1.0 / 60.0
// friction force = velocity * friction constant
let frictionForce = self.spring!.velocity * frictionConstant
// spring force = (target point - current position) * spring constant
let springForce = -currentOffset * springConstant
// force = spring force - friction force
let force = springForce - frictionForce
// velocity = current velocity + force * time / mass
self.spring!.velocity = self.spring!.velocity + force * time
// position = current position + velocity * time
offset = currentOffset + self.spring!.velocity * time
offset = offset.isNaN ? 0.0 : offset
let epsilon: CGFloat = 0.1
if abs(offset) < epsilon && abs(self.spring!.velocity) < epsilon {
offset = 0.0
self.spring!.velocity = 0.0
} else {
continueAnimations = true
}
if abs(offset) > 250.0 {
offset = offset < 0.0 ? -250.0 : 250.0
}
self.bounds = CGRect(origin: CGPoint(x: 0.0, y: offset), size: bounds.size)
}
return continueAnimations
}
}