-
Notifications
You must be signed in to change notification settings - Fork 265
Expand file tree
/
Copy pathSimpleLayout.swift
More file actions
114 lines (98 loc) · 3.04 KB
/
SimpleLayout.swift
File metadata and controls
114 lines (98 loc) · 3.04 KB
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
//
// SimpleLayout.swift
// CollectionKit
//
// Created by Luke Zhao on 2017-09-11.
// Copyright © 2017 lkzhao. All rights reserved.
//
import UIKit
open class SimpleLayout: Layout {
var _contentSize: CGSize = .zero
public private(set) var frames: [CGRect] = []
open func simpleLayout(context: LayoutContext) -> [CGRect] {
fatalError("Subclass should provide its own layout")
}
open func doneLayout() {
}
public final override func layout(context: LayoutContext) {
frames = simpleLayout(context: context)
_contentSize = frames.reduce(CGRect.zero) { (old, item) in
old.union(item)
}.size
doneLayout()
}
public final override var contentSize: CGSize {
return _contentSize
}
public final override func frame(at: Int) -> CGRect {
return frames[at]
}
open override func visible(in visibleFrame: CGRect) -> (indexes: [Int], frame: CGRect) {
var result = [Int]()
for (i, frame) in frames.enumerated() {
if frame.intersects(visibleFrame) {
result.append(i)
}
}
return (result, visibleFrame)
}
}
open class VerticalSimpleLayout: SimpleLayout {
private var maxFrameLength: CGFloat = 0
open override func doneLayout() {
maxFrameLength = frames.max { $0.height < $1.height }?.height ?? 0
}
open override func visible(in visibleFrame: CGRect) -> (indexes: [Int], frame: CGRect) {
guard !visibleFrame.isEmptyOrNegative else {
// When this vertical layout gets called in a
// section provider with horizontal layout we need
// to guard here because the optimised index search
// here doesn't take the X axes into account.
return ([], visibleFrame)
}
var index = frames.binarySearch { $0.minY < visibleFrame.minY - maxFrameLength }
var visibleIndexes = [Int]()
while index < frames.count {
let frame = frames[index]
if frame.minY >= visibleFrame.maxY {
break
}
if frame.maxY > visibleFrame.minY {
visibleIndexes.append(index)
}
index += 1
}
return (visibleIndexes, visibleFrame)
}
}
open class HorizontalSimpleLayout: SimpleLayout {
private var maxFrameLength: CGFloat = 0
open override func doneLayout() {
maxFrameLength = frames.max { $0.width < $1.width }?.width ?? 0
}
open override func visible(in visibleFrame: CGRect) -> (indexes: [Int], frame: CGRect) {
guard !visibleFrame.isEmptyOrNegative else {
return ([], visibleFrame)
}
var index = frames.binarySearch { $0.minX < visibleFrame.minX - maxFrameLength }
var visibleIndexes = [Int]()
while index < frames.count {
let frame = frames[index]
if frame.minX >= visibleFrame.maxX {
break
}
if frame.maxX > visibleFrame.minX {
visibleIndexes.append(index)
}
index += 1
}
return (visibleIndexes, visibleFrame)
}
}
extension CGRect {
/// Returns whether a rectangle has zero or less
/// width or height, or is a null rectangle.
var isEmptyOrNegative: Bool {
return isEmpty || size.width < 0 || size.height < 0
}
}