Третья версия SwiftUI принесла нам несколько модификаторов представления (view modifiers), которые позволяют нам одинаково обрабатывать семантически похожие операции для разных представлений. Например одним из таких модификаторов представления является onSubmit
, который мы можем использовать для управления как формами, так и полями поиска (search fields
). На этой неделе мы поговорим о другом модификаторе представления, который SwiftUI предоставляет нам для отображения диалоговых окон подтверждения (confirmationDialog
).
Диалог подтверждения (confirmation dialog
) — это очень распространенный шаблон UI/UX, который мы обычно используем для подтверждения любых опасных действий в наших приложениях. Например, мы можем выводить диалоговое окно подтверждения перед удалением каких-либо конфиденциальных данных из приложения.
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
NavigationView {
List {
ForEach(viewModel.messages, id: \.self) { message in
Text(message)
.swipeActions {
Button(
role: .destructive,
action: {
withAnimation {
viewModel.delete(message)
}
}
) {
Image(systemName: "trash")
}
}
}
}
.navigationTitle("Messages")
.onAppear { viewModel.fetch() }
}
}
}
Как вы можете видеть в приведенном выше примере, у нас есть экран, показывающий список сообщений из модели представления. Для предоставления действий, связанных с элементом списка, мы используем свайпы. В нашем случае мы показываем деструктивную кнопку, которая удаляет сообщение, как только вы ее нажимаете. Давайте посмотрим, как мы можем вывести диалоговое окно подтверждения с помощью нового модификатора представления confirmationDialog
.
struct ContentView: View {
@StateObject var viewModel = ViewModel()
@State private var confirmationShown = false
var body: some View {
NavigationView {
List {
ForEach(viewModel.messages, id: \.self) { message in
Text(message)
.swipeActions {
Button(
role: .destructive,
action: { confirmationShown = true }
) {
Image(systemName: "trash")
}
}
.confirmationDialog(
"Are you sure?",
isPresented: $confirmationShown
) {
Button("Yes") {
withAnimation {
viewModel.delete(message)
}
}
}
}
}
.navigationTitle("Messages")
.onAppear { viewModel.fetch() }
}
}
}
Мы добавляем модификатор confirmationDialog
к представлению Text
, которое мы хотим удалить. Для отображения диалогового окна подтверждения потребуется несколько параметров:
Первый - это заголовок конкретного диалогового окна подтверждения. Это может быть
Text
илиLocalizedStringKey
.Второй - привязка к логическому значению, которое указывает, когда следует отображать диалоговое окно подтверждения.
Третий - это замыкание
@ViewBuilder
, которое мы можем использовать для предоставления доступных действий с помощью представлений кнопок. Имейте в виду, что мы можем использовать только кнопки с текстом.
Вам не нужно предоставлять кнопку отмены. SwiftUI делает это автоматически для любого диалогового окна подтверждения. Но вы все равно можете предложить кнопку с ролью .cancel
, чтобы заменить кнопку отмены по умолчанию.
.confirmationDialog("Are you sure?", isPresented: $confirmationShown) {
Button("Yes") {
withAnimation {
viewModel.delete(message)
}
}
Button("No", role: .cancel) {}
}
Вам не нужно изменять значение привязки на false
чтобы закрыть диалоговое окно подтверждения. SwiftUI закрывает диалоговое окно подтверждения, как только пользователь выполняет любое из указанных действий.
Я должен упомянуть, что система может переупорядочивать кнопки в зависимости от их ролей и важности. SwiftUI применяет более высокий приоритет для действия по умолчанию. Вы можете сделать любое из предоставленных действий действием по умолчанию, используя модификатор представления keyboardShortcut
.
.confirmationDialog("Are you sure?", isPresented: $confirmationShown) {
Button("Yes") {
withAnimation {
viewModel.delete(message)
}
}.keyboardShortcut(.defaultAction)
Button("No", role: .cancel) {}
}
SwiftUI обрабатывает различные среды соответственно - диалог подтверждения отображается как всплывающее окно при запуске в классах стандартного размера и в качестве списка действий в компактных классах.
Чтобы узнать больше о всплывающих окнах и списках действий в SwiftUI, почитайте мою статью «Alerts, Action Sheets, Modals and Popovers in SwiftUI».
Модификатор представления confirmationDialog
также предоставляет нам возможность контролировать titleVisibility
представленного диалога. Параметр titleVisibility
принимает инстанс перечисления Visibility
с одним из следующих значений: automatic
, visible
, и hidden
.
.confirmationDialog(
"Are you sure?",
isPresented: $confirmationShown,
titleVisibility: .visible
) {
Button("Yes") {
withAnimation {
viewModel.delete(message)
}
}.keyboardShortcut(.defaultAction)
Button("No", role: .cancel) {}
}
Мы также можем добавить дополнительное сообщение под заголовком с помощью параметра сообщения, который принимает другое замыкание @ViewBuilder
, чтобы создать представление для отображения пользовательского сообщения.
.confirmationDialog(
"Are you sure?",
isPresented: $confirmationShown,
titleVisibility: .visible
) {
Button("Yes") {
withAnimation {
viewModel.delete(message)
}
}.keyboardShortcut(.defaultAction)
Button("No", role: .cancel) {}
} message: {
Text("This action cannot be undone")
}
Модификатор представления confrimationDialog
позволяет нам предоставлять дополнительные данные для передачи в замыкания @ViewBuilder
как для сообщения, так и для действий.
.confirmationDialog(
"Are you sure?",
isPresented: $confirmationShown,
titleVisibility: .visible,
presenting: message
) { message in
Button("Yes, delete: \(message)") {
withAnimation {
viewModel.delete(message)
}
}.keyboardShortcut(.defaultAction)
Button("No", role: .cancel) {}
} message: { message in
Text(message)
}
Чтобы узнать больше о преимуществах замыканий ViewBuilder
в SwiftUI, читайте мою публикацию «The power of @ViewBuilder in SwiftUI».
Мне очень нравится новый модификатор представления confirmationDialog
за тот уровень гибкости, что он обеспечивает при кастомизации пользовательского опыта в наших приложениях. Надеюсь, вам понравилась эта статья. Не стесняйтесь подписываться на меня в Твиттере и задавать свои вопросы, связанные с этой темой. Спасибо за внимание, до встречи на следующей неделе!
Материал подготовлен в рамках специализации «iOS Developer».
Всех желающих приглашаем на открытый урок «Новые инструменты Swift, для работы с асинхронностью Async/Away/Actor». На открытом уроке поговорим о новых инструментах Swift 5.5 по работе с асинхронными задачами.Открытый урок рассчитан на разработчиков, имеющих опыт, и желающих ознакомиться с новыми возможностями для работы с асинхронными задачами.