-
Notifications
You must be signed in to change notification settings - Fork 0
/
UIScrollView+Extensions.swift
154 lines (133 loc) · 5.75 KB
/
UIScrollView+Extensions.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//
// UIScrollView+Extensions.swift
// OYExtensions
//
// Created by osmanyildirim
//
import UIKit
extension UIScrollView {
/// Get and Set contentSize width of UIScrollView
public var oy_contentSizeWidth: CGFloat {
get { contentSize.width }
set(value) { contentSize = .oy_init(value, contentSize.height) }
}
/// Get and Set contentSize height of UIScrollView
public var oy_contentSizeHeight: CGFloat {
get { contentSize.height }
set(value) { contentSize = .oy_init(contentSize.width, value) }
}
/// Get and Set contentOffset of UIScrollView
public var oy_contentOffset: CGPoint {
get { contentOffset }
set(value) { contentOffset = value }
}
/// Get and Set contentOffset X coordinate of UIScrollView
public var oy_contentOffsetX: CGFloat {
get { contentOffset.x }
set(value) { setContentOffset(.oy_init(value, oy_contentOffsetY), animated: true) }
}
/// Get and Set contentOffset Y coordinate of UIScrollView
public var oy_contentOffsetY: CGFloat {
get { contentOffset.y }
set(value) { setContentOffset(.oy_init(oy_contentOffsetX, value), animated: true) }
}
/// Get and Set contentInset of UIScrollView
public var oy_contentInset: UIEdgeInsets {
get { contentInset }
set(value) { contentInset = value }
}
/// Get and Set contentInset Top of UIScrollView
public var oy_contentInsetTop: CGFloat {
get { contentInset.top }
set(value) {
contentInset = .oy_init(value, oy_contentInsetLeft, oy_contentInsetBottom, oy_contentInsetRight) }
}
/// Get and Set contentInset Bottom of UIScrollView
public var oy_contentInsetBottom: CGFloat {
get { contentInset.bottom }
set(value) { contentInset = .oy_init(oy_contentInsetTop, oy_contentInsetLeft, value, oy_contentInsetRight) }
}
/// Get and Set contentInset Left of UIScrollView
public var oy_contentInsetLeft: CGFloat {
get { contentInset.left }
set(value) { contentInset = .oy_init(oy_contentInsetTop, value, oy_contentInsetBottom, oy_contentInsetRight) }
}
/// Get and Set contentInset Right of UIScrollView
public var oy_contentInsetRight: CGFloat {
get { contentInset.right }
set(value) { contentInset = .oy_init(oy_contentInsetTop, oy_contentInsetLeft, oy_contentInsetBottom, value) }
}
/// Set UIScrollView contentOffset
/// - Parameters:
/// - x: contentOffset X coordinate
/// - y: contentOffset Y coordinate
/// - duration: animation duration
/// - options: animation options
public func oy_contentOffsetAnimate(x: CGFloat? = nil, y: CGFloat? = nil, duration: TimeInterval = 0.5, options: UIView.AnimationOptions = .curveEaseOut) {
let xOffset = x ?? oy_contentOffsetX
let yOffset = y ?? oy_contentOffsetY
DispatchQueue.main.async {
UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
self.oy_contentOffset = .oy_init(xOffset, yOffset)
}, completion: nil)
}
}
/// Scroll to the most content offset by position
/// - Parameters:
/// - position: scroll position: top, bottom etc.
/// - animated: if the should be animated (default is true)
public func oy_scrollTo(position: Position, animated: Bool = true) {
var point = CGPoint()
switch position {
case .top: point = .oy_init(contentOffset.x, -contentInset.top)
case .bottom: point = .oy_init(contentOffset.x, max(0, contentSize.height - bounds.height) + contentInset.bottom)
case .left: point = .oy_init(-contentInset.left, contentOffset.y)
case .right: point = .oy_init(max(0, contentSize.width - bounds.width) + contentInset.right, contentOffset.y)
}
setContentOffset(point, animated: animated)
}
/// Observe UIScrollView's contentOffset changes
/// - Parameter completion: completion handler with CGPoint
public func oy_observeContentOffset(completion: ((CGPoint?) -> Void)?) {
_ = observe(\.contentOffset, options: .new) { _, value in
completion?(value.newValue)
}
}
/// Observe UIScrollView's contentSize changes
/// - Parameter completion: completion handler with CGSize
public func oy_observeContentSize(closure: ((CGSize?) -> Void)?) {
_ = observe(\.contentSize, options: .new) { _, value in
closure?(value.newValue)
}
}
/// Snapshot of type optional UIImage
public override var oy_snapshot: UIImage? {
UIGraphicsBeginImageContextWithOptions(contentSize, false, 0)
defer {
UIGraphicsEndImageContext()
}
guard let context = UIGraphicsGetCurrentContext() else { return nil }
let previousFrame = frame
frame = CGRect(origin: frame.origin, size: contentSize)
layer.render(in: context)
frame = previousFrame
return UIGraphicsGetImageFromCurrentImageContext()
}
/// Hide keyboard when scrolling
/// - Parameter when: KeyboardDismissMode
/// • onDrag: dismisses the keyboard when a drag begins
/// • interactive: the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
/// • onDragWithAccessory: dismisses both keyboard and accessory in the style of UIScrollViewKeyboardDismissModeOnDrag
/// • interactiveWithAccessory: dismisses both keyboard and accessory in the style of UIScrollViewKeyboardDismissModeInteractive
public func oy_keyboardDismiss(when: KeyboardDismissMode) {
keyboardDismissMode = when
}
}
extension UIScrollView {
public enum Position {
case top
case bottom
case left
case right
}
}