Каждый раз, когда мы загружаем изображения из Интернета, есть вероятность, что загрузка не удалась. Для лучшего взаимодействия с пользователем важно иметь готовый механизм заполнителя. В этом посте я покажу вам, как я расширил свой форк Xamarin.Forms.Nuke для достижения этой цели на iOS.

Что такое Xamarin.Forms.Nuke?

Xamarin.Forms.Nuke - это реализация Xamarin.Forms Nuke, одной из самых продвинутых библиотек изображений для iOS на сегодняшний день. Реализация Xamarin.Forms в значительной степени ориентирована только на кеширование, в то время как исходная библиотека имеет множество дополнительных функций. Я узнал об этой библиотеке, когда начал искать альтернативу кэшированию изображений через Akavache, который я использовал раньше (я никогда не писал об этой части, потому что она не была готова к этому, tbh).

Зачем нужно расширять библиотеку?

В настоящее время библиотека делает только одно (очень хорошо) - обрабатывает кеширование веб-изображений. Он использует настройки по умолчанию собственной библиотеки Nuke. Реализация Xamarin.Forms перезаписывает ImageSourceHandler для UriImageSource и FileImageSource (необязательно), но случай загрузки заполнителя не предусмотрен в исходной версии. Поскольку у меня есть несколько сценариев, в которых может пригодиться заполнитель, я решил расширить библиотеку - и с этого момента поддерживать ее собственный форк. (Может быть, тоже будет запрос на перенос к первоисточнику).

Покажи мне наконец код!

Для нашего расширения мы модифицируем класс FormsHandler, а также класс ImageSourceHandler. Давайте сначала посмотрим на класс FormsHandler. Мы добавляем новое свойство для заполнителя:

public static ImageSource PlaceholderImageSource { get; private set; }

Я выбрал класс FormsHandler, потому что установка заполнителя - это глобальная вещь (в моих сценариях ваш пробег может отличаться). Это уже все, что есть в классе FormsHandler, поэтому давайте взглянем на класс ImageSourceHandler.

Поскольку мы используем значение по умолчанию Xamarin.Forms ImageSourceHandler для изображения ресурса (это StreamImageSource) и FontImageSource, нам нужно сначала добавить для них статические поля:

private static readonly StreamImagesourceHandler DefaultStreamImageSourceHandler = new StreamImagesourceHandler();

private static readonly FontImageSourceHandler DefaultFontImageSourcehandler = new FontImageSourceHandler();

Теперь давайте реализуем загрузку заполнителя отдельным методом:

private static Task<UIImage> LoadPlaceholderAsync()
{
    switch (FormsHandler.PlaceholderImageSource)
    {
        case StreamImageSource streamImageSource:
            FormsHandler.Warn($"loading placeholder from resource");
            return DefaultStreamImageSourceHandler.LoadImageAsync(streamImageSource);
                    
        case FontImageSource fontImageSource:
            FormsHandler.Warn($"loading placeholder from Font");
            return DefaultFontImageSourcehandler.LoadImageAsync(fontImageSource);
        default:
            FormsHandler.Warn($"no valid placeholder found");
            return null;
    }
}

Как видите, ничего сложного в этом методе нет. В зависимости от типа заполнителя, установленного в классе FormsHandler, мы вызываем реализацию по умолчанию Xamarin.Forms для изображения-заполнителя. Давайте применим этот код, изменив LoadImageAsync метод ImageSourceHandler:

public async Task<UIImage> LoadImageAsync(
    ImageSource imageSource,
    CancellationToken cancellationToken = new CancellationToken(),
    float scale = 1)
{
    var result = await NukeHelper.LoadViaNuke(imageSource, cancellationToken, scale);
    if (result == null)
        result = await LoadPlaceholderAsync();

    return result;
}

Поскольку нам нужно знать, может ли класс Nukehelper загрузить изображение, мы уже запускаем код, ожидая его на этом уровне. Если результат равен нулю, мы загружаем изображение-заполнитель с помощью нашего ранее реализованного метода. Это все, что нам нужно сделать в нашем разветвленном репозитории Xamarin.Forms.Nuke.

Как использовать его в своем проекте Xamarin.Forms - iOS

Сначала клонируйте мою вилку (или, если хотите) репозитория Xamarin.Forms.Nuke, импортируйте ее в свое решение Xamarin.Forms и ссылайтесь на нее в своем проекте iOS. Как только это будет сделано, нам нужно инициализировать библиотеку Nuke (как в исходном коде) в методе AppDelegate‘s FinishedLaunching:

Xamarin.Forms.Nuke.FormsHandler.Init(true, false);

Второй шаг - определить источник изображения-заполнителя. FontImageSource следует определять после LoadApplication метода. Таким образом вы можете Xamarin.Forms загрузить шрифт как ресурс.

//Resource image
Xamarin.Forms.Nuke.FormsHandler.PlaceholderFromResource("CachedImageTest.MSicc_Logo_Base_Blue_1024px_pad25.png", Assembly.GetAssembly(typeof(MainViewModel)));

//FontImageSource
Xamarin.Forms.Nuke.FormsHandler.PlaceholderFromFontImageSource(new FontImageSource
{
    Glyph = CachedImageTest.Resources.MaterialDesignIcons.ImageBroken,
    FontFamily = "MaterialDesignIcons",
    Color = Color.Red
});

Теперь используйте элемент управления Xamarin.Forms Image, как всегда. Если изображение из Интернета не может быть загружено, вы увидите заполнитель, как в этих двух примерах:

С помощью нескольких дополнений к библиотеке Xamarin.Forms.Nuke мы реализовали механизм заполнителя для изображений, которые не могут быть загружены. Как всегда, я надеюсь, что этот пост будет полезен для некоторых из вас. Теперь, когда у меня есть реализация для iOS быстрого кэширования изображения с загрузкой заполнителя, я перейду к Android, где я попытаюсь добиться того же с помощью библиотеки Glidex.Forms и расширить ее, чтобы загрузить заполнитель. После реализации будет и полный образец. Следите за новостями!

До следующей публикации, желаю всем счастливого кодирования!

Сообщение Расширение Xamarin.Forms.Nuke на iOS для загрузки заполнителя для изображений, которые не загружаются впервые появилось в Блоге MSicc.