-
Notifications
You must be signed in to change notification settings - Fork 3
/
ScrollPageController.swift
52 lines (46 loc) 路 1.96 KB
/
ScrollPageController.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
import CoreGraphics
struct ScrollPageController {
/// Computes page offset from page offsets array for given scroll offset and velocity
///
/// - Parameters:
/// - offset: current scroll offset
/// - velocity: current scroll velocity
/// - pageOffsets: page offsets array
/// - Returns: target page offset from array or nil if no page offets provided
func pageOffset(for offset: CGFloat, velocity: CGFloat, in pageOffsets: [CGFloat]) -> CGFloat? {
let pages = pageOffsets.enumerated().reduce([Int: CGFloat]()) {
var dict = $0
dict[$1.0] = $1.1
return dict
}
guard let page = pages.min(by: { abs($0.1 - offset) < abs($1.1 - offset) }) else {
return nil
}
if abs(velocity) < 0.2 {
return page.value
}
if velocity < 0 {
return pages[pageOffsets.index(before: page.key)] ?? page.value
}
return pages[pageOffsets.index(after: page.key)] ?? page.value
}
/// Cumputes page fraction from page offsets array for given scroll offset
///
/// - Parameters:
/// - offset: current scroll offset
/// - pageOffsets: page offsets array
/// - Returns: current page fraction in range from 0 to number of pages or nil if no page offets provided
func pageFraction(for offset: CGFloat, in pageOffsets: [CGFloat]) -> CGFloat? {
let pages = pageOffsets.sorted().enumerated()
if let index = pages.first(where: { $0.1 == offset })?.0 {
return CGFloat(index)
}
guard let nextOffset = pages.first(where: { $0.1 >= offset })?.1 else {
return pages.map { $0.0 }.last.map { CGFloat($0) }
}
guard let (prevIdx, prevOffset) = pages.reversed().first(where: { $0.1 <= offset }) else {
return pages.map { $0.0 }.first.map { CGFloat($0) }
}
return CGFloat(prevIdx) + (offset - prevOffset) / (nextOffset - prevOffset)
}
}