/
OverlapCollectionViewLayout.swift
138 lines (117 loc) · 4.95 KB
/
OverlapCollectionViewLayout.swift
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//
// OverlapCollectionViewLayout.swift
// CollectionViewCustomInsertion
//
// Created by Mark DiFranco on 2016-04-03.
// Copyright © 2016 mdfprojects. All rights reserved.
//
import UIKit
class OverlapCollectionViewLayout: UICollectionViewLayout {
var preferredSize = CGSizeMake(200, 200)
private let centerDiff: CGFloat = 40
private var numberOfItems = 0
private var updateItems = [UICollectionViewUpdateItem]()
override func prepareLayout() {
super.prepareLayout()
numberOfItems = collectionView?.numberOfItemsInSection(0) ?? 0
}
override func prepareForCollectionViewUpdates(updateItems: [UICollectionViewUpdateItem]) {
super.prepareForCollectionViewUpdates(updateItems)
self.updateItems = updateItems
}
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
override func collectionViewContentSize() -> CGSize {
if let collectionView = collectionView {
let width = max(collectionView.bounds.width + 1, preferredSize.width + CGFloat((numberOfItems - 1)) * centerDiff)
let height = collectionView.bounds.height - 1
return CGSizeMake(width, height)
}
return CGSizeZero
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var allAttributes = [UICollectionViewLayoutAttributes]()
for index in 0 ..< numberOfItems {
let indexPath = NSIndexPath(forItem: index, inSection: 0)
allAttributes.append(layoutAttributesForItemAtIndexPath(indexPath)!)
}
return allAttributes
}
override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
attributes.size = preferredSize
let centerX = preferredSize.width / 2.0 + CGFloat(indexPath.item) * centerDiff
let centerY = collectionView!.bounds.height / 2.0
attributes.center = CGPointMake(centerX, centerY)
attributes.zIndex = indexPath.item
return attributes
}
override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = layoutAttributesForItemAtIndexPath(itemIndexPath)
for updateItem in updateItems {
switch updateItem.updateAction {
case .Insert:
if updateItem.indexPathAfterUpdate == itemIndexPath {
let translation = collectionView!.bounds.height
attributes?.transform = CGAffineTransformMakeTranslation(0, translation)
break
}
default:
break
}
}
return attributes
}
override func finalLayoutAttributesForDisappearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
for updateItem in updateItems {
switch updateItem.updateAction {
case .Delete:
if updateItem.indexPathBeforeUpdate == itemIndexPath {
let attributes = layoutAttributesForItemAtIndexPath(itemIndexPath)
let translation = collectionView!.bounds.height
attributes?.transform = CGAffineTransformMakeTranslation(0, translation)
return attributes
}
case .Move:
if updateItem.indexPathBeforeUpdate == itemIndexPath {
return layoutAttributesForItemAtIndexPath(updateItem.indexPathAfterUpdate!)
}
default:
break
}
}
let finalIndex = finalIndexForIndexPath(itemIndexPath)
let shiftedIndexPath = NSIndexPath(forItem: finalIndex, inSection: itemIndexPath.section)
return layoutAttributesForItemAtIndexPath(shiftedIndexPath)
}
override func finalizeCollectionViewUpdates() {
super.finalizeCollectionViewUpdates()
updateItems.removeAll(keepCapacity: true)
}
private func finalIndexForIndexPath(indexPath: NSIndexPath) -> Int {
var newIndex = indexPath.item
for updateItem in updateItems {
switch updateItem.updateAction {
case .Insert:
if updateItem.indexPathAfterUpdate!.item <= newIndex {
newIndex += 1
}
case .Delete:
if updateItem.indexPathBeforeUpdate!.item < newIndex {
newIndex -= 1
}
case .Move:
if updateItem.indexPathBeforeUpdate!.item < newIndex {
newIndex -= 1
}
if updateItem.indexPathAfterUpdate!.item <= newIndex {
newIndex += 1
}
default:
break
}
}
return newIndex
}
}