Skip to content

Commit 102879a

Browse files
authored
Merge pull request #26 from yacir/refactor_mask
Refactor mask calculation
2 parents 1b8fd39 + 0141826 commit 102879a

12 files changed

Lines changed: 509 additions & 56 deletions

CollectionViewSlantedLayout.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
FB132C641C910F5900728981 /* CollectionViewSlantedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB132C611C910F5900728981 /* CollectionViewSlantedCell.swift */; };
1414
FB132C651C910F5900728981 /* CollectionViewSlantedLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB132C621C910F5900728981 /* CollectionViewSlantedLayout.swift */; };
1515
FB132C661C910F5900728981 /* CollectionViewSlantedLayoutAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB132C631C910F5900728981 /* CollectionViewSlantedLayoutAttributes.swift */; };
16+
FB3A7BE1215F591500B18AE8 /* CollectionViewSlantedMasks.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB3A7BE0215F591500B18AE8 /* CollectionViewSlantedMasks.swift */; };
17+
FB3A7BE3215F592400B18AE8 /* CAShapeLayer+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB3A7BE2215F592400B18AE8 /* CAShapeLayer+Helpers.swift */; };
18+
FB3A7BE8215F76EF00B18AE8 /* CollectionViewSlantedMasksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB3A7BE4215F727300B18AE8 /* CollectionViewSlantedMasksTests.swift */; };
1619
FB40E22C1CA3530400B37E7C /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB40E22A1CA352FD00B37E7C /* CollectionViewController.swift */; };
1720
FB6A0BF71FEC838F0078E2DD /* UICollectionView+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB6A0BF61FEC838F0078E2DD /* UICollectionView+Helpers.swift */; };
1821
FB6A0BFA1FEC8D260078E2DD /* UICollectionViewLayout+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB6A0BF91FEC8D260078E2DD /* UICollectionViewLayout+Helpers.swift */; };
@@ -40,6 +43,9 @@
4043
FB132C611C910F5900728981 /* CollectionViewSlantedCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewSlantedCell.swift; sourceTree = "<group>"; };
4144
FB132C621C910F5900728981 /* CollectionViewSlantedLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewSlantedLayout.swift; sourceTree = "<group>"; };
4245
FB132C631C910F5900728981 /* CollectionViewSlantedLayoutAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewSlantedLayoutAttributes.swift; sourceTree = "<group>"; };
46+
FB3A7BE0215F591500B18AE8 /* CollectionViewSlantedMasks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewSlantedMasks.swift; sourceTree = "<group>"; };
47+
FB3A7BE2215F592400B18AE8 /* CAShapeLayer+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CAShapeLayer+Helpers.swift"; sourceTree = "<group>"; };
48+
FB3A7BE4215F727300B18AE8 /* CollectionViewSlantedMasksTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewSlantedMasksTests.swift; sourceTree = "<group>"; };
4349
FB40E22A1CA352FD00B37E7C /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = "<group>"; };
4450
FB6A0BF61FEC838F0078E2DD /* UICollectionView+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Helpers.swift"; sourceTree = "<group>"; };
4551
FB6A0BF91FEC8D260078E2DD /* UICollectionViewLayout+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionViewLayout+Helpers.swift"; sourceTree = "<group>"; };
@@ -102,6 +108,7 @@
102108
isa = PBXGroup;
103109
children = (
104110
FB132C591C910C0300728981 /* CollectionViewSlantedLayoutTests.swift */,
111+
FB3A7BE4215F727300B18AE8 /* CollectionViewSlantedMasksTests.swift */,
105112
FB40E22A1CA352FD00B37E7C /* CollectionViewController.swift */,
106113
FB132C691C910F8200728981 /* Supporting Files */,
107114
);
@@ -128,6 +135,7 @@
128135
FB6A0BF51FEC83380078E2DD /* Internal */ = {
129136
isa = PBXGroup;
130137
children = (
138+
FB3A7BE0215F591500B18AE8 /* CollectionViewSlantedMasks.swift */,
131139
FB132C631C910F5900728981 /* CollectionViewSlantedLayoutAttributes.swift */,
132140
);
133141
path = Internal;
@@ -136,6 +144,7 @@
136144
FB6A0BF81FEC83950078E2DD /* Extensions */ = {
137145
isa = PBXGroup;
138146
children = (
147+
FB3A7BE2215F592400B18AE8 /* CAShapeLayer+Helpers.swift */,
139148
FB6A0BF61FEC838F0078E2DD /* UICollectionView+Helpers.swift */,
140149
FB6A0BF91FEC8D260078E2DD /* UICollectionViewLayout+Helpers.swift */,
141150
);
@@ -270,8 +279,10 @@
270279
isa = PBXSourcesBuildPhase;
271280
buildActionMask = 2147483647;
272281
files = (
282+
FB3A7BE1215F591500B18AE8 /* CollectionViewSlantedMasks.swift in Sources */,
273283
FB6A0BF71FEC838F0078E2DD /* UICollectionView+Helpers.swift in Sources */,
274284
FBBBC5E71FF79E1000A2AC04 /* CollectionViewDelegateSlantedLayout.swift in Sources */,
285+
FB3A7BE3215F592400B18AE8 /* CAShapeLayer+Helpers.swift in Sources */,
275286
FB6A0BFA1FEC8D260078E2DD /* UICollectionViewLayout+Helpers.swift in Sources */,
276287
FB132C641C910F5900728981 /* CollectionViewSlantedCell.swift in Sources */,
277288
FB132C651C910F5900728981 /* CollectionViewSlantedLayout.swift in Sources */,
@@ -285,6 +296,7 @@
285296
buildActionMask = 2147483647;
286297
files = (
287298
FB40E22C1CA3530400B37E7C /* CollectionViewController.swift in Sources */,
299+
FB3A7BE8215F76EF00B18AE8 /* CollectionViewSlantedMasksTests.swift in Sources */,
288300
FB132C5F1C910E4300728981 /* CollectionViewSlantedLayoutTests.swift in Sources */,
289301
);
290302
runOnlyForDeploymentPostprocessing = 0;

Sources/CollectionViewSlantedCell.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,5 @@ import UIKit
5454
slantedLayerMask = layoutAttributes.slantedLayerMask
5555
layer.mask = layoutAttributes.slantedLayerMask
5656
}
57+
5758
}

Sources/CollectionViewSlantedLayout+Constants.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@ import Foundation
5555
internal var isAscending: Bool {
5656
return self == .ascending
5757
}
58+
5859
}

Sources/CollectionViewSlantedLayout.swift

Lines changed: 38 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -146,67 +146,46 @@ import UIKit
146146
internal var cachedContentSize: CGFloat = 0
147147

148148
/// :nodoc:
149-
fileprivate func itemSize(forItemAt indexPath: IndexPath) -> CGFloat {
149+
fileprivate func itemSize(forItemAt indexPath: IndexPath) -> (value: CGFloat, isDynamic: Bool) {
150150
guard let collectionView = collectionView,
151151
let delegate = collectionView.delegate as? CollectionViewDelegateSlantedLayout else {
152-
return max(itemSize, 0)
152+
return (max(itemSize, 0), false)
153153
}
154154

155155
let size = delegate.collectionView?(collectionView, layout: self, sizeForItemAt: indexPath)
156-
return max(size ?? itemSize, 0)
156+
return (max(size ?? itemSize, 0), size != nil)
157157
}
158158

159159
/// :nodoc:
160-
fileprivate func maskForItemAtIndexPath(_ indexPath: IndexPath) -> CAShapeLayer {
161-
let size = itemSize(forItemAt: indexPath)
160+
fileprivate func maskForItemAtIndexPath(_ indexPath: IndexPath,
161+
size: CGFloat,
162+
isDynamicSize: Bool,
163+
staticMasks: CollectionViewSlantedMasks) -> CAShapeLayer {
162164

163-
let isFirstCellExcluded = indexPath.row == 0 && self.isFirstCellExcluded
164-
let isLastCellExcluded = indexPath.row == numberOfItems - 1 && self.isLastCellExcluded
165+
let masks = isDynamicSize ? calculatedMasks(itemSize: size) : CollectionViewSlantedMasks(masks: staticMasks)
165166

166-
let firstControlPoint = isFirstCellExcluded ? 0 : CGFloat(slantingSize)
167-
let secondControlPoint = isLastCellExcluded ? size : size - CGFloat(slantingSize)
168-
169-
var pathPoints = [CGPoint]()
170-
171-
if scrollDirection.isVertical {
172-
switch self.slantingDirection {
173-
case .downward:
174-
pathPoints = [CGPoint(x: 0, y: 0),
175-
CGPoint(x: width, y: firstControlPoint),
176-
CGPoint(x: width, y: size),
177-
CGPoint(x: 0, y: secondControlPoint)]
178-
default:
179-
pathPoints = [CGPoint(x: 0, y: firstControlPoint),
180-
CGPoint(x: width, y: 0),
181-
CGPoint(x: width, y: secondControlPoint),
182-
CGPoint(x: 0, y: size)]
183-
}
184-
} else {
185-
switch self.slantingDirection {
186-
case .upward:
187-
pathPoints = [CGPoint(x: firstControlPoint, y: 0),
188-
CGPoint(x: size, y: 0),
189-
CGPoint(x: secondControlPoint, y: height),
190-
CGPoint(x: 0, y: height)]
191-
default:
192-
pathPoints = [CGPoint(x: 0, y: 0),
193-
CGPoint(x: secondControlPoint, y: 0),
194-
CGPoint(x: size, y: height),
195-
CGPoint(x: firstControlPoint, y: height)]
196-
}
167+
// isFirstCell && isFirstCellExcluded
168+
if indexPath.row == 0 && isFirstCellExcluded {
169+
return masks.startingMask
197170
}
198171

199-
let bezierPath = UIBezierPath()
200-
bezierPath.move(to: pathPoints[0])
201-
bezierPath.addLine(to: pathPoints[1])
202-
bezierPath.addLine(to: pathPoints[2])
203-
bezierPath.addLine(to: pathPoints[3])
204-
bezierPath.close()
172+
// isLastCell && isLastCellExcluded
173+
if (indexPath.row == numberOfItems - 1) && isLastCellExcluded {
174+
return masks.endingMask
175+
}
205176

206-
let slantedLayerMask = CAShapeLayer()
207-
slantedLayerMask.path = bezierPath.cgPath
177+
return masks.defaultMask
178+
}
208179

209-
return slantedLayerMask
180+
/// :nodoc:
181+
fileprivate func calculatedMasks(itemSize: CGFloat) -> CollectionViewSlantedMasks {
182+
let size = CGSize(width: scrollDirection.isVertical ? width : itemSize,
183+
height: scrollDirection.isVertical ? itemSize : height)
184+
185+
return CollectionViewSlantedMasks(size: size,
186+
slantingSize: CGFloat(slantingSize),
187+
scrollDirection: scrollDirection,
188+
slantingDirection: slantingDirection)
210189
}
211190

212191
/// :nodoc:
@@ -227,6 +206,7 @@ import UIKit
227206
/// :nodoc:
228207
fileprivate func invalidate() {
229208
invalidateCache()
209+
updateRotationAngle()
230210
invalidateLayout()
231211
}
232212

@@ -261,32 +241,34 @@ extension CollectionViewSlantedLayout {
261241
return
262242
}
263243

264-
updateRotationAngle()
244+
let staticMasks = calculatedMasks(itemSize: max(itemSize, 0))
265245

266246
var position: CGFloat = 0
267247

268248
for item in 0..<numberOfItems {
269249
let indexPath = IndexPath(item: item, section: 0)
270250
let attributes = CollectionViewSlantedLayoutAttributes(forCellWith: indexPath)
271251
let size = itemSize(forItemAt: indexPath)
272-
let frame: CGRect
273252

253+
let frame: CGRect
274254
if scrollDirection.isVertical {
275-
frame = CGRect(x: 0, y: position, width: width, height: size)
255+
frame = CGRect(x: 0, y: position, width: width, height: size.value)
276256
} else {
277-
frame = CGRect(x: position, y: 0, width: size, height: height)
257+
frame = CGRect(x: position, y: 0, width: size.value, height: height)
278258
}
279259

280260
attributes.frame = frame
281261
attributes.size = frame.size
282-
283262
attributes.zIndex = zIndexOrder.isAscending ? item : (numberOfItems - item)
263+
attributes.slantedLayerMask = maskForItemAtIndexPath(indexPath,
264+
size: size.value,
265+
isDynamicSize: size.isDynamic,
266+
staticMasks: staticMasks)
284267

285-
attributes.slantedLayerMask = self.maskForItemAtIndexPath(indexPath)
286268
cachedAttributes.append(attributes)
287-
cachedContentSize += size
269+
cachedContentSize += size.value
288270

289-
position += size + lineSpacing - CGFloat(slantingSize)
271+
position += size.value + lineSpacing - CGFloat(slantingSize)
290272
}
291273
}
292274

@@ -301,4 +283,5 @@ extension CollectionViewSlantedLayout {
301283
override open func layoutAttributesForItem(at indexPath: IndexPath) -> CollectionViewSlantedLayoutAttributes? {
302284
return cachedAttributes[indexPath.item]
303285
}
286+
304287
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
This file is part of the CollectionViewSlantedLayout package.
3+
4+
Copyright © 2017 Yassir Barchi <github@yassir.fr>
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
*/
24+
25+
import QuartzCore
26+
27+
/// :nodoc:
28+
extension CAShapeLayer {
29+
30+
/// :nodoc:
31+
convenience init(path cgpath: CGPath?) {
32+
self.init()
33+
path = cgpath
34+
}
35+
36+
/// :nodoc:
37+
convenience init(pathPoints: [CGPoint]) {
38+
self.init()
39+
guard pathPoints.count > 2 else { return }
40+
41+
let bezierPath = UIBezierPath()
42+
bezierPath.move(to: pathPoints[0])
43+
44+
for idx in 1..<pathPoints.count {
45+
bezierPath.addLine(to: pathPoints[idx])
46+
}
47+
48+
bezierPath.close()
49+
50+
path = bezierPath.cgPath
51+
}
52+
53+
}

Sources/Extensions/UICollectionView+Helpers.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ extension UICollectionView.ScrollDirection {
2929
var isVertical: Bool {
3030
return self == .vertical
3131
}
32+
3233
}

Sources/Extensions/UICollectionViewLayout+Helpers.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ extension UICollectionViewLayout {
4444

4545
return collectionView.frame.height - collectionView.contentInset.top - collectionView.contentInset.bottom
4646
}
47+
4748
}

Sources/Internal/CollectionViewSlantedLayoutAttributes.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,5 @@ open class CollectionViewSlantedLayoutAttributes: UICollectionViewLayoutAttribut
5252

5353
return false
5454
}
55+
5556
}

0 commit comments

Comments
 (0)