-
Notifications
You must be signed in to change notification settings - Fork 3k
/
Copy pathTopTabsLayout.swift
113 lines (93 loc) · 5.75 KB
/
TopTabsLayout.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
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import Foundation
class TopTabsLayoutDelegate: NSObject, UICollectionViewDelegateFlowLayout {
weak var tabSelectionDelegate: TabSelectionDelegate?
let HeaderFooterWidth = TopTabsUX.SeparatorWidth + TopTabsUX.FaderPading
@objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return TopTabsUX.SeparatorWidth
}
@objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: TopTabsUX.TabWidth, height: collectionView.frame.height)
}
@objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return .zero
}
@objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return TopTabsUX.SeparatorWidth
}
@objc func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
tabSelectionDelegate?.didSelectTabAtIndex(indexPath.row)
}
@objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: HeaderFooterWidth, height: 0)
}
@objc func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: HeaderFooterWidth, height: 0)
}
}
class TopTabsViewLayout: UICollectionViewFlowLayout {
var decorationAttributeArr: [Int: UICollectionViewLayoutAttributes?] = [:]
let separatorYOffset = TopTabsUX.SeparatorYOffset
let separatorSize = TopTabsUX.SeparatorHeight
let SeparatorZIndex = -2 ///Prevent the header/footer from appearing above the Tabs
override var collectionViewContentSize: CGSize {
let tabsWidth = ((CGFloat(collectionView!.numberOfItems(inSection: 0))) * (TopTabsUX.TabWidth + TopTabsUX.SeparatorWidth)) - TopTabsUX.SeparatorWidth
return CGSize(width: tabsWidth + (TopTabsUX.TopTabsBackgroundShadowWidth * 2), height: collectionView!.bounds.height)
}
override func prepare() {
super.prepare()
self.minimumLineSpacing = TopTabsUX.SeparatorWidth
scrollDirection = .horizontal
register(TopTabsSeparator.self, forDecorationViewOfKind: TopTabsSeparatorUX.Identifier)
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
decorationAttributeArr = [:]
return true
}
// MARK: layoutAttributesForElementsInRect
override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard indexPath.row < self.collectionView!.numberOfItems(inSection: 0) else {
let separatorAttr = UICollectionViewLayoutAttributes(forDecorationViewOfKind: TopTabsSeparatorUX.Identifier, with: indexPath)
separatorAttr.frame = .zero
separatorAttr.zIndex = SeparatorZIndex
return separatorAttr
}
if let attr = self.decorationAttributeArr[indexPath.item] {
return attr
} else {
// Compute the separator if it does not exist in the cache
let separatorAttr = UICollectionViewLayoutAttributes(forDecorationViewOfKind: TopTabsSeparatorUX.Identifier, with: indexPath)
let x = TopTabsUX.TopTabsBackgroundShadowWidth + ((CGFloat(indexPath.row) * (TopTabsUX.TabWidth + TopTabsUX.SeparatorWidth)) - TopTabsUX.SeparatorWidth)
separatorAttr.frame = CGRect(x: x, y: separatorYOffset, width: TopTabsUX.SeparatorWidth, height: separatorSize)
separatorAttr.zIndex = SeparatorZIndex
return separatorAttr
}
}
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = super.layoutAttributesForSupplementaryView(ofKind: elementKind, at: indexPath)
attributes?.zIndex = SeparatorZIndex
return attributes
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributes = super.layoutAttributesForElements(in: rect)!
// Create attributes for the Tab Separator.
for i in attributes {
guard i.representedElementKind != UICollectionElementKindSectionHeader && i.representedElementKind != UICollectionElementKindSectionFooter else {
i.zIndex = SeparatorZIndex
continue
}
let sep = UICollectionViewLayoutAttributes(forDecorationViewOfKind: TopTabsSeparatorUX.Identifier, with: i.indexPath)
sep.frame = CGRect(x: i.frame.origin.x - TopTabsUX.SeparatorWidth, y: separatorYOffset, width: TopTabsUX.SeparatorWidth, height: separatorSize)
sep.zIndex = SeparatorZIndex
i.zIndex = 10
// Only add the seperator if it will be shown.
if i.indexPath.row != 0 && i.indexPath.row < self.collectionView!.numberOfItems(inSection: 0) {
attributes.append(sep)
decorationAttributeArr[i.indexPath.item] = sep
}
}
return attributes
}
}