Итак, есть задача: переделать экран авторизации на новый дизайн, добавить новые способы авторизации. И заодно опять же перейти на SwiftUI. Кстати, у нас довольно объёмный проект, и я думала мы будем очень долго переходить с UIKit, но прошло пол года, а уже треть почти переделана, без особых напрягов.
Так вот, кусочек дизайна выглядит примерно так (все экраны нет смысла показывать, т к в данной статье хочу показать только злополучное модальное окно).
Есть: начальный экран с кнопками для входа и модальный экран с согласием на обработку данных. На первый взгляд никакого подвоха, всё должно быть нативно.
Пишем код основной вью:
struct AuthView: View { @StateObject private var viewModel = AuthViewModel() @StateObject private var agreementViewModel = AuthAgreementModalViewModel() var body: some View { NavigationView { VStack(spacing: 0) { // Image Image("authPicture") // Title Text("Quick login") // Кнопки мессенджеров VStack(spacing: 8) { ... // в действие по нажатию на кнопку добавляем // появление модального окна: agreementViewModel.showModal = true } .padding(.top, 24) Spacer() // Дополнительный лейбл Text("If you have any problems with authorization, please contact our support service support@domain.com") } .navigationBarHidden(true) } } }
Добавляем ViewModel:
class AuthViewModel: ObservableObject { @Published vars ... var completionHandler: (() -> Void)? func handleLoginAfterAgreement() { guard let button = selectedButton else { return } handleLogin(for: button) selectedButton = nil } func handleLogin(for button: LoginButtonId) { switch button { case .apple: print("Apple ID login tapped") startSignInWithAppleFlow() case .gmail: print("gmail login tapped") // логику для gmail case .email: print("email login tapped") // логику для email } } func startSignInWithAppleFlow() { ... } func onFinish() { completionHandler?() } }
Полный код будет на GitHub, там полностью всё расписала, в том числе и регистрацию через AppleID.
По нажатию на одну из кнопок регистрации нужно сначала показать окно с соглашением, и только после согласия пользователя с правилами — производить действие по регистрации.
Собственно, самое простое, как показать модальное окно:
.sheet(isPresented: $agreementViewModel.showModal) { AuthAgreementModalView() }
Но что мы видим при такой имплементации:

Вроде всё норм, но модальное окно не подстраивается по высоте содержимого. Это легко решается с помощью: .presentationDetents
.sheet(isPresented: $agreementViewModel.showModal) { AuthAgreementModalView() .presentationDetents([.medium, .large]) // Опционально несколько размеров .presentationDragIndicator(.visible) // Показывает индикатор перетаскивания }
Так же, как в UIKit, сделать, к сожалению, нельзя. То есть нам всё равно придётся примерно выбрать высоту. Но на ios15 даже такое не работает. Поэтому возвращаемся к любимому костылю:
.overlay( Group { if agreementViewModel.showModal { Color(white: 0, opacity: 0.5) .edgesIgnoringSafeArea(.all) AuthAgreementModalView(viewModel: agreementViewModel, onDismiss: { // Обработчик закрытия модального окна agreementViewModel.showModal = false viewModel.handleLoginAfterAgreement() }) .transition(.move(edge: .bottom)) .zIndex(1) } } ) .animation(.easeInOut, value: agreementViewModel.showModal)
Прописываем прозрачный серый бэкграунд, откуда появляется окно, а так же действие по закрытию. А в сам AuthAgreementModalView добавим скругление верхних углов .cornerRadius(24, corners: [.topLeft, .topRight])
Ну вот и всё, после скрытия модального окна открывается нужная регистрация:

Полный код тут: ссылка на GitHub.
Если интересно, подписывайтесь на мой ТГ, там выкладываю рилсы про разработку: канал тут.
ссылка на оригинал статьи https://habr.com/ru/articles/874258/
Добавить комментарий