Skip to content

Commit 8786ec0

Browse files
committed
Fix changing state from outside
1 parent d214d37 commit 8786ec0

File tree

5 files changed

+91
-75
lines changed

5 files changed

+91
-75
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,5 @@ iOSInjectionProject/
116116

117117
# End of https://www.gitignore.io/api/xcode,swift,carthage,cocoapods
118118

119+
Podfile.lock
120+
contents.xcworkspacedata

ConcentricOnboarding.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Pod::Spec.new do |s|
1010
s.name = "ConcentricOnboarding"
11-
s.version = "0.0.1"
11+
s.version = "0.0.2"
1212
s.summary = "SwiftUI library for a walkthrough or onboarding flow with tap actions"
1313

1414
s.homepage = 'https://github.com/exyte/ConcentricOnboarding.git'

Example/ConcentricOnboardingExample.xcworkspace/contents.xcworkspacedata

-10
This file was deleted.

Example/Podfile.lock

-16
This file was deleted.

Source/ConcentricOnboardingView.swift

+88-48
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,41 @@
88

99
import SwiftUI
1010

11+
class ObservableBool: ObservableObject {
12+
@Published var value: Bool {
13+
didSet {
14+
didSet?()
15+
}
16+
}
17+
18+
var didSet: (()->())?
19+
20+
init(_ value: Bool = false) {
21+
self.value = value
22+
}
23+
}
24+
25+
class ObservableInt: ObservableObject {
26+
@Published var value: Int {
27+
didSet {
28+
didSet?()
29+
}
30+
}
31+
32+
var didSet: (()->())?
33+
34+
init(_ value: Int = 0) {
35+
self.value = value
36+
}
37+
}
38+
1139
public struct ConcentricOnboardingView : View {
1240
public var animationWillBegin = {}
1341
public var animationDidEnd = {}
1442
public var didGoToLastPage = {}
43+
public var didPressNextButton: (()->())? // replaces default button action with user's custom closure
1544
public var currentPageIndex: Int {
16-
return currentIndex
45+
return currentIndex.value
1746
}
1847

1948
let radius: Double = 30
@@ -29,20 +58,12 @@ public struct ConcentricOnboardingView : View {
2958
let bgColors: [Color]
3059
let duration: Double // in seconds
3160

32-
@State var currentIndex = 0
33-
@State var nextIndex = 1
61+
@ObservedObject var currentIndex = ObservableInt()
62+
@ObservedObject var nextIndex = ObservableInt(1)
63+
@ObservedObject var isAnimating = ObservableBool()
64+
@ObservedObject var isAnimatingForward = ObservableBool(true)
3465

3566
@State var progress: Double = 0
36-
@State var isAnimating = false {
37-
didSet {
38-
if isAnimating && (pages.count < 2 || bgColors.count < 2) {
39-
isAnimating = false
40-
return
41-
}
42-
isAnimating ? animationWillBegin() : animationDidEnd()
43-
}
44-
}
45-
@State var isAnimatingForward = true
4667
@State var bgColor = Color.white
4768
@State var circleColor = Color.white
4869

@@ -65,27 +86,46 @@ public struct ConcentricOnboardingView : View {
6586
print("Add more bg colors")
6687
}
6788

68-
if bgColors.count > currentIndex {
69-
bgColor = bgColors[currentIndex]
89+
if bgColors.count > currentIndex.value {
90+
bgColor = bgColors[currentIndex.value]
7091
}
71-
if bgColors.count > nextIndex {
72-
circleColor = bgColors[nextIndex]
92+
if bgColors.count > nextIndex.value {
93+
circleColor = bgColors[nextIndex.value]
7394
}
7495
let width = CGFloat(radius * 2)
7596
shape = AnyView(Circle().foregroundColor(circleColor).frame(width: width, height: width, alignment: .center))
97+
98+
isAnimating.didSet = {
99+
if self.isAnimating.value && (self.pages.count < 2 || self.bgColors.count < 2) {
100+
self.isAnimating.value = false
101+
} else {
102+
self.isAnimating.value ? self.animationWillBegin() : self.animationDidEnd()
103+
}
104+
}
105+
106+
currentIndex.didSet = {
107+
if self.currentIndex.value == self.pages.count - 1 {
108+
self.didGoToLastPage()
109+
}
110+
}
76111
}
77112

113+
78114
public var body: some View {
79115

80116
let mainView = ZStack {
81117
bgColor
82118

83119
ZStack {
84120
Button(action: {
85-
self.isAnimating = true
121+
if let block = self.didPressNextButton {
122+
block()
123+
} else {
124+
self.goToNextPageAnimated()
125+
}
86126
}) { shape }
87127

88-
if !isAnimating {
128+
if !isAnimating.value {
89129
Image("arrow")
90130
.resizable()
91131
.frame(width: 7, height: 12)
@@ -99,10 +139,10 @@ public struct ConcentricOnboardingView : View {
99139
}
100140
.edgesIgnoringSafeArea(.vertical)
101141
.onReceive(timer) { _ in
102-
if !self.isAnimating {
142+
if !self.isAnimating.value {
103143
return
104144
}
105-
self.isAnimatingForward ? self.refreshAnimatingViewsForward() : self.refreshAnimatingViewsBackward()
145+
self.isAnimatingForward.value ? self.refreshAnimatingViewsForward() : self.refreshAnimatingViewsBackward()
106146
}
107147

108148
return mainView
@@ -140,17 +180,17 @@ public struct ConcentricOnboardingView : View {
140180
func refreshAnimatingViewsForward() {
141181
progress += step
142182
if progress < limit {
143-
bgColor = bgColors[currentIndex]
144-
circleColor = bgColors[nextIndex]
183+
bgColor = bgColors[currentIndex.value]
184+
circleColor = bgColors[nextIndex.value]
145185
shape = createGrowingShape(progress)
146186
}
147187
else if progress < 2*limit {
148-
bgColor = bgColors[nextIndex]
149-
circleColor = bgColors[currentIndex]
188+
bgColor = bgColors[nextIndex.value]
189+
circleColor = bgColors[currentIndex.value]
150190
shape = createShrinkingShape(progress - limit)
151191
}
152192
else {
153-
isAnimating = false
193+
isAnimating.value = false
154194
progress = 0
155195
goToNextPageUnanimated()
156196
}
@@ -160,17 +200,17 @@ public struct ConcentricOnboardingView : View {
160200
progress += step
161201
let backwardProgress = 2*limit - progress
162202
if progress < limit {
163-
bgColor = bgColors[currentIndex]
164-
circleColor = bgColors[nextIndex]
203+
bgColor = bgColors[currentIndex.value]
204+
circleColor = bgColors[nextIndex.value]
165205
shape = createShrinkingShape(backwardProgress - limit)
166206
}
167207
else if progress < 2*limit {
168-
bgColor = bgColors[nextIndex]
169-
circleColor = bgColors[currentIndex]
208+
bgColor = bgColors[nextIndex.value]
209+
circleColor = bgColors[currentIndex.value]
170210
shape = createGrowingShape(backwardProgress)
171211
}
172212
else {
173-
isAnimating = false
213+
isAnimating.value = false
174214
progress = 0
175215
goToPrevPageUnanimated()
176216
}
@@ -181,22 +221,22 @@ public struct ConcentricOnboardingView : View {
181221
let maxYOffset = 40.0
182222
let currentPageOffset = easingOutProgressFor(time: progress/limit/2)
183223
let nextPageOffset = easingInProgressFor(time: 1 - progress/limit/2)
184-
let coeff: CGFloat = isAnimatingForward ? -1 : 1
224+
let coeff: CGFloat = isAnimatingForward.value ? -1 : 1
185225

186226
var reverseScaleFactor = 1 - nextPageOffset/3
187227
if reverseScaleFactor == 0 {
188228
reverseScaleFactor = 1
189229
}
190230

191231
return ZStack {
192-
if pages.count > 0 { pages[currentIndex]
232+
if pages.count > 0 { pages[currentIndex.value]
193233
//swap effects order to create another animation
194234
.scaleEffect(CGFloat(1 - currentPageOffset/3))
195235
.offset(x: coeff * CGFloat(maxXOffset * currentPageOffset),
196236
y: CGFloat(maxYOffset * currentPageOffset))
197237
}
198238

199-
if pages.count > 1 { pages[nextIndex]
239+
if pages.count > 1 { pages[nextIndex.value]
200240
.scaleEffect(CGFloat(reverseScaleFactor))
201241
.offset(x: -coeff * CGFloat(maxXOffset * nextPageOffset),
202242
y: CGFloat(maxYOffset * nextPageOffset))
@@ -208,33 +248,33 @@ public struct ConcentricOnboardingView : View {
208248
let width = CGFloat(radius * 2)
209249
shape = AnyView(Circle().foregroundColor(circleColor).frame(width: width, height: width, alignment: .center))
210250

211-
bgColor = bgColors[currentIndex]
212-
circleColor = bgColors[nextIndex]
251+
bgColor = bgColors[currentIndex.value]
252+
circleColor = bgColors[nextIndex.value]
213253
}
214254

215255
func goToNextPageAnimated() {
216-
isAnimatingForward = true
217-
nextIndex = moveIndexForward(currentIndex)
218-
isAnimating = true
256+
isAnimatingForward.value = true
257+
nextIndex.value = moveIndexForward(currentIndex.value)
258+
isAnimating.value = true
219259
}
220260

221261
func goToNextPageUnanimated() {
222-
isAnimatingForward = true
223-
currentIndex = moveIndexForward(currentIndex)
224-
nextIndex = moveIndexForward(currentIndex)
262+
isAnimatingForward.value = true
263+
currentIndex.value = moveIndexForward(currentIndex.value)
264+
nextIndex.value = moveIndexForward(currentIndex.value)
225265
updateColors()
226266
}
227267

228268
func goToPrevPageAnimated() {
229-
isAnimatingForward = false
230-
nextIndex = moveIndexBackward(currentIndex)
231-
isAnimating = true
269+
isAnimatingForward.value = false
270+
nextIndex.value = moveIndexBackward(currentIndex.value)
271+
isAnimating.value = true
232272
}
233273

234274
func goToPrevPageUnanimated() {
235-
isAnimatingForward = false
236-
currentIndex = moveIndexBackward(currentIndex)
237-
nextIndex = moveIndexBackward(currentIndex)
275+
isAnimatingForward.value = false
276+
currentIndex.value = moveIndexBackward(currentIndex.value)
277+
nextIndex.value = moveIndexBackward(currentIndex.value)
238278
updateColors()
239279
}
240280

0 commit comments

Comments
 (0)