|
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Android.Widget;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.Platform;
using ARect = Android.Graphics.Rect;
using AScaleType = Android.Widget.ImageView.ScaleType;
using AViewCompat = AndroidX.Core.View.ViewCompat;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Android.FastRenderers
{
public static class ImageElementManager
{
public static void Init(IVisualElementRenderer renderer)
{
renderer.ElementPropertyChanged += OnElementPropertyChanged;
renderer.ElementChanged += OnElementChanged;
if (renderer is ILayoutChanges layoutChanges)
layoutChanges.LayoutChange += OnLayoutChange;
}
static void OnLayoutChange(object sender, global::Android.Views.View.LayoutChangeEventArgs e)
{
if (sender is IVisualElementRenderer renderer && renderer.View is ImageView imageView)
#pragma warning disable CS0618 // Obsolete
AViewCompat.SetClipBounds(imageView, imageView.GetScaleType() == AScaleType.CenterCrop ? new ARect(0, 0, e.Right - e.Left, e.Bottom - e.Top) : null);
#pragma warning restore CS0618 // Obsolete
}
public static void Dispose(IVisualElementRenderer renderer)
{
renderer.ElementPropertyChanged -= OnElementPropertyChanged;
renderer.ElementChanged -= OnElementChanged;
if (renderer is ILayoutChanges layoutChanges)
layoutChanges.LayoutChange -= OnLayoutChange;
if (renderer is IImageRendererController imageRenderer)
imageRenderer.SetFormsAnimationDrawable(null);
if (renderer.View is ImageView imageView)
{
imageView.SetImageDrawable(null);
imageView.Reset();
}
}
async static void OnElementChanged(object sender, VisualElementChangedEventArgs e)
{
var renderer = (sender as IVisualElementRenderer);
var view = renderer.View as ImageView;
var newImageElementManager = e.NewElement as IImageElement;
var oldImageElementManager = e.OldElement as IImageElement;
var rendererController = renderer as IImageRendererController;
if (rendererController.IsDisposed)
return;
await TryUpdateBitmap(rendererController, view, newImageElementManager, oldImageElementManager);
if (rendererController.IsDisposed)
return;
UpdateAspect(rendererController, view, newImageElementManager, oldImageElementManager);
if (rendererController.IsDisposed)
return;
ElevationHelper.SetElevation(view, renderer.Element);
}
async static void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var renderer = (sender as IVisualElementRenderer);
var ImageElementManager = (IImageElement)renderer.Element;
var imageController = (IImageController)renderer.Element;
if (renderer?.View?.LayoutParameters == null && (renderer is ILayoutChanges lc && lc.HasLayoutOccurred))
{
return;
}
if (e.IsOneOf(Image.SourceProperty, Button.ImageSourceProperty))
{
await TryUpdateBitmap(renderer as IImageRendererController, (ImageView)renderer.View, (IImageElement)renderer.Element).ConfigureAwait(false);
}
else if (e.Is(Image.AspectProperty))
{
UpdateAspect(renderer as IImageRendererController, (ImageView)renderer.View, (IImageElement)renderer.Element);
}
else if (e.Is(Image.IsAnimationPlayingProperty))
await StartStopAnimation(renderer, imageController, ImageElementManager).ConfigureAwait(false);
}
async static Task StartStopAnimation(
IVisualElementRenderer renderer,
IImageController imageController,
IImageElement imageElement)
{
IImageRendererController imageRendererController = renderer as IImageRendererController;
var view = renderer.View as ImageView;
if (imageRendererController.IsDisposed || imageElement == null || view == null || view.IsDisposed())
return;
if (imageElement.IsLoading)
return;
if (!(view.Drawable is FormsAnimationDrawable) && imageElement.IsAnimationPlaying)
await TryUpdateBitmap(imageRendererController, view, imageElement);
if (view.Drawable is FormsAnimationDrawable animation)
{
if (imageElement.IsAnimationPlaying && !animation.IsRunning)
animation.Start();
else if (!imageElement.IsAnimationPlaying && animation.IsRunning)
animation.Stop();
}
}
async static Task TryUpdateBitmap(IImageRendererController rendererController, ImageView Control, IImageElement newImage, IImageElement previous = null)
{
if (newImage == null || rendererController.IsDisposed)
{
return;
}
if (Control.Drawable is FormsAnimationDrawable currentAnimation)
{
rendererController.SetFormsAnimationDrawable(currentAnimation);
currentAnimation.Stop();
}
else
{
rendererController.SetFormsAnimationDrawable(null);
}
try
{
await Control.UpdateBitmap(newImage, previous).ConfigureAwait(false);
}
catch (Exception ex)
{
Application.Current?.FindMauiContext()?.CreateLogger<IImageRendererController>()?.LogWarning(ex, "Error loading image");
}
finally
{
if (newImage is IImageController imageController)
imageController.SetIsLoading(false);
}
if (rendererController.IsDisposed)
return;
if (Control.Drawable is FormsAnimationDrawable updatedAnimation)
{
rendererController.SetFormsAnimationDrawable(updatedAnimation);
if (newImage.IsAnimationPlaying)
updatedAnimation.Start();
}
}
internal static void OnAnimationStopped(IElementController image, FormsAnimationDrawableStateEventArgs e)
{
if (image != null && e.Finished)
image.SetValueFromRenderer(Image.IsAnimationPlayingProperty, false);
}
static void UpdateAspect(IImageRendererController rendererController, ImageView Control, IImageElement newImage, IImageElement previous = null)
{
if (newImage == null || rendererController.IsDisposed)
{
return;
}
ImageView.ScaleType type = newImage.Aspect.ToScaleType();
Control.SetScaleType(type);
}
}
} |