no message

This commit is contained in:
Peter 2016-12-22 03:19:59 +03:00
parent bed02f5c56
commit 269fccdcc9
9 changed files with 231 additions and 76 deletions

View File

@ -32,6 +32,9 @@ public enum ContainedViewLayoutTransition {
public extension ContainedViewLayoutTransition { public extension ContainedViewLayoutTransition {
func updateFrame(node: ASDisplayNode, frame: CGRect, completion: ((Bool) -> Void)? = nil) { func updateFrame(node: ASDisplayNode, frame: CGRect, completion: ((Bool) -> Void)? = nil) {
if node.frame.equalTo(frame) {
completion?(true)
} else {
switch self { switch self {
case .immediate: case .immediate:
node.frame = frame node.frame = frame
@ -48,8 +51,12 @@ public extension ContainedViewLayoutTransition {
}) })
} }
} }
}
func updatePosition(node: ASDisplayNode, position: CGPoint, completion: ((Bool) -> Void)? = nil) { func updatePosition(node: ASDisplayNode, position: CGPoint, completion: ((Bool) -> Void)? = nil) {
if node.position.equalTo(position) {
completion?(true)
} else {
switch self { switch self {
case .immediate: case .immediate:
node.position = position node.position = position
@ -66,6 +73,7 @@ public extension ContainedViewLayoutTransition {
}) })
} }
} }
}
func animatePosition(node: ASDisplayNode, from position: CGPoint, completion: ((Bool) -> Void)? = nil) { func animatePosition(node: ASDisplayNode, from position: CGPoint, completion: ((Bool) -> Void)? = nil) {
switch self { switch self {
@ -83,6 +91,9 @@ public extension ContainedViewLayoutTransition {
} }
func animatePosition(node: ASDisplayNode, to position: CGPoint, removeOnCompletion: Bool = true, completion: ((Bool) -> Void)? = nil) { func animatePosition(node: ASDisplayNode, to position: CGPoint, removeOnCompletion: Bool = true, completion: ((Bool) -> Void)? = nil) {
if node.position.equalTo(position) {
completion?(true)
} else {
switch self { switch self {
case .immediate: case .immediate:
if let completion = completion { if let completion = completion {
@ -96,6 +107,7 @@ public extension ContainedViewLayoutTransition {
}) })
} }
} }
}
func animateOffsetAdditive(node: ASDisplayNode, offset: CGFloat) { func animateOffsetAdditive(node: ASDisplayNode, offset: CGFloat) {
switch self { switch self {
@ -115,6 +127,9 @@ public extension ContainedViewLayoutTransition {
} }
func updateFrame(layer: CALayer, frame: CGRect, completion: ((Bool) -> Void)? = nil) { func updateFrame(layer: CALayer, frame: CGRect, completion: ((Bool) -> Void)? = nil) {
if layer.frame.equalTo(frame) {
completion?(true)
} else {
switch self { switch self {
case .immediate: case .immediate:
layer.frame = frame layer.frame = frame
@ -131,6 +146,7 @@ public extension ContainedViewLayoutTransition {
}) })
} }
} }
}
func updateAlpha(node: ASDisplayNode, alpha: CGFloat, completion: ((Bool) -> Void)? = nil) { func updateAlpha(node: ASDisplayNode, alpha: CGFloat, completion: ((Bool) -> Void)? = nil) {
if node.alpha.isEqual(to: alpha) { if node.alpha.isEqual(to: alpha) {

View File

@ -13,6 +13,18 @@ public struct Font {
return CTFontCreateWithName("HelveticaNeue-Medium" as CFString, size, nil) return CTFontCreateWithName("HelveticaNeue-Medium" as CFString, size, nil)
} }
} }
public static func bold(_ size: CGFloat) -> UIFont {
if #available(iOS 8.2, *) {
return UIFont.systemFont(ofSize: size, weight: UIFontWeightBold)
} else {
return CTFontCreateWithName("HelveticaNeue-Bold" as CFString, size, nil)
}
}
public static func italic(_ size: CGFloat) -> UIFont {
return UIFont.italicSystemFont(ofSize: size)
}
} }
public extension NSAttributedString { public extension NSAttributedString {

View File

@ -87,7 +87,16 @@ public func generateStretchableFilledCircleImage(radius: CGFloat, color: UIColor
public func generateStretchableFilledCircleImage(diameter: CGFloat, color: UIColor?, backgroundColor: UIColor? = nil) -> UIImage? { public func generateStretchableFilledCircleImage(diameter: CGFloat, color: UIColor?, backgroundColor: UIColor? = nil) -> UIImage? {
let intRadius = Int(diameter / 2.0) let intRadius = Int(diameter / 2.0)
let cap = intRadius == 1 ? 2 : intRadius let intDiameter = Int(diameter)
let cap: Int
if intDiameter == 3 {
cap = 1
} else if intRadius == 1 {
cap = 2
} else {
cap = intRadius
}
return generateFilledCircleImage(diameter: diameter, color: color, backgroundColor: backgroundColor)?.stretchableImage(withLeftCapWidth: cap, topCapHeight: cap) return generateFilledCircleImage(diameter: diameter, color: color, backgroundColor: backgroundColor)?.stretchableImage(withLeftCapWidth: cap, topCapHeight: cap)
} }

View File

@ -1,6 +1,15 @@
import UIKit import UIKit
private class GridNodeScrollerLayer: CALayer {
override func setNeedsDisplay() {
}
}
private class GridNodeScrollerView: UIScrollView { private class GridNodeScrollerView: UIScrollView {
override class var layerClass: AnyClass {
return GridNodeScrollerLayer.self
}
override func touchesShouldCancel(in view: UIView) -> Bool { override func touchesShouldCancel(in view: UIView) -> Bool {
return true return true
} }

View File

@ -14,6 +14,9 @@ private final class ListViewBackingLayer: CALayer {
override func layoutSublayers() { override func layoutSublayers() {
} }
override func setNeedsDisplay() {
}
} }
final class ListViewBackingView: UIView { final class ListViewBackingView: UIView {
@ -146,6 +149,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
private var flashNodesDelayTimer: Foundation.Timer? private var flashNodesDelayTimer: Foundation.Timer?
private var highlightedItemIndex: Int? private var highlightedItemIndex: Int?
private let waitingForNodesDisposable = MetaDisposable()
public func reportDurationInMS(duration: Int, smallDropEvent: Double, largeDropEvent: Double) { public func reportDurationInMS(duration: Int, smallDropEvent: Double, largeDropEvent: Double) {
print("reportDurationInMS duration: \(duration), smallDropEvent: \(smallDropEvent), largeDropEvent: \(largeDropEvent)") print("reportDurationInMS duration: \(duration), smallDropEvent: \(smallDropEvent), largeDropEvent: \(largeDropEvent)")
} }
@ -241,6 +246,15 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
deinit { deinit {
self.pauseAnimations() self.pauseAnimations()
self.displayLink.invalidate() self.displayLink.invalidate()
for itemNode in self.itemNodes {
ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: itemNode)
}
for itemHeaderNode in self.itemHeaderNodes {
ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: itemHeaderNode)
}
self.waitingForNodesDisposable.dispose()
} }
@objc func frictionSliderChanged(_ slider: UISlider) { @objc func frictionSliderChanged(_ slider: UISlider) {
@ -738,7 +752,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
DispatchQueue.global().async(execute: f) DispatchQueue.global().async(execute: f)
} }
private func nodeForItem(synchronous: Bool, item: ListViewItem, previousNode: ListViewItemNode?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, width: CGFloat, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNode, ListViewItemNodeLayout, @escaping () -> Void) -> Void) { private func nodeForItem(synchronous: Bool, item: ListViewItem, previousNode: ListViewItemNode?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, width: CGFloat, updateAnimation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNode, ListViewItemNodeLayout, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
if let previousNode = previousNode { if let previousNode = previousNode {
item.updateNode(async: { f in item.updateNode(async: { f in
if synchronous { if synchronous {
@ -750,22 +764,28 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
if Thread.isMainThread { if Thread.isMainThread {
if synchronous { if synchronous {
completion(previousNode, layout, { completion(previousNode, layout, {
return (nil, {
previousNode.index = index previousNode.index = index
apply() apply()
}) })
})
} else { } else {
self.async { self.async {
completion(previousNode, layout, { completion(previousNode, layout, {
return (nil, {
previousNode.index = index previousNode.index = index
apply() apply()
}) })
})
} }
} }
} else { } else {
completion(previousNode, layout, { completion(previousNode, layout, {
return (nil, {
previousNode.index = index previousNode.index = index
apply() apply()
}) })
})
} }
}) })
} else { } else {
@ -1068,7 +1088,53 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
let stationaryItemIndex = updatedState.stationaryOffset?.0 let stationaryItemIndex = updatedState.stationaryOffset?.0
let next = { let next = {
self.replayOperations(animated: animated, animateAlpha: options.contains(.AnimateAlpha), animateTopItemVerticalOrigin: options.contains(.AnimateTopItemPosition), operations: updatedOperations, requestItemInsertionAnimationsIndices: options.contains(.RequestItemInsertionAnimations) ? insertedIndexSet : Set(), scrollToItem: scrollToItem, updateSizeAndInsets: updateSizeAndInsets, stationaryItemIndex: stationaryItemIndex, updateOpaqueState: updateOpaqueState, completion: completion) var updatedOperations = updatedOperations
var readySignals: [Signal<Void, NoError>]?
if options.contains(.PreferSynchronousResourceLoading) {
var currentReadySignals: [Signal<Void, NoError>] = []
for i in 0 ..< updatedOperations.count {
if case let .InsertNode(index, offsetDirection, node, layout, apply) = updatedOperations[i] {
let (ready, commitApply) = apply()
updatedOperations[i] = .InsertNode(index: index, offsetDirection: offsetDirection, node: node, layout: layout, apply: {
return (nil, commitApply)
})
if let ready = ready {
currentReadySignals.append(ready)
}
}
}
readySignals = currentReadySignals
}
let beginReplay = { [weak self] in
if let strongSelf = self {
strongSelf.replayOperations(animated: animated, animateAlpha: options.contains(.AnimateAlpha), animateTopItemVerticalOrigin: options.contains(.AnimateTopItemPosition), operations: updatedOperations, requestItemInsertionAnimationsIndices: options.contains(.RequestItemInsertionAnimations) ? insertedIndexSet : Set(), scrollToItem: scrollToItem, updateSizeAndInsets: updateSizeAndInsets, stationaryItemIndex: stationaryItemIndex, updateOpaqueState: updateOpaqueState, completion: {
if options.contains(.PreferSynchronousResourceLoading) {
let startTime = CACurrentMediaTime()
self?.recursivelyEnsureDisplaySynchronously(true)
let deltaTime = CACurrentMediaTime() - startTime
print("ListView: waited \(deltaTime * 1000.0) ms for nodes to display")
}
completion()
})
}
}
if let readySignals = readySignals, !readySignals.isEmpty && false {
let readyWithTimeout = combineLatest(readySignals)
|> deliverOnMainQueue
|> timeout(0.2, queue: Queue.mainQueue(), alternate: .single([]))
let startTime = CACurrentMediaTime()
self.waitingForNodesDisposable.set(readyWithTimeout.start(completed: {
let deltaTime = CACurrentMediaTime() - startTime
print("ListView: waited \(deltaTime * 1000.0) ms for nodes to load")
beginReplay()
}))
} else {
beginReplay()
}
} }
if options.contains(.LowLatency) || options.contains(.Synchronous) { if options.contains(.LowLatency) || options.contains(.Synchronous) {
@ -1123,7 +1189,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
let heightDelta = layout.size.height - updatedState.nodes[i].frame.size.height let heightDelta = layout.size.height - updatedState.nodes[i].frame.size.height
updatedOperations.append(.UpdateLayout(index: i, layout: layout, apply: apply)) updatedOperations.append(.UpdateLayout(index: i, layout: layout, apply: {
return (nil, apply)
}))
if !animated { if !animated {
let previousFrame = updatedState.nodes[i].frame let previousFrame = updatedState.nodes[i].frame
@ -1252,7 +1320,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
} }
} }
private func insertNodeAtIndex(animated: Bool, animateAlpha: Bool, forceAnimateInsertion: Bool, previousFrame: CGRect?, nodeIndex: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> (), timestamp: Double) { private func insertNodeAtIndex(animated: Bool, animateAlpha: Bool, forceAnimateInsertion: Bool, previousFrame: CGRect?, nodeIndex: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> (Signal<Void, NoError>?, () -> Void), timestamp: Double) {
let insertionOrigin = self.referencePointForInsertionAtIndex(nodeIndex) let insertionOrigin = self.referencePointForInsertionAtIndex(nodeIndex)
let nodeOrigin: CGPoint let nodeOrigin: CGPoint
@ -1272,7 +1340,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
node.insets = layout.insets node.insets = layout.insets
node.apparentHeight = animated ? 0.0 : layout.size.height node.apparentHeight = animated ? 0.0 : layout.size.height
node.frame = nodeFrame node.frame = nodeFrame
apply() apply().1()
self.itemNodes.insert(node, at: nodeIndex) self.itemNodes.insert(node, at: nodeIndex)
if useDynamicTuning { if useDynamicTuning {
@ -1514,10 +1582,10 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
if let height = height, let previousLayout = previousLayout { if let height = height, let previousLayout = previousLayout {
if takenPreviousNodes.contains(referenceNode) { if takenPreviousNodes.contains(referenceNode) {
self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: ListViewItemNode(layerBacked: true), layout: ListViewItemNodeLayout(contentSize: CGSize(width: self.visibleSize.width, height: height), insets: UIEdgeInsets()), apply: { }, timestamp: timestamp) self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: ListViewItemNode(layerBacked: true), layout: ListViewItemNodeLayout(contentSize: CGSize(width: self.visibleSize.width, height: height), insets: UIEdgeInsets()), apply: { return (nil, {}) }, timestamp: timestamp)
} else { } else {
referenceNode.index = nil referenceNode.index = nil
self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: referenceNode, layout: previousLayout, apply: { }, timestamp: timestamp) self.insertNodeAtIndex(animated: false, animateAlpha: false, forceAnimateInsertion: false, previousFrame: nil, nodeIndex: index, offsetDirection: offsetDirection, node: referenceNode, layout: previousLayout, apply: { return (nil, {}) }, timestamp: timestamp)
self.addSubnode(referenceNode) self.addSubnode(referenceNode)
} }
} else { } else {
@ -1562,7 +1630,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
node.contentSize = layout.contentSize node.contentSize = layout.contentSize
node.insets = layout.insets node.insets = layout.insets
apply() apply().1()
let updatedApparentHeight = node.bounds.size.height let updatedApparentHeight = node.bounds.size.height
let updatedInsets = node.insets let updatedInsets = node.insets
@ -1893,7 +1961,6 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
let lowestHeaderNode = self.lowestHeaderNode() let lowestHeaderNode = self.lowestHeaderNode()
for itemNode in temporaryPreviousNodes { for itemNode in temporaryPreviousNodes {
itemNode.frame = itemNode.frame.offsetBy(dx: 0.0, dy: offset) itemNode.frame = itemNode.frame.offsetBy(dx: 0.0, dy: offset)
temporaryPreviousNodes.append(itemNode)
if let lowestHeaderNode = lowestHeaderNode { if let lowestHeaderNode = lowestHeaderNode {
self.insertSubnode(itemNode, belowSubnode: lowestHeaderNode) self.insertSubnode(itemNode, belowSubnode: lowestHeaderNode)
} else { } else {
@ -1942,12 +2009,18 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
animation.completion = { _ in animation.completion = { _ in
for itemNode in temporaryPreviousNodes { for itemNode in temporaryPreviousNodes {
itemNode.removeFromSupernode() itemNode.removeFromSupernode()
ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: itemNode)
} }
for headerNode in temporaryHeaderNodes { for headerNode in temporaryHeaderNodes {
headerNode.removeFromSupernode() headerNode.removeFromSupernode()
ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: headerNode)
} }
} }
self.layer.add(animation, forKey: nil) self.layer.add(animation, forKey: nil)
} else {
for itemNode in temporaryPreviousNodes {
ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: itemNode)
}
} }
} }
@ -1977,6 +2050,12 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
//print("replayOperations \(delta * 1000.0) ms") //print("replayOperations \(delta * 1000.0) ms")
} }
for (previousNode, _) in previousApparentFrames {
if previousNode.supernode == nil {
ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: previousNode)
}
}
completion() completion()
} }
}) })
@ -2306,6 +2385,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
let node = self.itemNodes[i] let node = self.itemNodes[i]
if node.index == nil && node.apparentHeight <= CGFloat(FLT_EPSILON) { if node.index == nil && node.apparentHeight <= CGFloat(FLT_EPSILON) {
self.removeItemNodeAtIndex(i) self.removeItemNodeAtIndex(i)
ASDeallocQueue.sharedDeallocation().releaseObject(inBackground: node)
} else { } else {
i += 1 i += 1
} }
@ -2507,6 +2587,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
if true { //!(itemNode.hitTest(CGPoint(x: strongSelf.touchesPosition.x - itemNode.frame.minX, y: strongSelf.touchesPosition.y - itemNode.frame.minY), with: event) is UIControl) { if true { //!(itemNode.hitTest(CGPoint(x: strongSelf.touchesPosition.x - itemNode.frame.minX, y: strongSelf.touchesPosition.y - itemNode.frame.minY), with: event) is UIControl) {
if !itemNode.isLayerBacked { if !itemNode.isLayerBacked {
strongSelf.view.bringSubview(toFront: itemNode.view) strongSelf.view.bringSubview(toFront: itemNode.view)
for (_, headerNode) in strongSelf.itemHeaderNodes {
strongSelf.view.bringSubview(toFront: headerNode.view)
}
} }
itemNode.setHighlighted(true, animated: false) itemNode.setHighlighted(true, animated: false)
} }
@ -2594,6 +2677,9 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
if itemNode.index == index { if itemNode.index == index {
if !itemNode.isLayerBacked { if !itemNode.isLayerBacked {
self.view.bringSubview(toFront: itemNode.view) self.view.bringSubview(toFront: itemNode.view)
for (_, headerNode) in self.itemHeaderNodes {
self.view.bringSubview(toFront: headerNode.view)
}
} }
itemNode.setHighlighted(true, animated: false) itemNode.setHighlighted(true, animated: false)
break break

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import SwiftSignalKit
public enum ListViewCenterScrollPositionOverflow { public enum ListViewCenterScrollPositionOverflow {
case Top case Top
@ -121,6 +122,7 @@ public struct ListViewDeleteAndInsertOptions: OptionSet {
public static let Synchronous = ListViewDeleteAndInsertOptions(rawValue: 8) public static let Synchronous = ListViewDeleteAndInsertOptions(rawValue: 8)
public static let RequestItemInsertionAnimations = ListViewDeleteAndInsertOptions(rawValue: 16) public static let RequestItemInsertionAnimations = ListViewDeleteAndInsertOptions(rawValue: 16)
public static let AnimateTopItemPosition = ListViewDeleteAndInsertOptions(rawValue: 32) public static let AnimateTopItemPosition = ListViewDeleteAndInsertOptions(rawValue: 32)
public static let PreferSynchronousResourceLoading = ListViewDeleteAndInsertOptions(rawValue: 64)
} }
public struct ListViewUpdateSizeAndInsets { public struct ListViewUpdateSizeAndInsets {
@ -222,7 +224,7 @@ struct TransactionState {
struct PendingNode { struct PendingNode {
let index: Int let index: Int
let node: ListViewItemNode let node: ListViewItemNode
let apply: () -> () let apply: () -> (Signal<Void, NoError>?, () -> Void)
let frame: CGRect let frame: CGRect
let apparentHeight: CGFloat let apparentHeight: CGFloat
} }
@ -701,7 +703,7 @@ struct ListViewState {
return height return height
} }
mutating func insertNode(_ itemIndex: Int, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: @escaping () -> (), offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, operations: inout [ListViewStateOperation], itemCount: Int) { mutating func insertNode(_ itemIndex: Int, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: @escaping () -> (Signal<Void, NoError>?, () -> Void), offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, operations: inout [ListViewStateOperation], itemCount: Int) {
let (insertionOrigin, insertionIndex) = self.nodeInsertionPointAndIndex(itemIndex) let (insertionOrigin, insertionIndex) = self.nodeInsertionPointAndIndex(itemIndex)
let nodeOrigin: CGPoint let nodeOrigin: CGPoint
@ -806,7 +808,7 @@ struct ListViewState {
} }
} }
mutating func updateNodeAtItemIndex(_ itemIndex: Int, layout: ListViewItemNodeLayout, direction: ListViewItemOperationDirectionHint?, animation: ListViewItemUpdateAnimation, apply: @escaping () -> Void, operations: inout [ListViewStateOperation]) { mutating func updateNodeAtItemIndex(_ itemIndex: Int, layout: ListViewItemNodeLayout, direction: ListViewItemOperationDirectionHint?, animation: ListViewItemUpdateAnimation, apply: @escaping () -> (Signal<Void, NoError>?, () -> Void), operations: inout [ListViewStateOperation]) {
var i = -1 var i = -1
for node in self.nodes { for node in self.nodes {
i += 1 i += 1
@ -862,9 +864,9 @@ struct ListViewState {
} }
enum ListViewStateOperation { enum ListViewStateOperation {
case InsertNode(index: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> ()) case InsertNode(index: Int, offsetDirection: ListViewInsertionOffsetDirection, node: ListViewItemNode, layout: ListViewItemNodeLayout, apply: () -> (Signal<Void, NoError>?, () -> Void))
case InsertDisappearingPlaceholder(index: Int, referenceNode: ListViewItemNode, offsetDirection: ListViewInsertionOffsetDirection) case InsertDisappearingPlaceholder(index: Int, referenceNode: ListViewItemNode, offsetDirection: ListViewInsertionOffsetDirection)
case Remove(index: Int, offsetDirection: ListViewInsertionOffsetDirection) case Remove(index: Int, offsetDirection: ListViewInsertionOffsetDirection)
case Remap([Int: Int]) case Remap([Int: Int])
case UpdateLayout(index: Int, layout: ListViewItemNodeLayout, apply: () -> ()) case UpdateLayout(index: Int, layout: ListViewItemNodeLayout, apply: () -> (Signal<Void, NoError>?, () -> Void))
} }

View File

@ -6,8 +6,22 @@ public enum ListViewItemUpdateAnimation {
case System(duration: Double) case System(duration: Double)
} }
public struct ListViewItemConfigureNodeFlags: OptionSet {
public var rawValue: Int32
public init() {
self.rawValue = 0
}
public init(rawValue: Int32) {
self.rawValue = rawValue
}
public static let preferSynchronousResourceLoading = ListViewItemConfigureNodeFlags(rawValue: 1 << 0)
}
public protocol ListViewItem { public protocol ListViewItem {
func nodeConfiguredForWidth(async: @escaping (@escaping () -> Void) -> Void, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> Void) -> Void) func nodeConfiguredForWidth(async: @escaping (@escaping () -> Void) -> Void, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void)
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping () -> Void) -> Void) func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping () -> Void) -> Void)
var accessoryItem: ListViewAccessoryItem? { get } var accessoryItem: ListViewAccessoryItem? { get }
@ -37,8 +51,4 @@ public extension ListViewItem {
func selected(listView: ListView) { func selected(listView: ListView) {
} }
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: ListViewItemNode, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping () -> Void) -> Void) {
completion(ListViewItemNodeLayout(contentSize: node.contentSize, insets: node.insets), {})
}
} }

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit
var testSpringFrictionLimits: (CGFloat, CGFloat) = (3.0, 60.0) var testSpringFrictionLimits: (CGFloat, CGFloat) = (3.0, 60.0)
var testSpringFriction: CGFloat = 31.8211269378662 var testSpringFriction: CGFloat = 31.8211269378662
@ -133,6 +134,10 @@ open class ListViewItemNode: ASDisplayNode {
return ListViewItemNodeLayout(contentSize: contentSize, insets: insets) return ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
} }
public var displayResourcesReady: Signal<Void, NoError> {
return .complete()
}
public init(layerBacked: Bool, dynamicBounce: Bool = true, rotated: Bool = false) { public init(layerBacked: Bool, dynamicBounce: Bool = true, rotated: Bool = false) {
if true { if true {
if dynamicBounce { if dynamicBounce {
@ -163,6 +168,12 @@ open class ListViewItemNode: ASDisplayNode {
self.isLayerBacked = layerBacked self.isLayerBacked = layerBacked
} }
/*deinit {
if Thread.isMainThread {
print("deallocating on main thread")
}
}*/
var apparentHeight: CGFloat = 0.0 var apparentHeight: CGFloat = 0.0
private var _bounds: CGRect = CGRect() private var _bounds: CGRect = CGRect()
private var _position: CGPoint = CGPoint() private var _position: CGPoint = CGPoint()

View File

@ -56,7 +56,7 @@ class NavigationTransitionCoordinator {
self.dimView.backgroundColor = UIColor.black self.dimView.backgroundColor = UIColor.black
self.shadowView = UIImageView(image: shadowImage) self.shadowView = UIImageView(image: shadowImage)
if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar { if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar, !topNavigationBar.isHidden, !bottomNavigationBar.isHidden {
var topFrame = topNavigationBar.view.convert(topNavigationBar.bounds, to: container) var topFrame = topNavigationBar.view.convert(topNavigationBar.bounds, to: container)
var bottomFrame = bottomNavigationBar.view.convert(bottomNavigationBar.bounds, to: container) var bottomFrame = bottomNavigationBar.view.convert(bottomNavigationBar.bounds, to: container)
topFrame.origin.x = 0.0 topFrame.origin.x = 0.0
@ -111,7 +111,7 @@ class NavigationTransitionCoordinator {
} }
func updateNavigationBarTransition() { func updateNavigationBarTransition() {
if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar { if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar, self.inlineNavigationBarTransition {
let position: CGFloat let position: CGFloat
switch self.transition { switch self.transition {
case .Push: case .Push:
@ -126,7 +126,7 @@ class NavigationTransitionCoordinator {
} }
func maybeCreateNavigationBarTransition() { func maybeCreateNavigationBarTransition() {
if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar { if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar, self.inlineNavigationBarTransition {
let position: CGFloat let position: CGFloat
switch self.transition { switch self.transition {
case .Push: case .Push:
@ -141,7 +141,7 @@ class NavigationTransitionCoordinator {
} }
func endNavigationBarTransition() { func endNavigationBarTransition() {
if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar { if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar, self.inlineNavigationBarTransition {
topNavigationBar.transitionState = nil topNavigationBar.transitionState = nil
bottomNavigationBar.transitionState = nil bottomNavigationBar.transitionState = nil
} }