Skip to content

Commit 8a1e838

Browse files
committed
Added missing files
1 parent fd9287f commit 8a1e838

File tree

4 files changed

+106
-0
lines changed

4 files changed

+106
-0
lines changed

Package.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// swift-tools-version:5.3
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "SnappingLayout",
8+
products: [
9+
// Products define the executables and libraries a package produces, and make them visible to other packages.
10+
.library(
11+
name: "SnappingLayout",
12+
targets: ["SnappingLayout"]),
13+
],
14+
dependencies: [
15+
// Dependencies declare other packages that this package depends on.
16+
// .package(url: /* package url */, from: "1.0.0"),
17+
],
18+
targets: [
19+
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
20+
// Targets can depend on other targets in this package, and on products in packages this package depends on.
21+
.target(
22+
name: "SnappingLayout",
23+
dependencies: []),
24+
.testTarget(
25+
name: "SnappingLayoutTests",
26+
dependencies: ["SnappingLayout"]),
27+
]
28+
)

Sources/SnappingLayout/Assets/.gitkeep

Whitespace-only changes.

Sources/SnappingLayout/Classes/.gitkeep

Whitespace-only changes.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//
2+
// HorizontalSnappingLayout.swift
3+
//
4+
5+
/// This works best when setting `collectionView.decelerationRate = .fast`.
6+
public class SnappingLayout: UICollectionViewFlowLayout {
7+
8+
// MARK: - Enums
9+
10+
public enum SnapPositionType: Int {
11+
case left
12+
case center
13+
case right
14+
}
15+
16+
// MARK: - Properties
17+
18+
/// Position to snap the cells.
19+
public var snapPosition = SnapPositionType.center
20+
21+
/// Minimum horizontal velocity to trigger the snap effect.
22+
private let minimumSnapVelocity: CGFloat = 0.3
23+
24+
// MARK: - UICollectionViewFlowLayout
25+
26+
public override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
27+
guard let collectionView = collectionView else {
28+
return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
29+
}
30+
31+
var offsetAdjusment = CGFloat.greatestFiniteMagnitude
32+
let horizontalPosition: CGFloat
33+
34+
switch snapPosition {
35+
case .left:
36+
horizontalPosition = proposedContentOffset.x + collectionView.contentInset.left + sectionInset.left
37+
case .center:
38+
horizontalPosition = proposedContentOffset.x + (collectionView.bounds.width * 0.5)
39+
case .right:
40+
horizontalPosition = proposedContentOffset.x + collectionView.bounds.width - sectionInset.right
41+
}
42+
43+
let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView.bounds.size.width, height: collectionView.bounds.size.height)
44+
let layoutAttributesArray = super.layoutAttributesForElements(in: targetRect)
45+
layoutAttributesArray?.forEach { layoutAttributes in
46+
let itemHorizontalPosition: CGFloat
47+
48+
switch snapPosition {
49+
case .left:
50+
itemHorizontalPosition = layoutAttributes.frame.minX - collectionView.contentInset.left
51+
case .center:
52+
itemHorizontalPosition = layoutAttributes.center.x
53+
case .right:
54+
itemHorizontalPosition = layoutAttributes.frame.maxX + collectionView.contentInset.right
55+
}
56+
57+
if abs(itemHorizontalPosition - horizontalPosition) < abs(offsetAdjusment) {
58+
// If the drag velocity is lower than the minimum velocity (no matter the direction):
59+
// snap the current cell to it's original position.
60+
if abs(velocity.x) < self.minimumSnapVelocity {
61+
offsetAdjusment = itemHorizontalPosition - horizontalPosition
62+
}
63+
// If the velocity is higher than the snap threshold and drag is right->left:
64+
// move to the next cell on the right.
65+
else if velocity.x > 0 {
66+
offsetAdjusment = itemHorizontalPosition - horizontalPosition + (layoutAttributes.bounds.width + self.minimumLineSpacing)
67+
}
68+
// If the velocity is higher than the snap threshold and drag is left->right:
69+
// move to the next cell on the left.
70+
else { // velocity.x < 0
71+
offsetAdjusment = itemHorizontalPosition - horizontalPosition - (layoutAttributes.bounds.width + self.minimumLineSpacing)
72+
}
73+
}
74+
}
75+
76+
return CGPoint(x: proposedContentOffset.x + offsetAdjusment, y: proposedContentOffset.y)
77+
}
78+
}

0 commit comments

Comments
 (0)