Розробка мультишагового процесу реєстрації (Wizard) мобільного приложення
Багатошагова реєстрація вирішує конкретну проблему: користувач не готовий за один раз заповнити 15 полів. Wizard розбиває процес на послідовні екрани, зменшує когнітивну навантаження та дозволяє зберігати прогрес. Але він же створює технічні завдання — управління станом між кроками, валідація по частинах, восстановлення після переривання.
Архітектура стану
Головна помилка — зберігати дані кожного кроку в окремому ViewModel. При переході "назад" стан втрачається, користувач вводить дані повторно.
Правильно: єдиний RegistrationViewModel (або RegistrationStore у Redux/MVI архітектурі) зберігає весь стан wizard:
data class RegistrationState(
val currentStep: RegistrationStep = RegistrationStep.PERSONAL_INFO,
val personalInfo: PersonalInfoForm = PersonalInfoForm(),
val contactDetails: ContactDetailsForm = ContactDetailsForm(),
val accountSetup: AccountSetupForm = AccountSetupForm(),
val isLoading: Boolean = false,
val error: String? = null
)
sealed class RegistrationStep {
object PersonalInfo : RegistrationStep()
object ContactDetails : RegistrationStep()
object AccountSetup : RegistrationStep()
object EmailVerification : RegistrationStep()
object Completed : RegistrationStep()
}
Кожен крок — окремий Composable/UIViewController, що отримує фрагмент стану та колбеки. Навігація управляється з ViewModel через currentStep, а не через NavController напрямки.
Навігація між кроками
У iOS — UIPageViewController (горизонтальний свайп) або кастомний ContainerViewController. У SwiftUI — TabView з .tabViewStyle(.page) та прихованими індикаторами, або кастомний ZStack з анімацією slide.
У Jetpack Compose — AnimatedContent по currentStep:
AnimatedContent(
targetState = state.currentStep,
transitionSpec = {
slideInHorizontally { width -> width } + fadeIn() with
slideOutHorizontally { width -> -width } + fadeOut()
}
) { step ->
when (step) {
is RegistrationStep.PersonalInfo -> PersonalInfoStep(...)
is RegistrationStep.ContactDetails -> ContactDetailsStep(...)
// ...
}
}
Кнопка "Назад" — не системна back-кнопка (хоча її теж обробляємо), а явна кнопка в header з переходом до попереднього кроку без скидання даних.
Прогрес-індикатор
Лінійний прогресбар (LinearProgressIndicator) з анімованим заповненням — мінімум. Додатково — крок N з M, текстова назва поточного кроку. Не показуємо кроки, які користувач ще не видів — тільки пройдені та поточний.
Валідація пошагово
Кожен крок валідується перед переходом до наступного. Якщо користувач повертається на попередній крок та змінює дані — перевалідуємо залежні наступні кроки (наприклад, телефон змінився — OTP вже не актуальна, email verification скидається).
// iOS — валідація перед переходом
func proceedToNextStep() {
guard case .success = validateCurrentStep() else {
showValidationErrors()
return
}
currentStep = currentStep.next
}
Восстановлення прогреса
Якщо користувач закрив приложення на кроці 3 з 5 — що відбувається при повертанні? Варіанти:
- Скинути: найпростіший варіант, підходить для коротких wizard (2–3 кроки).
-
Восстановити: зберігаємо
RegistrationStateвUserDefaults/Room/Core Data (без чутливих даних — пароль не зберігаємо). При запуску перевіряємо наявність незавершеної реєстрації. - Сервер зберігає прогрес: при першому кроці створюємо чорновик на сервері, кожен крок патчимо чорновик. На будь-якому пристрої користувач продовжує з того ж місця.
Для крупних onboarding-форм (entity verification, медичні дані) — третій варіант обов'язковий.
Email/Phone верифікація всередину wizard
OTP-крок — окремий екран з полем для коду. Таймер зворотного відліку (60 секунд), кнопка "Відправити повторно" з'являється після істечення таймера. Автоматичне читання OTP з SMS (iOS: .textContentType(.oneTimeCode), Android: SMS Retriever API через SmsRetrieverClient).
SMS Retriever на Android не потребує дозволу READ_SMS — це важливо для прохідження ревю в Google Play. Працює через хеш приложення (11-символьний рядковий токен, генерується з signing certificate), який включається в текст SMS.
Завершення реєстрації
Після останнього кроку — не одразу в головний екран. Екран "Добро пожаловать" з анімацією (Lottie або SF Symbols animation) та єдиною CTA. Зберігаємо стан "реєстрація завершена" в UserDefaults — щоб при наступному відкриванні не показувати onboarding знову.
Терміни
Wizard з 3–4 кроків з валідацією, прогрес-індикатором, OTP-верифікацією та восстановленням прогреса — 10–16 робочих днів на одну платформу. Якщо потрібен кроссплатформенний (React Native/Flutter) — 14–20 днів. Серверна частина для зберігання чорновиків — окрема оцінка.







