Home telegram - listViewIntermediateState
Post
Cancel

telegram - listViewIntermediateState

ListViewStateNode

enum ListViewStateNode

1
2
case Node(index: Int, frame: CGRect, referenceNode: QueueLocalObject<ListViewItemNode>?)
case Placeholder(frame: CGRect)

insertNode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
mutating func insertNode(_ itemIndex: Int, node: QueueLocalObject<ListViewItemNode>, layout: ListViewItemNodeLayout, apply: @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void), offsetDirection: ListViewInsertionOffsetDirection, animated: Bool, operations: inout [ListViewStateOperation], itemCount: Int) {
    let (insertionOrigin, insertionIndex) = self.nodeInsertionPointAndIndex(itemIndex)

    let nodeOrigin: CGPoint
    switch offsetDirection {
    case .Up:
        nodeOrigin = CGPoint(x: insertionOrigin.x, y: insertionOrigin.y - (animated ? 0.0 : layout.size.height))
    case .Down:
        nodeOrigin = insertionOrigin
    }

    let nodeFrame = CGRect(origin: nodeOrigin, size: CGSize(width: layout.size.width, height: animated ? 0.0 : layout.size.height))

    operations.append(.InsertNode(index: insertionIndex, offsetDirection: offsetDirection, animated: animated, node: node, layout: layout, apply: apply))
    self.nodes.insert(.Node(index: itemIndex, frame: nodeFrame, referenceNode: nil), at: insertionIndex)

    if !animated {
        switch offsetDirection {
        case .Up:
            var i = insertionIndex - 1
            while i >= 0 {
                var frame = self.nodes[i].frame
                frame.origin.y -= nodeFrame.size.height
                self.nodes[i].frame = frame
                i -= 1
            }
        case .Down:
            var i = insertionIndex + 1
            while i < self.nodes.count {
                var frame = self.nodes[i].frame
                frame.origin.y += nodeFrame.size.height
                self.nodes[i].frame = frame
                i += 1
            }
        }
    }

    var previousIndex: Int?
    for node in self.nodes {
        if let index = node.index {
            if let currentPreviousIndex = previousIndex {
                if index <= currentPreviousIndex {
                    print("index <= previousIndex + 1")
                    break
                }
                previousIndex = index
            } else {
                previousIndex = index
            }
        }
    }

    if let _ = self.scrollPosition {
        self.fixScrollPosition(itemCount)
    }
}

Insert Point

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
func insertionPoint(_ insertDirectionHints: [Int: ListViewItemOperationDirectionHint], itemCount: Int) -> ListViewInsertionPoint? {
    var fixedNode: (nodeIndex: Int, index: Int, frame: CGRect)?

    if let (fixedIndex, _) = self.scrollPosition {
        for i in 0 ..< self.nodes.count {
            let node = self.nodes[i]
            if let index = node.index , index == fixedIndex {
                fixedNode = (i, index, node.frame)
                break
            }
        }

        if fixedNode == nil {
            return ListViewInsertionPoint(index: fixedIndex, point: CGPoint(), direction: .Down)
        }
    }

    var fixedNodeIsStationary = false
    if fixedNode == nil {
        if let (fixedIndex, _) = self.stationaryOffset {
            for i in 0 ..< self.nodes.count {
                let node = self.nodes[i]
                if let index = node.index , index == fixedIndex {
                    fixedNode = (i, index, node.frame)
                    fixedNodeIsStationary = true
                    break
                }
            }
        }
    }

    if fixedNode == nil {
        for i in 0 ..< self.nodes.count {
            let node = self.nodes[i]
            if let index = node.index , node.frame.maxY >= self.insets.top {
                fixedNode = (i, index, node.frame)
                break
            }
        }
    }

    if fixedNode == nil && self.nodes.count != 0 {
        for i in (0 ..< self.nodes.count).reversed() {
            let node = self.nodes[i]
            if let index = node.index {
                fixedNode = (i, index, node.frame)
                break
            }
        }
    }

    if let fixedNode = fixedNode {
        var currentUpperNode = fixedNode
        for i in (0 ..< fixedNode.nodeIndex).reversed() {
            let node = self.nodes[i]
            if let index = node.index {
                if index != currentUpperNode.index - 1 {
                    if currentUpperNode.frame.minY > -self.invisibleInset - CGFloat.ulpOfOne {
                        var directionHint: ListViewInsertionOffsetDirection?
                        if let hint = insertDirectionHints[currentUpperNode.index - 1] , currentUpperNode.frame.minY > self.insets.top - CGFloat.ulpOfOne {
                            directionHint = ListViewInsertionOffsetDirection(hint)
                        }
                        return ListViewInsertionPoint(index: currentUpperNode.index - 1, point: CGPoint(x: 0.0, y: currentUpperNode.frame.minY), direction: directionHint ?? .Up)
                    } else {
                        break
                    }
                }
                currentUpperNode = (i, index, node.frame)
            }
        }

        if currentUpperNode.index != 0 && currentUpperNode.frame.minY > -self.invisibleInset - CGFloat.ulpOfOne {
            var directionHint: ListViewInsertionOffsetDirection?
            if let hint = insertDirectionHints[currentUpperNode.index - 1] {
                if currentUpperNode.frame.minY >= self.insets.top - CGFloat.ulpOfOne {
                    directionHint = ListViewInsertionOffsetDirection(hint)
                }
            } else if currentUpperNode.frame.minY >= self.insets.top - CGFloat.ulpOfOne && !fixedNodeIsStationary {
                directionHint = .Down
            }

            return ListViewInsertionPoint(index: currentUpperNode.index - 1, point: CGPoint(x: 0.0, y: currentUpperNode.frame.minY), direction: directionHint ?? .Up)
        }

        var currentLowerNode = fixedNode
        if fixedNode.nodeIndex + 1 < self.nodes.count {
            for i in (fixedNode.nodeIndex + 1) ..< self.nodes.count {
                let node = self.nodes[i]
                if let index = node.index {
                    if index != currentLowerNode.index + 1 {
                        if currentLowerNode.frame.maxY < self.visibleSize.height + self.invisibleInset - CGFloat.ulpOfOne {
                            var directionHint: ListViewInsertionOffsetDirection?
                            if let hint = insertDirectionHints[currentLowerNode.index + 1] , currentLowerNode.frame.maxY < self.visibleSize.height - self.insets.bottom + CGFloat.ulpOfOne {
                                directionHint = ListViewInsertionOffsetDirection(hint)
                            }
                            return ListViewInsertionPoint(index: currentLowerNode.index + 1, point: CGPoint(x: 0.0, y: currentLowerNode.frame.maxY), direction: directionHint ?? .Down)
                        } else {
                            break
                        }
                    }
                    currentLowerNode = (i, index, node.frame)
                }
            }
        }

        if currentLowerNode.index != itemCount - 1 && currentLowerNode.frame.maxY < self.visibleSize.height + self.invisibleInset - CGFloat.ulpOfOne {
            var directionHint: ListViewInsertionOffsetDirection?
            if let hint = insertDirectionHints[currentLowerNode.index + 1] , currentLowerNode.frame.maxY < self.visibleSize.height - self.insets.bottom + CGFloat.ulpOfOne {
                directionHint = ListViewInsertionOffsetDirection(hint)
            }
            return ListViewInsertionPoint(index: currentLowerNode.index + 1, point: CGPoint(x: 0.0, y: currentLowerNode.frame.maxY), direction: directionHint ?? .Down)
        }
    } else if itemCount != 0 {
        return ListViewInsertionPoint(index: 0, point: CGPoint(x: 0.0, y: self.insets.top), direction: .Down)
    }

    return nil
}
This post is licensed under CC BY 4.0 by the author.