145 lines
4.9 KiB
Swift
145 lines
4.9 KiB
Swift
|
|
//
|
|
// TableAnimationInterface.swift
|
|
// TGUIKit
|
|
//
|
|
// Created by keepcoder on 02/10/2016.
|
|
// Copyright © 2016 Telegram. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
|
|
open class TableAnimationInterface: NSObject {
|
|
|
|
public struct AnimateItem {
|
|
public let index: Int
|
|
public let from: NSPoint
|
|
public let to: NSPoint
|
|
}
|
|
|
|
public let scrollBelow:Bool
|
|
public let saveIfAbove:Bool
|
|
let animate:([AnimateItem])->Void
|
|
public init(_ scrollBelow:Bool = true, _ saveIfAbove:Bool = true, _ animate:@escaping([AnimateItem])->Void) {
|
|
self.scrollBelow = scrollBelow
|
|
self.saveIfAbove = saveIfAbove
|
|
self.animate = animate
|
|
}
|
|
|
|
@discardableResult public func animate(table:TableView, documentOffset: NSPoint, added:[TableRowItem], removed:[TableRowItem], previousRange: NSRange = NSMakeRange(NSNotFound, 0)) -> [AnimateItem] {
|
|
|
|
var height:CGFloat = 0
|
|
|
|
let contentView = table.clipView
|
|
let bounds = contentView.bounds
|
|
|
|
var scrollBelow = self.scrollBelow || (bounds.minY - height) < 0
|
|
var checkBelowAfter: Bool = false
|
|
|
|
|
|
|
|
var range:NSRange = table.visibleRows(height)
|
|
|
|
let added = added.filter { item in
|
|
if item.index < range.location || item.index > range.location + range.length {
|
|
return false
|
|
} else {
|
|
return true
|
|
}
|
|
}
|
|
|
|
let removed = removed.filter { item in
|
|
if item.index < range.location || item.index > range.location + range.length {
|
|
return false
|
|
} else {
|
|
return true
|
|
}
|
|
}
|
|
|
|
for item in added {
|
|
height += item.heightValue
|
|
}
|
|
|
|
for item in removed {
|
|
height -= item.heightValue
|
|
}
|
|
|
|
if previousRange.length == 0 {
|
|
return []
|
|
}
|
|
|
|
range = table.visibleRows(height)
|
|
|
|
if added.isEmpty && removed.isEmpty {
|
|
return []
|
|
}
|
|
|
|
if scrollBelow, documentOffset.y >= 0 {
|
|
table.tile()
|
|
contentView.updateBounds(to: NSMakePoint(0, min(0, documentOffset.y)))
|
|
} else {
|
|
checkBelowAfter = true
|
|
}
|
|
|
|
var animatedItems:[AnimateItem] = []
|
|
|
|
scrollBelow = scrollBelow || (checkBelowAfter && (bounds.minY - height) < 0)
|
|
|
|
if height - bounds.height < table.frame.height || bounds.minY > height, scrollBelow {
|
|
|
|
contentView.updateBounds(to: NSMakePoint(0, min(0, documentOffset.y)))
|
|
|
|
if range.length >= added[0].index {
|
|
for idx in added[0].index ..< range.length {
|
|
|
|
if let view = table.viewNecessary(at: idx), let layer = view.layer {
|
|
|
|
var inset = (layer.frame.minY - height);
|
|
if let presentLayer = layer.presentation(), presentLayer.animation(forKey: "position") != nil {
|
|
inset = presentLayer.position.y
|
|
}
|
|
|
|
let from: CGPoint = NSMakePoint(0, inset)
|
|
let to: CGPoint = NSMakePoint(0, layer.position.y)
|
|
|
|
|
|
// if layer.presentation()?.animation(forKey: "position") == nil {
|
|
layer.animatePosition(from: from, to: to, duration: 0.2, timingFunction: .easeOut)
|
|
// }
|
|
|
|
animatedItems.append(AnimateItem(index: added[0].index, from: from, to: to))
|
|
|
|
/*
|
|
if layer.presentation()?.animation(forKey: "position") == nil {
|
|
layer.animatePosition(from: NSMakePoint(0, -height), to: NSZeroPoint, duration: 0.2, timingFunction: .easeOut, additive: true)
|
|
}
|
|
*/
|
|
|
|
for item in added {
|
|
if item.index == idx {
|
|
//layer.animateAlpha(from: 0, to: 1, duration: 0.2)
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if !scrollBelow {
|
|
contentView.bounds = NSMakeRect(0, bounds.minY + height, contentView.bounds.width, contentView.bounds.height)
|
|
table.reflectScrolledClipView(contentView)
|
|
}
|
|
|
|
if !animatedItems.isEmpty {
|
|
self.animate(animatedItems)
|
|
}
|
|
return animatedItems
|
|
}
|
|
|
|
public func scroll(table:TableView, from:NSRect, to:NSRect) -> Void {
|
|
table.contentView.layer?.animateBounds(from: from, to: to, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeOut)
|
|
}
|
|
|
|
|
|
}
|