Connect with us

Программирование

Как использовать UIContentUnavailableConfiguration для управления пустыми состояниями

Мне очень нравится это улучшение в UIKit, оно затрагивает аспект, которым долгое время пренебрегали разработчики и дизайнеры — пустое состояние.

Опубликовано

/

     
     

В этом году на WWDC Apple удивила разработчиков неожиданным улучшением UIKit. Представление  UIContentUnavailableConfiguration было направлено на упрощение процесса создания пустых состояний для контроллеров представления.

По словам Apple, UIContentUnavailableConfiguration представляет собой composable описание пустого состояния и может быть снабжено содержимым-заполнителем, например, изображением или текстом.

Вот пример пустого состояния, продемонстрированный на WWDC:

Как использовать UIContentUnavailableConfiguration для управления пустыми состояниями

Теперь давайте разберемся в деталях.

Примечание: Эта статья в основном посвящена UIKit. Если вы хотите узнать, как сделать то же самое в SwiftUI, рекомендую ознакомиться с этой статьей Антуана ван дер Ли.

Создание UIContentUnavailableConfiguration

Существует 4 способа создания UIContentUnavailableConfiguration:

  1. Создание с нуля
  2. Использование предопределенной конфигурации загрузки
  3. Использование предопределенной конфигурации поиска
  4. Использование конфигурации UIHostingConfiguration

1. Создание с нуля

Чтобы начать с нуля, мы должны сначала создать пустую UIContentUnavailableConfiguration.

var config = UIContentUnavailableConfiguration.empty()

После этого нам нужно будет настроить содержимое UIContentUnavailableConfiguration в соответствии с нашими потребностями:

config.image = UIImage(systemName: "applelogo")
config.text = "WWDC23 Demo"
config.secondaryText = "Code new worlds."

Наконец, просто установить конфигурацию в contentUnavailableConfiguration контроллера представления.

self.contentUnavailableConfiguration = config

Пустое состояние, показанное ниже, теперь должно быть видно в центре контроллера представления.

Как использовать UIContentUnavailableConfiguration для управления пустыми состояниями

Вы можете обратиться к документации по UIContentUnavailableConfiguration, чтобы узнать обо всех других настраиваемых параметрах содержимого.

2. Использование предопределенной конфигурации загрузки

Если нам нужно показать пустое состояние в ожидании загрузки приложений, то мы можем использовать предопределенную конфигурацию загрузки.

var config = UIContentUnavailableConfiguration.loading()
self.contentUnavailableConfiguration = config

Использование приведенного выше кода приведет к следующему пустому состоянию:

Как использовать UIContentUnavailableConfiguration для управления пустыми состояниями

Как и в пустой конфигурации, содержимое заполнителя загрузочной конфигурации также настраивается.

var config = UIContentUnavailableConfiguration.loading()

config.text = "Fetching content. Please wait..."
config.textProperties.font = .boldSystemFont(ofSize: 18)
        
self.contentUnavailableConfiguration = config

Вот как это выглядит после вышеуказанной настройки:

Как использовать UIContentUnavailableConfiguration для управления пустыми состояниями3. Использование предопределенной конфигурации поиска

Еще одна очень полезная предопределенная конфигурация — это конфигурация поиска. Мы можем использовать ее, когда хотим показать пустое состояние для результата поиска:

var config = UIContentUnavailableConfiguration.search()
self.contentUnavailableConfiguration = config

Подобно конфигурации загрузки, содержимое-заполнитель конфигурации поиска также можно настраивать.

Как использовать UIContentUnavailableConfiguration для управления пустыми состояниями4. Использование UIHostingConfiguration

И наконец, мой личный фаворит — использование UIHostingConfiguration. Этот подход, по сути, позволяет нам создать любой пустой макет состояния, который мы хотим, используя SwiftUI.

Например:

let config = UIHostingConfiguration {
    Text("Unknown error occurred, please [contact support](https://swiftsenpai.com).")
        .multilineTextAlignment(.center)
}

self.contentUnavailableConfiguration = config

Приведенный выше код даст нам следующий результат:

Как использовать UIContentUnavailableConfiguration для управления пустыми состояниями

Профессиональный совет: Чтобы узнать больше о UIHostingConfiguration, я рекомендую ознакомиться с этими статьями.

Обновление contentUnavailableConfiguration контроллера представления

Когда дело доходит до обновления contentUnavailableConfiguration, Apple рекомендует разработчикам переопределить новый метод обновления под названием updateContentUnavailableConfiguration(using:).

На данный момент нет официальной документации, определяющей, когда именно будет вызываться этот метод. Однако, по моим наблюдениям, метод вызывается каждый раз, когда загружается контроллер представления.

В ситуациях, когда нам нужно вручную вызвать метод обновления, мы можем вызвать следующую функцию:

setNeedsUpdateContentUnavailableConfiguration()

Пример использования в реальной жизни

На основе того, что мы только что обсудили, я создал пример приложения, чтобы показать, как использовать UIContentUnavailableConfiguration для отображения пустого состояния, когда приложение либо загружается, либо сталкивается с ошибкой.

Для дальнейшего повышения интерактивности примера приложения я также добавил кнопку перезагрузки (которая также является частью UIContentUnavailableConfiguration) в пустое состояние ошибки. Эта кнопка перезагрузки позволяет пользователям легко обновить содержимое приложения в случае ошибки.

Как использовать UIContentUnavailableConfiguration для управления пустыми состояниями

Вот полный код примера, если вам интересно. Обязательно запустите его на Xcode 15 beta 1 или более поздней версии.

import UIKit

class ContentUnavailableViewController: UIViewController {
    
    /// Variable to keep track of content fetching state
    /// nil means content is not yet fetched
    var fetchContentSuccessful: Bool? = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Create fetch button
        let fetchAction = UIAction(handler: { [weak self]_ in
            self?.startFetchCotent()
        })
        let fetchButton = UIBarButtonItem(title: "Fetch", primaryAction: fetchAction)
        navigationItem.rightBarButtonItem = fetchButton
    }
    
    override func updateContentUnavailableConfiguration(
        using state: UIContentUnavailableConfigurationState
    ) {
        // Remove existing configuration (if exist)
        contentUnavailableConfiguration = nil
        
        guard let fetchContentSuccessful else {
            // User have not trigger fetch
            return
        }
        
        if fetchContentSuccessful {
            // Prompt alert view
            showContent()
        } else {
            // Show empty state
            showError()
        }
    }
    
    /// Start the fetch content flow
    private func startFetchCotent() {
        
        Task { [weak self] in
           
            guard let self = self else { return }
            
            showLoading()
            fetchContentSuccessful = await fetchContent()
            
            // Update UI
            setNeedsUpdateContentUnavailableConfiguration()
        }
    }
    
    /// Action to run after successfully fetch content
    private func showContent() {
        
        let alert = UIAlertController(
            title: "🎉🎉🎉",
            message: "Fetch successful!",
            preferredStyle: .alert
        )
        
        let positiveAction = UIAlertAction(
            title: "OK",
            style: .default
        )
        alert.addAction(positiveAction)
        
        present(alert, animated: true)
    }
    
    /// Show the loading empty state
    private func showLoading() {
        
        var config = UIContentUnavailableConfiguration.loading()
        config.text = "Fetching content. Please wait..."
        config.textProperties.font = .boldSystemFont(ofSize: 18)
        
        self.contentUnavailableConfiguration = config
    }
    
    /// Show the empty state when encounter error
    private func showError() {
        
        var errorConfig = UIContentUnavailableConfiguration.empty()
        errorConfig.image = UIImage(systemName: "exclamationmark.circle.fill")
        errorConfig.text = "Something went wrong."
        errorConfig.secondaryText = "Please try again later."
        
        // Create configuration for reload button
        var retryButtonConfig = UIButton.Configuration.borderless()
        retryButtonConfig.image = UIImage(systemName: "arrow.clockwise.circle.fill")
        errorConfig.button = retryButtonConfig
        
        // Define the reload button action
        errorConfig.buttonProperties.primaryAction = UIAction.init(handler: { _ in
            
            Task { [weak self] in
                guard let self = self else { return }
                startFetchCotent()
            }
        })
        
        contentUnavailableConfiguration = errorConfig
    }
    
    /// A dummy function to simulate the fetch content action
    private func fetchContent() async -> Bool {
        
        // Sleep for 1 minutes to simulate a slow API call
        try? await Task.sleep(nanoseconds: 1_000_000_000)
        
        return Bool.random()
    }
}

Подведение итогов

Мне очень нравится это улучшение в UIKit, оно затрагивает аспект, которым долгое время пренебрегали разработчики и дизайнеры — пустое состояние.

Уменьшая трение, связанное с обработкой пустых состояний, Apple эффективно устраняет одно из распространенных оправданий, по которым разработчики пренебрегали этим аспектом дизайна приложений. Компания поощряет разработчиков брать на себя ответственность за то, чтобы пользовательский интерфейс их приложений не оставался в унылом, необработанном состоянии.

Спасибо за чтение. 👨🏻‍💻

Источник

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.

Наши партнеры:

LEGALBET

Мобильные приложения для ставок на спорт
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: