Что такое glidex.forms?

Библиотека glidex.forms - это Xamarin.Forms реализация Glide, который является одним из квазистандартов для обработки изображений на Android (даже рекомендован Google). К счастью, Джонатан Пепперс из Microsoft стремится улучшить Xamarin.Android, и Xamarin.Forms также извлекает из этого большое преимущество. Он сделал Xamarin.Android библиотеку привязки, а также реализацию Xamarin.Forms. Как и раньше с Xamarin.Forms.Nuke, я узнал об этой библиотеке, потому что заменяю свое прежнее решение для кэширования изображений на Akavache.

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

Если вы хотите загрузить заполнитель, который хранится в ресурсах вашего Android-проекта - в этом нет необходимости. Вы можете просто реализовать собственный хук в GlideExtensions класс glidex.forms (я вам тоже покажу). Но если вы хотите загрузить изображение из Xamarin.Forms ресурса или даже из шрифта, нам нужно немного расширить класс GlideExtensions.

Кстати, я попытался использовать существующий механизм реализации IGlideHandler для этих целей, но из-за проблем с синхронизацией мне так и не удалось загрузить такие заполнители, и я пошел дальше, расширив класс GlideExtensions.

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

Используйте ресурс Android

Давайте сначала посмотрим, как загрузить ресурс Android в качестве заполнителя (потому что это самый простой способ). Для этого нам просто нужно создать собственную реализацию IGlideHandler в проекте Android, который затем будет вызываться реализацией GlideExtensions:

public class GlideWithAndroidResourcePlaceholder : IGlideHandler
{
    public GlideWithAndroidResourcePlaceholder()
    {
    }

    public bool Build(ImageView imageView, ImageSource source, RequestBuilder builder, CancellationToken token)
    {
        if (builder != null)
        {
            //easiest way - add the image to Android resources ....
            //general placeholder:
            //builder.Placeholder(Resource.Drawable.MSicc_Logo_Base_Blue_1024px_pad25).Into(imageView);

            //error placeholder:
            builder.Error(Resource.Drawable.MSicc_Logo_Base_Blue_1024px_pad25).Into(imageView);

            return true;
        }
        else
            return false;
    }
}

Как видите, в RequestBuilder уже есть механизм заполнителя. Мы просто подключаемся к этому. Если вам нужен общий заполнитель (изображение отображается также во время загрузки), используйте метод Placeholder. Только при неудачной загрузке изображения используйте Error method. Вот и все.

Используйте Xamarin.Forms resouce / FontImageSource

Однако, поскольку мы хотим иметь возможность загружать ресурсы FontImageSource и Xamarin.Forms, нам нужно пойти другим путем. Как и в случае с iOS, нам нужно добавить свойство-заполнитель в класс Forms:

public static ImageSource? PlaceholderImageSource { get; private set; }

Чтобы заполнить наш ImageSource либо Xamarin.Forms ресурсом, либо FontImageSource, добавьте также эти два метода:

public static void PlaceholderFromResource (string resourceName, Assembly assembly) =>
    PlaceholderImageSource = ImageSource.FromResource (resourceName, assembly);

public static void PlaceholderFromFontImageSource (FontImageSource fontImageSource) =>
    PlaceholderImageSource = fontImageSource;

Теперь, когда у нас есть PlaceholderImageSource, нам нужно расширить класс GlideExtensions. Сначала мы реализуем обработчик для FontImageSource. Обработчик Xamarin.Forms для FontImageSource предоставляет нам растровое изображение, которое мы собираемся использовать в качестве заполнителя. У меня это работает только с методом AsDrawable, метод AsBitmap всегда выдает исключение, потому что он не может преобразовать Bitmap в Drawable (я не исследовал это дальше).

private static async Task<RequestBuilder?> HandleFontImageSource (RequestManager request, Context? context, FontImageSource fontImageSource, CancellationToken token, Func<bool> cancelled)
{
    if (context == null)
        return null;

    var defaultHandler = new Xamarin.Forms.Platform.Android.FontImageSourceHandler ();

    var bitmap = await defaultHandler.LoadImageAsync (fontImageSource, context, token);

    if (token.IsCancellationRequested || cancelled())
        return null;

    if (bitmap == null)
        return null;

    return request.AsDrawable().Load (bitmap);
}

Что касается метода HandleFontImageSource, мне также нужно было изменить возвращаемое значение метода HandleStreamImageSource, чтобы использовать метод AsDrawable, иначе мы получим то же исключение, что и с FontImageSource:

static async Task<RequestBuilder?> HandleStreamImageSource (RequestManager request, StreamImageSource source, CancellationToken token, Func<bool> cancelled) { //code omitted for readability return request.AsDrawable().Load (memoryStream.ToArray ()); }

Последние шаги, чтобы заставить все это работать, выполняются LoadViaGlide методом. Сначала добавьте еще одну переменную RequestBuilder? и назовите ее errorBuilder:

RequestBuilder? errorBuilder = null;

После переключателя, который обрабатывает параметр source, добавьте следующие строки кода:

switch(Forms.PlaceholderImageSource) { case StreamImageSource streamSource: errorBuilder = await HandleStreamImageSource (request, streamSource, token, () => !IsActivityAlive (imageView, Forms.PlaceholderImageSource)); break; case FontImageSource fontImageSource: errorBuilder = await HandleFontImageSource(request, imageView.Context, fontImageSource, token, () => !IsActivityAlive (imageView, Forms.PlaceholderImageSource)); break; default: errorBuilder = null; break; } if (errorBuilder != null) builder?.Error (errorBuilder);

Мы обращаемся с нашим PlaceholderImageSource так же, как с ImageSource, который мы собираемся загрузить. Если у нас есть действительный errorBuilder, мы передаем его всему процессу. С этим у нас уже все на месте. Давайте посмотрим, как использовать это в вашем приложении.

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

Перейдите к классу MainActivity в своем проекте Android и добавьте следующий метод:

private void AttachGlide() { Android.Glide.Forms.Init(this, null, false); //recommended way of loading resource images=> //Android.Glide.Forms.Init(this, new GlideWithAndroidResourcePlaceholder(), false); //Xamarin Forms resource image //Android.Glide.Forms.PlaceholderFromResource("CachedImageTest.MSicc_Logo_Base_Blue_1024px_pad25.png", Assembly.GetAssembly(typeof(MainViewModel))); //FontImageSource Android.Glide.Forms.PlaceholderFromFontImageSource(new FontImageSource { Glyph = XfNativeCachedImages.Resources.MaterialDesignIcons.ImageBroken, FontFamily = "MaterialDesignIcons", Color = Xamarin.Forms.Color.Red }); }

Библиотеку Glide нужно инициализировать. В зависимости от того, какой метод вы используете, это можно сделать по-разному. Вышеупомянутый метод показывает их все, вам просто нужно изменить закомментированный код, чтобы поэкспериментировать с ним в образце (ссылка в конце сообщения). Механизм похож на тот, который я использовал для iOS и пакета Nuke.

Если вы последовали (или загрузили образец), вы должны увидеть результат, аналогичный следующему:

Вывод

Как и в случае с iOS, теперь мы также используем собственное кэширование и обработку изображений в Android. На то, чтобы запустить его, у меня ушло немало времени, но оно того стоило. Образец содержит более пятисот удаленных изображений, загруженных в CollectionView. Проверьте, насколько плавная прокрутка (даже с DataBinding!).

Вы можете найти образец здесь на Github, а модифицированная версия glidex.forms доступна здесь. Как всегда, я надеюсь, что этот пост будет полезен для некоторых из вас.

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

Первоначально опубликовано на https://msicc.net 26 марта 2021 г.