Skip to content

Instantly share code, notes, and snippets.

@khcrysalis
Last active July 14, 2025 02:37
Show Gist options
  • Select an option

  • Save khcrysalis/c9b9246a72282df0339c412ec3b49180 to your computer and use it in GitHub Desktop.

Select an option

Save khcrysalis/c9b9246a72282df0339c412ec3b49180 to your computer and use it in GitHub Desktop.
Fancy Onboarding SwiftUI View for iOS
import SwiftUI
// MARK: - View
struct OnboardingView: View {
@AppStorage("Feather.onboarding") private var _onboardingFinished: Bool = false
@State private var _page: Int = 0
private var _pageLimit: Int = 2
// MARK: Body
var body: some View {
VStack(alignment: .center) {
ZStack {
if _page == 0 {
_largeTitle()
.compatBlurTransition()
} else if _page == 1 {
_details(
"Inspect Package Files",
"Feather is an on-device application inspector and manager designed for self-developed apps, mainly viewing on how iOS apps function and work as a whole."
)
.compatBlurTransition()
} else if _page == 2 {
_details(
"Pairing File",
"Feather requires a VPN and a pairing file to operate."
)
.compatBlurTransition()
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.background(
ZStack {
if _page == 0 {
LinearGradient(
colors: [
Color(hex: "46365f"),
Color(hex: "413258"),
Color(hex: "4a3963")
],
startPoint: .top,
endPoint: .bottom
)
.transition(.opacity)
} else {
Color(.systemBackground)
.transition(.opacity)
}
}
.ignoresSafeArea(.all)
)
.safeAreaInset(edge: .bottom) {
HStack(spacing: 12) {
if _page != 0 {
_button("Back", action: _backward)
.compatBlurTransition()
_button("Continue", action: _forward)
.compatBlurTransition()
} else {
_button("Continue", action: _forward)
.compatBlurTransition()
}
}
.padding()
.padding(.horizontal, 24)
}
.animation(.default, value: _page)
}
@ViewBuilder
private func _largeTitle() -> some View {
VStack(alignment: .center) {
Text("Welcome to")
.foregroundStyle(.white)
Text(Bundle.main.name)
.foregroundStyle(.accent)
}
.font(.system(size: 45))
.fontWeight(.heavy)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
}
@ViewBuilder
private func _details(_ title: String, _ desc: String) -> some View {
VStack(alignment: .leading, spacing: 12) {
Text(title)
.font(.title)
.bold()
Text(desc)
}
.padding()
.padding(.horizontal, 24)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
}
@ViewBuilder
private func _button(_ title: String, action: @escaping () -> Void) -> some View {
Button(action: {
action()
}) {
Text(title)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
LinearGradient(
colors: [
.white,
_page == 0 ? Color(hex: "776A89") : .secondary
],
startPoint: .top,
endPoint: .bottom
)
)
.foregroundColor(.init(hex: "413258"))
.clipShape(
RoundedRectangle(cornerRadius: 12, style: .continuous)
)
.bold()
}
.frame(height: 50)
.shadow(color: .black.opacity(0.4), radius: 15, x: 0, y: 8)
}
private func _forward() {
if _page != _pageLimit {
_page += 1
}
if _page == _pageLimit {
// _onboardingFinished = true
}
}
private func _backward() {
if _page != 0 {
_page -= 1
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment