-
Notifications
You must be signed in to change notification settings - Fork 337
/
PaperOnboarding.swift
231 lines (179 loc) · 7.22 KB
/
PaperOnboarding.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
//
// PaperOnboarding.swift
// AnimatedPageView
//
// Created by Alex K. on 20/04/16.
// Copyright © 2016 Alex K. All rights reserved.
//
import UIKit
public typealias OnboardingItemInfo = (imageName: String, title: String, description: String, iconName: String, color: UIColor, titleColor: UIColor, descriptionColor: UIColor, titleFont: UIFont, descriptionFont: UIFont)
/**
* The PaperOnboardingDataSource protocol is adopted by an object that mediates the application’s data model for a PaperOnboarding object.
The data source information it needs to construct and modify a PaperOnboarding.
*/
public protocol PaperOnboardingDataSource {
/**
Asks the data source to return the number of items.
- parameter index: An index of item in PaperOnboarding.
- returns: The number of items in PaperOnboarding.
*/
func onboardingItemsCount() -> Int
/**
Asks the data source for configureation item.
- parameter index: An index of item in PaperOnboarding.
- returns: configuration info for item
*/
func onboardingItemAtIndex(index: Int) -> OnboardingItemInfo
}
/**
* The delegate of a PaperOnboarding object must adopt the PaperOnboardingDelegate protocol. Optional methods of the
protocol allow the delegate to manage items, configure items, and perform other actions.
*/
public protocol PaperOnboardingDelegate {
/**
Tells the delegate that the paperOnbording start scrolling.
- parameter index: An curretn index item
*/
func onboardingWillTransitonToIndex(index: Int)
/**
Tells the delegate that the specified item is now selected
- parameter index: An curretn index item
*/
func onboardingDidTransitonToIndex(index: Int)
/**
Tells the delegate the PaperOnboarding is about to draw a item for a particular row. Use this method for configure items
- parameter item: A OnboardingContentViewItem object that PaperOnboarding is going to use when drawing the row.
- parameter index: An curretn index item
*/
func onboardingConfigurationItem(item: OnboardingContentViewItem, index: Int)
}
///An instance of PaperOnboarding which display collection of information.
public class PaperOnboarding: UIView {
/// The object that acts as the data source of the PaperOnboardingDataSource.
@IBOutlet public var dataSource: AnyObject? {
didSet {
commonInit()
}
}
/// The object that acts as the delegate of the PaperOnboarding. PaperOnboardingDelegate protocol
@IBOutlet public var delegate: AnyObject?
/// current index item
public private(set) var currentIndex: Int = 0
var itemsCount: Int = 3
private var itemsInfo: [OnboardingItemInfo]?
private var pageViewBottomConstant: CGFloat = 32
private var pageViewSelectedRadius: CGFloat = 22
private var pageViewRadius: CGFloat = 8
private var fillAnimationView: FillAnimationView?
private var pageView: PageView?
private var gestureControl: GestureControl?
private var contentView: OnboardingContentView?
/**
Initializes and returns a PaperOnboarding object with items count.
- parameter itemsCount: The number of items in PaperOnboarding.
- returns: Returns an initialized PaperOnboading object
*/
public init(itemsCount: Int = 3) {
super.init(frame: CGRect.zero)
self.itemsCount = itemsCount
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
// MARK: methods
public extension PaperOnboarding {
/**
Scrolls through the PaperOnboarding until a index is at a particular location on the screen.
- parameter index: Scrolling to a curretn index item.
- parameter animated: True if you want to animate the change in position; false if it should be immediate.
*/
func currentIndex(index: Int, animated: Bool) {
if 0 ..< itemsCount ~= index {
(self.delegate as? PaperOnboardingDelegate)?.onboardingWillTransitonToIndex(index)
currentIndex = index
CATransaction.begin()
CATransaction.setCompletionBlock({
(self.delegate as? PaperOnboardingDelegate)?.onboardingDidTransitonToIndex(index)
})
if let postion = pageView?.positionItemIndex(index, onView: self) {
fillAnimationView?.fillAnimation(bakcgroundColor(currentIndex), centerPosition: postion, duration: 0.5)
}
pageView?.currentIndex(index, animated: animated)
contentView?.currentItem(index, animated: animated)
CATransaction.commit()
}
}
}
// MARK: create
extension PaperOnboarding {
private func commonInit() {
if case let dataSource as PaperOnboardingDataSource = self.dataSource {
itemsCount = dataSource.onboardingItemsCount()
}
itemsInfo = createItemsInfo()
translatesAutoresizingMaskIntoConstraints = false
fillAnimationView = FillAnimationView.animavtionViewOnView(self, color: bakcgroundColor(currentIndex))
contentView = OnboardingContentView.contentViewOnView(self,
delegate: self,
itemsCount: itemsCount,
bottomConstant: pageViewBottomConstant * -1 - pageViewSelectedRadius)
pageView = createPageView()
gestureControl = GestureControl(view: self, delegate: self)
}
private func createPageView() -> PageView {
let pageView = PageView.pageViewOnView(self,
itemsCount: itemsCount,
bottomConstant: pageViewBottomConstant * -1,
radius:pageViewRadius,
selectedRadius: pageViewSelectedRadius)
pageView.configuration = { item, index in
if let iconName = self.itemsInfo?[index].iconName {
item.imageView?.image = UIImage(named: iconName)
}
}
return pageView
}
private func createItemsInfo() -> [OnboardingItemInfo] {
guard case let dataSource as PaperOnboardingDataSource = self.dataSource else {
fatalError("set dataSource")
}
var items = [OnboardingItemInfo]()
for index in 0..<itemsCount {
let info = dataSource.onboardingItemAtIndex(index)
items.append(info)
}
return items
}
}
// MARK: helpers
extension PaperOnboarding {
private func bakcgroundColor(index: Int) -> UIColor {
guard let color = itemsInfo?[index].color else {
return .blackColor()
}
return color
}
}
// MARK: GestureControlDelegate
extension PaperOnboarding: GestureControlDelegate {
func gestureControlDidSwipe(direction: UISwipeGestureRecognizerDirection) {
switch direction {
case UISwipeGestureRecognizerDirection.Right:
currentIndex(currentIndex - 1, animated: true)
case UISwipeGestureRecognizerDirection.Left:
currentIndex(currentIndex + 1, animated: true)
default:
fatalError()
}
}
}
// MARK: OnboardingDelegate
extension PaperOnboarding: OnboardingContentViewDelegate {
func onboardingItemAtIndex(index: Int) -> OnboardingItemInfo? {
return itemsInfo?[index]
}
func onboardingConfigurationItem(item: OnboardingContentViewItem, index: Int) {
delegate?.onboardingConfigurationItem(item, index: index)
}
}