mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-04 20:00:53 +00:00
no message
This commit is contained in:
parent
c3d1e3cfd3
commit
572a74e278
@ -17,6 +17,7 @@ import UIKit
|
||||
}
|
||||
|
||||
private let completionKey = "CAAnimationUtils_completion"
|
||||
private let springKey = "CAAnimationUtilsSpringCurve"
|
||||
|
||||
public extension CAAnimation {
|
||||
public var completion: (Bool -> Void)? {
|
||||
@ -38,27 +39,50 @@ public extension CAAnimation {
|
||||
|
||||
public extension CALayer {
|
||||
public func animate(from from: NSValue, to: NSValue, keyPath: String, timingFunction: String, duration: NSTimeInterval, removeOnCompletion: Bool = true, completion: (Bool -> Void)? = nil) {
|
||||
let k = Float(UIView.animationDurationFactor())
|
||||
var speed: Float = 1.0
|
||||
if k != 0 && k != 1 {
|
||||
speed = Float(1.0) / k
|
||||
if timingFunction == springKey {
|
||||
let animation = CASpringAnimation(keyPath: keyPath)
|
||||
animation.fromValue = from
|
||||
animation.toValue = to
|
||||
animation.damping = 500.0
|
||||
animation.stiffness = 1000.0
|
||||
animation.mass = 3.0
|
||||
animation.duration = animation.settlingDuration
|
||||
animation.removedOnCompletion = removeOnCompletion
|
||||
animation.fillMode = kCAFillModeForwards
|
||||
if let completion = completion {
|
||||
animation.delegate = CALayerAnimationDelegate(completion: completion)
|
||||
}
|
||||
|
||||
let k = Float(UIView.animationDurationFactor())
|
||||
var speed: Float = 1.0
|
||||
if k != 0 && k != 1 {
|
||||
speed = Float(1.0) / k
|
||||
}
|
||||
|
||||
animation.speed = speed * Float(animation.duration / duration)
|
||||
|
||||
self.addAnimation(animation, forKey: keyPath)
|
||||
} else {
|
||||
let k = Float(UIView.animationDurationFactor())
|
||||
var speed: Float = 1.0
|
||||
if k != 0 && k != 1 {
|
||||
speed = Float(1.0) / k
|
||||
}
|
||||
|
||||
let animation = CABasicAnimation(keyPath: keyPath)
|
||||
animation.fromValue = from
|
||||
animation.toValue = to
|
||||
animation.duration = duration
|
||||
animation.timingFunction = CAMediaTimingFunction(name: timingFunction)
|
||||
animation.removedOnCompletion = removeOnCompletion
|
||||
animation.fillMode = kCAFillModeForwards
|
||||
animation.speed = speed
|
||||
if let completion = completion {
|
||||
animation.delegate = CALayerAnimationDelegate(completion: completion)
|
||||
}
|
||||
|
||||
self.addAnimation(animation, forKey: keyPath)
|
||||
}
|
||||
|
||||
let animation = CABasicAnimation(keyPath: keyPath)
|
||||
animation.fromValue = from
|
||||
animation.toValue = to
|
||||
animation.duration = duration
|
||||
animation.timingFunction = CAMediaTimingFunction(name: timingFunction)
|
||||
animation.removedOnCompletion = removeOnCompletion
|
||||
animation.fillMode = kCAFillModeForwards
|
||||
animation.speed = speed
|
||||
if let completion = completion {
|
||||
animation.delegate = CALayerAnimationDelegate(completion: completion)
|
||||
}
|
||||
|
||||
self.addAnimation(animation, forKey: keyPath)
|
||||
|
||||
//self.setValue(to, forKey: keyPath)
|
||||
}
|
||||
|
||||
public func animateAdditive(from from: NSValue, to: NSValue, keyPath: String, key: String, timingFunction: String, duration: NSTimeInterval, removeOnCompletion: Bool = true, completion: (Bool -> Void)? = nil) {
|
||||
@ -93,10 +117,28 @@ public extension CALayer {
|
||||
}
|
||||
|
||||
internal func animatePosition(from from: CGPoint, to: CGPoint, duration: NSTimeInterval, completion: (Bool -> Void)? = nil) {
|
||||
self.animate(from: NSValue(CGPoint: from), to: NSValue(CGPoint: to), keyPath: "position", timingFunction: kCAMediaTimingFunctionEaseInEaseOut, duration: duration, removeOnCompletion: true, completion: completion)
|
||||
if from == to {
|
||||
return
|
||||
}
|
||||
self.animate(from: NSValue(CGPoint: from), to: NSValue(CGPoint: to), keyPath: "position", timingFunction: springKey, duration: duration, removeOnCompletion: true, completion: completion)
|
||||
}
|
||||
|
||||
internal func animateBounds(from from: CGRect, to: CGRect, duration: NSTimeInterval, completion: (Bool -> Void)? = nil) {
|
||||
if from == to {
|
||||
return
|
||||
}
|
||||
self.animate(from: NSValue(CGRect: from), to: NSValue(CGRect: to), keyPath: "bounds", timingFunction: springKey, duration: duration, removeOnCompletion: true, completion: completion)
|
||||
}
|
||||
|
||||
public func animateBoundsOriginYAdditive(from from: CGFloat, to: CGFloat, duration: NSTimeInterval) {
|
||||
self.animateAdditive(from: from as NSNumber, to: to as NSNumber, keyPath: "bounds.origin.y", key: "boundsOriginYAdditive", timingFunction: kCAMediaTimingFunctionEaseInEaseOut, duration: duration, removeOnCompletion: true)
|
||||
}
|
||||
|
||||
public func animateFrame(from from: CGRect, to: CGRect, duration: NSTimeInterval, spring: Bool = false, completion: (Bool -> Void)? = nil) {
|
||||
if from == to {
|
||||
return
|
||||
}
|
||||
self.animatePosition(from: CGPoint(x: from.midX, y: from.midY), to: CGPoint(x: to.midX, y: to.midY), duration: duration, completion: nil)
|
||||
self.animateBounds(from: CGRect(origin: self.bounds.origin, size: from.size), to: CGRect(origin: self.bounds.origin, size: to.size), duration: duration, completion: completion)
|
||||
}
|
||||
}
|
||||
|
@ -1269,7 +1269,7 @@ public final class ListView: ASDisplayNode, UIScrollViewDelegate {
|
||||
})
|
||||
}
|
||||
|
||||
private func nodeForItem(synchronous: Bool, item: ListViewItem, previousNode: ListViewItemNode?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, width: CGFloat, completion: (ListViewItemNode, ListViewItemNodeLayout, () -> Void) -> Void) {
|
||||
private func nodeForItem(synchronous: Bool, item: ListViewItem, previousNode: ListViewItemNode?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, width: CGFloat, updateAnimation: ListViewItemUpdateAnimation, completion: (ListViewItemNode, ListViewItemNodeLayout, () -> Void) -> Void) {
|
||||
if let previousNode = previousNode {
|
||||
item.updateNode({ f in
|
||||
if synchronous {
|
||||
@ -1277,7 +1277,7 @@ public final class ListView: ASDisplayNode, UIScrollViewDelegate {
|
||||
} else {
|
||||
self.async(f)
|
||||
}
|
||||
}, node: previousNode, width: width, previousItem: previousItem, nextItem: nextItem, completion: { (layout, apply) in
|
||||
}, node: previousNode, width: width, previousItem: previousItem, nextItem: nextItem, animation: updateAnimation, completion: { (layout, apply) in
|
||||
if NSThread.isMainThread() {
|
||||
if synchronous {
|
||||
completion(previousNode, layout, {
|
||||
@ -1637,7 +1637,7 @@ public final class ListView: ASDisplayNode, UIScrollViewDelegate {
|
||||
} else {
|
||||
self.async(f)
|
||||
}
|
||||
}, node: referenceNode, width: state.visibleSize.width, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: index == self.items.count - 1 ? nil : self.items[index + 1], completion: { layout, apply in
|
||||
}, node: referenceNode, width: state.visibleSize.width, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: index == self.items.count - 1 ? nil : self.items[index + 1], animation: .None, completion: { layout, apply in
|
||||
var updatedState = state
|
||||
var updatedOperations = operations
|
||||
|
||||
@ -1670,6 +1670,7 @@ public final class ListView: ASDisplayNode, UIScrollViewDelegate {
|
||||
var previousNodes = inputPreviousNodes
|
||||
var operations = inputOperations
|
||||
let completion = inputCompletion
|
||||
let updateAnimation: ListViewItemUpdateAnimation = animated ? .System(duration: insertionAnimationDuration) : .None
|
||||
|
||||
while true {
|
||||
if self.items.count == 0 {
|
||||
@ -1694,7 +1695,7 @@ public final class ListView: ASDisplayNode, UIScrollViewDelegate {
|
||||
let index = insertionItemIndexAndDirection.0
|
||||
let threadId = pthread_self()
|
||||
var tailRecurse = false
|
||||
self.nodeForItem(synchronous, item: self.items[index], previousNode: previousNodes[index], index: index, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: self.items.count == index + 1 ? nil : self.items[index + 1], width: state.visibleSize.width, completion: { (node, layout, apply) in
|
||||
self.nodeForItem(synchronous, item: self.items[index], previousNode: previousNodes[index], index: index, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: self.items.count == index + 1 ? nil : self.items[index + 1], width: state.visibleSize.width, updateAnimation: updateAnimation, completion: { (node, layout, apply) in
|
||||
|
||||
if pthread_equal(pthread_self(), threadId) != 0 && !tailRecurse {
|
||||
tailRecurse = true
|
||||
@ -1749,6 +1750,10 @@ public final class ListView: ASDisplayNode, UIScrollViewDelegate {
|
||||
let previousApparentHeight = node.apparentHeight
|
||||
let previousInsets = node.insets
|
||||
|
||||
if node.wantsScrollDynamics && previousFrame != nil {
|
||||
assert(true)
|
||||
}
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
node.apparentHeight = animated ? 0.0 : layout.size.height
|
||||
@ -1787,6 +1792,16 @@ public final class ListView: ASDisplayNode, UIScrollViewDelegate {
|
||||
nextNode.removeApparentHeightAnimation()
|
||||
|
||||
takenAnimation = true
|
||||
|
||||
if abs(layout.size.height - previousApparentHeight) > CGFloat(FLT_EPSILON) {
|
||||
node.addApparentHeightAnimation(layout.size.height, duration: insertionAnimationDuration, beginAt: timestamp, update: { [weak node] progress in
|
||||
if let node = node {
|
||||
node.animateFrameTransition(progress)
|
||||
}
|
||||
})
|
||||
node.transitionOffset = previousApparentHeight - layout.size.height
|
||||
node.addTransitionOffsetAnimation(0.0, duration: insertionAnimationDuration, beginAt: timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2285,7 +2300,9 @@ public final class ListView: ASDisplayNode, UIScrollViewDelegate {
|
||||
updatedAccessoryItemNodeOrigin.y += updatedParentOrigin.y
|
||||
updatedAccessoryItemNodeOrigin.y -= itemNode.bounds.origin.y
|
||||
|
||||
nextAccessoryItemNode.animateTransitionOffset(CGPoint(x: 0.0, y: updatedAccessoryItemNodeOrigin.y - previousAccessoryItemNodeOrigin.y), beginAt: currentTimestamp, duration: insertionAnimationDuration * UIView.animationDurationFactor(), curve: listViewAnimationCurveSystem)
|
||||
let deltaHeight = itemNode.frame.size.height - nextItemNode.frame.size.height
|
||||
|
||||
nextAccessoryItemNode.animateTransitionOffset(CGPoint(x: 0.0, y: updatedAccessoryItemNodeOrigin.y - previousAccessoryItemNodeOrigin.y - deltaHeight), beginAt: currentTimestamp, duration: insertionAnimationDuration * UIView.animationDurationFactor(), curve: listViewAnimationCurveSystem)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
|
@ -12,7 +12,7 @@ public class ListViewAccessoryItemNode: ASDisplayNode {
|
||||
|
||||
final func animateTransitionOffset(from: CGPoint, beginAt: Double, duration: Double, curve: CGFloat -> CGFloat) {
|
||||
self.transitionOffset = from
|
||||
self.transitionOffsetAnimation = ListViewAnimation(from: from, to: CGPoint(), duration: duration, curve: curve, beginAt: beginAt, update: { [weak self] currentValue in
|
||||
self.transitionOffsetAnimation = ListViewAnimation(from: from, to: CGPoint(), duration: duration, curve: curve, beginAt: beginAt, update: { [weak self] _, currentValue in
|
||||
if let strongSelf = self {
|
||||
strongSelf.transitionOffset = currentValue
|
||||
}
|
||||
|
@ -43,6 +43,16 @@ extension UIEdgeInsets: Interpolatable {
|
||||
}
|
||||
}
|
||||
|
||||
extension CGRect: Interpolatable {
|
||||
public static func interpolator() -> (Interpolatable, Interpolatable, CGFloat) -> Interpolatable {
|
||||
return { from, to, t -> Interpolatable in
|
||||
let fromValue = from as! CGRect
|
||||
let toValue = to as! CGRect
|
||||
return floorToPixels(CGRect(x: toValue.origin.x * t + fromValue.origin.x * (1.0 - t), y: toValue.origin.y * t + fromValue.origin.y * (1.0 - t), width: toValue.size.width * t + fromValue.size.width * (1.0 - t), height: toValue.size.height * t + fromValue.size.height * (1.0 - t)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CGPoint: Interpolatable {
|
||||
public static func interpolator() -> (Interpolatable, Interpolatable, CGFloat) -> Interpolatable {
|
||||
return { from, to, t -> Interpolatable in
|
||||
@ -55,11 +65,10 @@ extension CGPoint: Interpolatable {
|
||||
|
||||
private let springAnimationIn: CASpringAnimation = {
|
||||
let animation = CASpringAnimation()
|
||||
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
|
||||
animation.duration = 0.6
|
||||
animation.damping = 500.0
|
||||
animation.stiffness = 1000.0
|
||||
animation.mass = 3.0
|
||||
animation.duration = animation.settlingDuration
|
||||
return animation
|
||||
}()
|
||||
|
||||
@ -87,18 +96,18 @@ public final class ListViewAnimation {
|
||||
let startTime: Double
|
||||
private let curve: CGFloat -> CGFloat
|
||||
private let interpolator: (Interpolatable, Interpolatable, CGFloat) -> Interpolatable
|
||||
private let update: Interpolatable -> Void
|
||||
private let update: (CGFloat, Interpolatable) -> Void
|
||||
private let completed: Bool -> Void
|
||||
|
||||
public init<T: Interpolatable>(from: T, to: T, duration: Double, curve: CGFloat -> CGFloat, beginAt: Double, update: T -> Void, completed: Bool -> Void = { _ in }) {
|
||||
public init<T: Interpolatable>(from: T, to: T, duration: Double, curve: CGFloat -> CGFloat, beginAt: Double, update: (CGFloat, T) -> Void, completed: Bool -> Void = { _ in }) {
|
||||
self.from = from
|
||||
self.to = to
|
||||
self.duration = duration
|
||||
self.curve = curve
|
||||
self.startTime = beginAt
|
||||
self.interpolator = T.interpolator()
|
||||
self.update = { value in
|
||||
update(value as! T)
|
||||
self.update = { progress, value in
|
||||
update(progress, value as! T)
|
||||
}
|
||||
self.completed = completed
|
||||
}
|
||||
@ -116,21 +125,28 @@ public final class ListViewAnimation {
|
||||
self.completed(false)
|
||||
}
|
||||
|
||||
private func valueAt(timestamp: Double) -> Interpolatable {
|
||||
if timestamp < self.startTime {
|
||||
private func valueAt(t: CGFloat) -> Interpolatable {
|
||||
if t <= 0.0 {
|
||||
return self.from
|
||||
}
|
||||
|
||||
let t = CGFloat((timestamp - self.startTime) / self.duration)
|
||||
|
||||
if t >= 1.0 {
|
||||
} else if t >= 1.0 {
|
||||
return self.to
|
||||
} else {
|
||||
return self.interpolator(self.from, self.to, self.curve(t))
|
||||
return self.interpolator(self.from, self.to, t)
|
||||
}
|
||||
}
|
||||
|
||||
public func applyAt(timestamp: Double) {
|
||||
self.update(self.valueAt(timestamp))
|
||||
var t = CGFloat((timestamp - self.startTime) / self.duration)
|
||||
let ct: CGFloat
|
||||
if t <= 0.0 + CGFloat(FLT_EPSILON) {
|
||||
t = 0.0
|
||||
ct = 0.0
|
||||
} else if t >= 1.0 - CGFloat(FLT_EPSILON) {
|
||||
t = 1.0
|
||||
ct = 1.0
|
||||
} else {
|
||||
ct = self.curve(t)
|
||||
}
|
||||
self.update(ct, self.valueAt(ct))
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,14 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
|
||||
public enum ListViewItemUpdateAnimation {
|
||||
case None
|
||||
case System(duration: Double)
|
||||
}
|
||||
|
||||
public protocol ListViewItem {
|
||||
func nodeConfiguredForWidth(async: (() -> Void) -> Void, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: (ListViewItemNode, () -> Void) -> Void)
|
||||
func updateNode(async: (() -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: (ListViewItemNodeLayout, () -> Void) -> Void)
|
||||
func updateNode(async: (() -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: (ListViewItemNodeLayout, () -> Void) -> Void)
|
||||
|
||||
var accessoryItem: ListViewAccessoryItem? { get }
|
||||
var headerAccessoryItem: ListViewAccessoryItem? { get }
|
||||
@ -28,7 +33,7 @@ public extension ListViewItem {
|
||||
func selected() {
|
||||
}
|
||||
|
||||
func updateNode(async: (() -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: (ListViewItemNodeLayout, () -> Void) -> Void) {
|
||||
func updateNode(async: (() -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: (ListViewItemNodeLayout, () -> Void) -> Void) {
|
||||
completion(ListViewItemNodeLayout(contentSize: node.contentSize, insets: node.insets), {})
|
||||
}
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ public class ListViewItemNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
public func addInsetsAnimationToValue(value: UIEdgeInsets, duration: Double, beginAt: Double) {
|
||||
let animation = ListViewAnimation(from: self.insets, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] currentValue in
|
||||
let animation = ListViewAnimation(from: self.insets, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] _, currentValue in
|
||||
if let strongSelf = self {
|
||||
strongSelf.insets = currentValue
|
||||
}
|
||||
@ -342,10 +342,13 @@ public class ListViewItemNode: ASDisplayNode {
|
||||
self.setAnimationForKey("insets", animation: animation)
|
||||
}
|
||||
|
||||
public func addApparentHeightAnimation(value: CGFloat, duration: Double, beginAt: Double) {
|
||||
let animation = ListViewAnimation(from: self.apparentHeight, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] currentValue in
|
||||
public func addApparentHeightAnimation(value: CGFloat, duration: Double, beginAt: Double, update: ((CGFloat) -> Void)? = nil) {
|
||||
let animation = ListViewAnimation(from: self.apparentHeight, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] progress, currentValue in
|
||||
if let strongSelf = self {
|
||||
strongSelf.apparentHeight = currentValue
|
||||
if let update = update {
|
||||
update(progress)
|
||||
}
|
||||
}
|
||||
})
|
||||
self.setAnimationForKey("apparentHeight", animation: animation)
|
||||
@ -358,7 +361,7 @@ public class ListViewItemNode: ASDisplayNode {
|
||||
duration = 0.0
|
||||
}
|
||||
|
||||
let animation = ListViewAnimation(from: self.apparentHeight, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] currentValue in
|
||||
let animation = ListViewAnimation(from: self.apparentHeight, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] _, currentValue in
|
||||
if let strongSelf = self {
|
||||
strongSelf.apparentHeight = currentValue
|
||||
}
|
||||
@ -373,7 +376,7 @@ public class ListViewItemNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
public func addTransitionOffsetAnimation(value: CGFloat, duration: Double, beginAt: Double) {
|
||||
let animation = ListViewAnimation(from: self.transitionOffset, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] currentValue in
|
||||
let animation = ListViewAnimation(from: self.transitionOffset, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] _, currentValue in
|
||||
if let strongSelf = self {
|
||||
strongSelf.transitionOffset = currentValue
|
||||
}
|
||||
@ -392,4 +395,8 @@ public class ListViewItemNode: ASDisplayNode {
|
||||
|
||||
public func setupGestures() {
|
||||
}
|
||||
|
||||
public func animateFrameTransition(progress: CGFloat) {
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user