На протяжении нашей профессиональной деятельности мы в основном создаем приложения, которые так или иначе обмениваются данными с веб-сервисами. Изображения на удаленных серверах — это как раз один из таких типов данных, которые нам необходимо загружать и отображать в нашем приложении. SwiftUI предоставляет нам тип AsyncImage, который является представлением для загрузки и отображения изображений по URL-адресу. В этой статье вы узнаете, как использовать и кастомизировать AsyncImage в SwiftUI.

Основы

Давайте рассмотрим небольшой пример, который показывает, как использовать AsyncImage.

struct AvatarView: View {
    let url: URL

    var body: some View {
        AsyncImage(url: url)
    }
}

В приведенном выше примере мы видим, что AsyncImage — это представление (view) SwiftUI, которое загружает и отображает изображение по указанному URL-адресу без дополнительной возни на сетевом уровне. Для загрузки и кеширования изображений AsyncImage использует общий URLSession. К сожалению, мы не можем использовать пользовательский URLCache или каким-либо образом кастомизировать URLRequest, который загружает изображение.

AsyncImage — это представление SwiftUI, что подразумевает возможность прикреплять любой набор модификаторов представления для получения желаемого внешнего вида и поведения. Например, можно установить размер и обрезать форму нашего изображения.

struct AvatarView: View {
    let url: URL

    var body: some View {
        AsyncImage(url: url)
            .frame(width: 44, height: 44)
            .background(Color.gray)
            .clipShape(Circle())
    }
}

Кастомизация

Зачастую нам требуется кастомизировать размер загружаемого изображения, параметры масштабирования, режим рендеринга и т.д. Мы можем получить доступ к экземпляру изображения-подложки, используя перегрузку инициализатора AsyncImage.

    AsyncImage(url: url) { image in
        image
            .resizable()
            .scaledToFill()
    } placeholder: {
        ProgressView()
    }
    .frame(width: 44, height: 44)
    .background(Color.gray)
    .clipShape(Circle())

Здесь мы использовали другой инициализатор AsyncImage для доступа к загружаемому изображению, изменения его размера и применения режима заполнения. Этот инициализатор также позволяет нам использовать представление-плейсхолдер, которое SwiftUI отображает при загрузке изображения.

Больше информации о параметрах рендеринга изображений в SwiftUI вы можете найти в моей статье “Mastering images in SwiftUI”.

Следует отметить, что этот инициализатор использует ViewBuilder замыкание, что дает возможность воспользоваться любым модификатором представления SwiftUI и создать супер-кастомную презентацию.

    AsyncImage(url: url) { image in
        image
            .resizable()
            .scaledToFill()
            .overlay(Material.ultraThin)
    } placeholder: {
        ProgressView()
    }
    .frame(width: 44, height: 44)
    .background(Color.gray)
    .clipShape(Circle())

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

Больше информации о логике, стоящей за типом ViewBuilder, вы найдете в моей статье “The power of @ViewBuilder in SwiftUI”.

С помощью другого инициализатора AsyncImage позволяет нам полностью контролировать все этапы презентации изображения.

struct AvatarView: View {
    let url: URL

    var body: some View {
        AsyncImage(
            url: url,
            transaction: Transaction(animation: .easeInOut)
        ) { phase in
            switch phase {
            case .empty:
                ProgressView()
            case .success(let image):
                image
                    .resizable()
                    .transition(.scale(scale: 0.1, anchor: .center))
            case .failure:
                Image(systemName: "wifi.slash")
            @unknown default:
                EmptyView()
            }
        }
        .frame(width: 44, height: 44)
        .background(Color.gray)
        .clipShape(Circle())
    }
}

Как видите, мы использовали другой инициализатор, который принимает ViewBuilder замыкание. Это замыкание имеет только один параметр, который является экземпляром перечисления AsyncImagePhase. Перечисление AsyncImagePhase определяет набор состояний загрузки изображения: empty, success, и failed. Обрабатывая все эти состояния вы можете создавать супер-кастомные презентации изображений.

Еще один параметр инициализатора, используемого выше, — это транзакция SwiftUI (Transaction). По умолчанию AsyncImage создает новую транзакцию с дефолтной конфигурацией. В нашем примере я создаю кастомную транзакцию с определенной анимацией, которую AsyncImage будет использовать при изменении фаз.

Больше информации о возможностях транзакций в SwiftUI вы найдете в моей статье “Transactions in SwiftUI”.

Заключение

Сегодня мы узнали, как загружать и отображать изображения с удаленных серверов с помощью представления AsyncImage. Я рад видеть, что SwiftUI предоставляет нам эту фичу, потому что она является фундаментальной для большинства приложений, которые мы создаем. Надеюсь, вам понравится эта статья. Подписывайтесь на меня вTwitterи задавайте свои вопросы по этой теме. Спасибо за проявленный интерес и до встречи на следующей неделе!


Материал подготовлен в рамках курса "iOS Developer. Basic".

Комментарии (0)