Костыли, костыли и ещё раз костыли. Или поддержка ios15 на SwiftUI

от автора

Итак, есть задача: переделать экран авторизации на новый дизайн, добавить новые способы авторизации. И заодно опять же перейти на 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *