This commit is contained in:
Wiesław Šoltés 2023-06-05 21:48:38 +02:00
Родитель fd4c6ff283
Коммит 3b2b6e22ef
4 изменённых файлов: 142 добавлений и 99 удалений

Просмотреть файл

@ -108,6 +108,70 @@ public class Lottie : Control
_baseUri = serviceProvider.GetContextBaseUri(); _baseUri = serviceProvider.GetContextBaseUri();
} }
/// <inheritdoc/>
protected override void OnLoaded()
{
base.OnLoaded();
var elemVisual = ElementComposition.GetElementVisual(this);
var compositor = elemVisual?.Compositor;
if (compositor is null)
{
return;
}
_customVisual = compositor.CreateCustomVisual(new LottieCompositionCustomVisualHandler());
ElementComposition.SetElementChildVisual(this, _customVisual);
LayoutUpdated += OnLayoutUpdated;
if (_preloadPath is null)
{
return;
}
DisposeImpl();
Load(_preloadPath);
_customVisual.Size = new Vector2((float)Bounds.Size.Width, (float)Bounds.Size.Height);
_customVisual.SendHandlerMessage(
new LottiePayload(
LottieCommand.Update,
_animation,
Stretch,
StretchDirection));
Start();
_preloadPath = null;
}
protected override void OnUnloaded()
{
base.OnUnloaded();
LayoutUpdated -= OnLayoutUpdated;
Stop();
DisposeImpl();
}
private void OnLayoutUpdated(object? sender, EventArgs e)
{
if (_customVisual == null)
{
return;
}
_customVisual.Size = new Vector2((float)Bounds.Size.Width, (float)Bounds.Size.Height);
_customVisual.SendHandlerMessage(
new LottiePayload(
LottieCommand.Update,
_animation,
Stretch,
StretchDirection));
}
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
if (_animation == null) if (_animation == null)
@ -122,52 +186,6 @@ public class Lottie : Control
return Stretch.CalculateSize(availableSize, sourceSize, StretchDirection); return Stretch.CalculateSize(availableSize, sourceSize, StretchDirection);
} }
protected override void OnLoaded()
{
var elemVisual = ElementComposition.GetElementVisual(this);
var compositor = elemVisual?.Compositor;
if (compositor is null)
{
return;
}
_customVisual = compositor.CreateCustomVisual(new LottieCustomVisualHandler());
ElementComposition.SetElementChildVisual(this, _customVisual);
LayoutUpdated += OnLayoutUpdated;
base.OnLoaded();
if (_preloadPath is null)
{
return;
}
DisposeImpl();
Load(_preloadPath);
_customVisual.Size = new Vector2((float)Bounds.Size.Width, (float)Bounds.Size.Height);
_customVisual.SendHandlerMessage(new LottieCustomVisualHandler.Payload(
LottieCustomVisualHandler.Command.Update,
_animation,
Stretch,
StretchDirection));
Start();
_preloadPath = null;
}
private void OnLayoutUpdated(object sender, EventArgs e)
{
if (_customVisual == null) return;
_customVisual.Size = new Vector2((float)Bounds.Size.Width, (float)Bounds.Size.Height);
_customVisual.SendHandlerMessage(
new LottieCustomVisualHandler.Payload(
LottieCustomVisualHandler.Command.Update,
_animation,
Stretch,
StretchDirection));
}
protected override Size ArrangeOverride(Size finalSize) protected override Size ArrangeOverride(Size finalSize)
{ {
if (_animation == null) if (_animation == null)
@ -212,12 +230,6 @@ public class Lottie : Control
} }
} }
private void Stop()
{
_customVisual?.SendHandlerMessage(
new LottieCustomVisualHandler.Payload(LottieCustomVisualHandler.Command.Stop));
}
private SkiaSharp.Skottie.Animation? Load(Stream stream) private SkiaSharp.Skottie.Animation? Load(Stream stream)
{ {
using var managedStream = new SKManagedStream(stream); using var managedStream = new SKManagedStream(stream);
@ -227,12 +239,13 @@ public class Lottie : Control
Logger Logger
.TryGet(LogEventLevel.Information, LogArea.Control)? .TryGet(LogEventLevel.Information, LogArea.Control)?
.Log(this, .Log(this, $"Version: {animation.Version} Duration: {animation.Duration} Fps:{animation.Fps} InPoint: {animation.InPoint} OutPoint: {animation.OutPoint}");
$"Version: {animation.Version} Duration: {animation.Duration} Fps:{animation.Fps} InPoint: {animation.InPoint} OutPoint: {animation.OutPoint}");
} }
else else
{ {
Logger.TryGet(LogEventLevel.Warning, LogArea.Control)?.Log(this, "Failed to load animation."); Logger
.TryGet(LogEventLevel.Warning, LogArea.Control)?
.Log(this, "Failed to load animation.");
} }
return animation; return animation;
@ -240,7 +253,9 @@ public class Lottie : Control
private SkiaSharp.Skottie.Animation? Load(string path, Uri? baseUri) private SkiaSharp.Skottie.Animation? Load(string path, Uri? baseUri)
{ {
var uri = path.StartsWith("/") ? new Uri(path, UriKind.Relative) : new Uri(path, UriKind.RelativeOrAbsolute); var uri = path.StartsWith("/")
? new Uri(path, UriKind.Relative)
: new Uri(path, UriKind.RelativeOrAbsolute);
if (uri.IsAbsoluteUri && uri.IsFile) if (uri.IsAbsoluteUri && uri.IsFile)
{ {
using var fileStream = File.OpenRead(uri.LocalPath); using var fileStream = File.OpenRead(uri.LocalPath);
@ -264,7 +279,6 @@ public class Lottie : Control
if (path is null) if (path is null)
{ {
DisposeImpl(); DisposeImpl();
return; return;
} }
@ -274,6 +288,7 @@ public class Lottie : Control
{ {
_repeatCount = RepeatCount; _repeatCount = RepeatCount;
_animation = Load(path, _baseUri); _animation = Load(path, _baseUri);
if (_animation is null) if (_animation is null)
{ {
return; return;
@ -286,21 +301,31 @@ public class Lottie : Control
} }
catch (Exception e) catch (Exception e)
{ {
Logger.TryGet(LogEventLevel.Warning, LogArea.Control)?.Log(this, "Failed to load animation: " + e); Logger
.TryGet(LogEventLevel.Warning, LogArea.Control)?
.Log(this, "Failed to load animation: " + e);
_animation = null; _animation = null;
} }
} }
private void DisposeImpl()
{
_customVisual?.SendHandlerMessage(
new LottieCustomVisualHandler.Payload(LottieCustomVisualHandler.Command.Dispose));
}
private void Start() private void Start()
{ {
_customVisual?.SendHandlerMessage(new LottieCustomVisualHandler.Payload(LottieCustomVisualHandler.Command.Start, _customVisual?.SendHandlerMessage(
_animation, new LottiePayload(
Stretch, StretchDirection, _repeatCount)); LottieCommand.Start,
_animation,
Stretch,
StretchDirection,
_repeatCount));
}
private void Stop()
{
_customVisual?.SendHandlerMessage(new LottiePayload(LottieCommand.Stop));
}
private void DisposeImpl()
{
_customVisual?.SendHandlerMessage(new LottiePayload(LottieCommand.Dispose));
} }
} }

Просмотреть файл

@ -0,0 +1,9 @@
namespace Avalonia.Skia.Lottie;
internal enum LottieCommand
{
Start,
Stop,
Update,
Dispose
}

Просмотреть файл

@ -6,7 +6,7 @@ using SkiaSharp;
namespace Avalonia.Skia.Lottie; namespace Avalonia.Skia.Lottie;
internal class LottieCustomVisualHandler : CompositionCustomVisualHandler internal class LottieCompositionCustomVisualHandler : CompositionCustomVisualHandler
{ {
private TimeSpan _primaryTimeElapsed, _animationElapsed; private TimeSpan _primaryTimeElapsed, _animationElapsed;
private TimeSpan? _lastServerTime; private TimeSpan? _lastServerTime;
@ -19,35 +19,24 @@ internal class LottieCustomVisualHandler : CompositionCustomVisualHandler
private int _repeatCount; private int _repeatCount;
private int _count; private int _count;
public enum Command
{
Start,
Stop,
Update,
Dispose
}
public record struct Payload(
Command Command,
SkiaSharp.Skottie.Animation? Animation = null,
Stretch? Stretch = null,
StretchDirection? StretchDirection = null,
int? RepeatCount = null);
public override void OnMessage(object message) public override void OnMessage(object message)
{ {
if (message is not Payload msg) return; if (message is not LottiePayload msg)
{
return;
}
switch (msg) switch (msg)
{ {
case case
{ {
Command: Command.Start, LottieCommand: LottieCommand.Start,
Animation: { } an, Animation: { } an,
Stretch: { } st, Stretch: { } st,
StretchDirection: { } sd, StretchDirection: { } sd,
RepeatCount: { } rp RepeatCount: { } rp
}: }:
{
_running = true; _running = true;
_lastServerTime = null; _lastServerTime = null;
_stretch = st; _stretch = st;
@ -58,24 +47,37 @@ internal class LottieCustomVisualHandler : CompositionCustomVisualHandler
_animationElapsed = TimeSpan.Zero; _animationElapsed = TimeSpan.Zero;
RegisterForNextAnimationFrameUpdate(); RegisterForNextAnimationFrameUpdate();
break; break;
}
case case
{ {
Command: Command.Update, LottieCommand: LottieCommand.Update,
Stretch: { } st, Stretch: { } st,
StretchDirection: { } sd StretchDirection: { } sd
}: }:
{
_stretch = st; _stretch = st;
_stretchDirection = sd; _stretchDirection = sd;
RegisterForNextAnimationFrameUpdate(); RegisterForNextAnimationFrameUpdate();
break; break;
case {Command: Command.Stop}: }
case
{
LottieCommand: LottieCommand.Stop
}:
{
_running = false; _running = false;
_animationElapsed = TimeSpan.Zero; _animationElapsed = TimeSpan.Zero;
_count = 0; _count = 0;
break; break;
case {Command: Command.Dispose}: }
case
{
LottieCommand: LottieCommand.Dispose
}:
{
DisposeImpl(); DisposeImpl();
break; break;
}
} }
} }
@ -95,7 +97,6 @@ internal class LottieCustomVisualHandler : CompositionCustomVisualHandler
RegisterForNextAnimationFrameUpdate(); RegisterForNextAnimationFrameUpdate();
} }
private void DisposeImpl() private void DisposeImpl()
{ {
lock (_sync) lock (_sync)
@ -128,7 +129,7 @@ internal class LottieCustomVisualHandler : CompositionCustomVisualHandler
return frameTime; return frameTime;
} }
private void SkottieDraw(SKCanvas canvas) private void Draw(SKCanvas canvas)
{ {
var animation = _animation; var animation = _animation;
if (animation is null) if (animation is null)
@ -158,14 +159,8 @@ internal class LottieCustomVisualHandler : CompositionCustomVisualHandler
var dst = new SKRect(0, 0, animation.Size.Width, animation.Size.Height); var dst = new SKRect(0, 0, animation.Size.Width, animation.Size.Height);
animation.SeekFrameTime(t, ic); animation.SeekFrameTime(t, ic);
// Debug.WriteLine($"dst: {dst}, ic.Bounds: {ic.Bounds}");
canvas.Save(); canvas.Save();
animation.Render(canvas, dst); animation.Render(canvas, dst);
// canvas.DrawRect(ic.Bounds, new SKPaint { Color = SKColors.Magenta, Style = SKPaintStyle.Stroke, StrokeWidth = 1 });
canvas.Restore(); canvas.Restore();
ic.Reset(); ic.Reset();
@ -187,8 +182,12 @@ internal class LottieCustomVisualHandler : CompositionCustomVisualHandler
_lastServerTime = CompositionNow; _lastServerTime = CompositionNow;
} }
if (_animation is not { } an
if (_animation is not { } an || _stretch is not { } st || _stretchDirection is not { } sd) return; || _stretch is not { } st
|| _stretchDirection is not { } sd)
{
return;
}
var leaseFeature = context.TryGetFeature<ISkiaSharpApiLeaseFeature>(); var leaseFeature = context.TryGetFeature<ISkiaSharpApiLeaseFeature>();
@ -231,7 +230,7 @@ internal class LottieCustomVisualHandler : CompositionCustomVisualHandler
{ {
return; return;
} }
SkottieDraw(canvas); Draw(canvas);
} }
} }
} }

Просмотреть файл

@ -0,0 +1,10 @@
using Avalonia.Media;
namespace Avalonia.Skia.Lottie;
internal record struct LottiePayload(
LottieCommand LottieCommand,
SkiaSharp.Skottie.Animation? Animation = null,
Stretch? Stretch = null,
StretchDirection? StretchDirection = null,
int? RepeatCount = null);