Skip to content

Commit 2e80cf6

Browse files
authored
[LottieGen] Added IAnimatedVisual2 implementation preview. (#477)
1 parent ad04ccc commit 2e80cf6

File tree

8 files changed

+255
-48
lines changed

8 files changed

+255
-48
lines changed

source/LottieToWinComp/Transforms.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#nullable enable
66

7+
using System;
78
using System.Diagnostics.CodeAnalysis;
89
using Microsoft.Toolkit.Uwp.UI.Lottie.Animatables;
910
using Microsoft.Toolkit.Uwp.UI.Lottie.LottieData;
@@ -225,9 +226,11 @@ public static bool TryCreateContainerShapeTransformChain(
225226
{
226227
// Set initial value to be non-visible (default is visible).
227228
visibilityNode.Scale = Sn.Vector2.Zero;
228-
visibilityAnimation.InsertKeyFrame(inProgress, Sn.Vector2.One, context.ObjectFactory.CreateHoldThenStepEasingFunction());
229+
visibilityAnimation.InsertKeyFrame(0.0f, Sn.Vector2.Zero, context.ObjectFactory.CreateHoldThenStepEasingFunction());
229230
}
230231

232+
visibilityAnimation.InsertKeyFrame(Math.Max(0.0f, inProgress), Sn.Vector2.One, context.ObjectFactory.CreateHoldThenStepEasingFunction());
233+
231234
if (outProgress < 1)
232235
{
233236
visibilityAnimation.InsertKeyFrame(outProgress, Sn.Vector2.Zero, context.ObjectFactory.CreateHoldThenStepEasingFunction());
@@ -336,16 +339,18 @@ static void InsertVisibilityVisualIntoTransformChain(
336339
{
337340
// Set initial value to be non-visible.
338341
visibilityNode.IsVisible = false;
339-
visibilityAnimation.InsertKeyFrame(inProgress, true);
342+
visibilityAnimation.InsertKeyFrame(0.0f, false);
340343
}
341344

345+
visibilityAnimation.InsertKeyFrame(Math.Max(0.0f, inProgress), true);
346+
342347
if (outProgress < 1)
343348
{
344349
visibilityAnimation.InsertKeyFrame(outProgress, false);
345350
}
346351

347352
visibilityAnimation.Duration = context.LottieComposition.Duration;
348-
Animate.WithKeyFrame(context, visibilityNode, "IsVisible", visibilityAnimation);
353+
Animate.WithKeyFrame(context, visibilityNode, nameof(visibilityNode.IsVisible), visibilityAnimation);
349354
}
350355
}
351356

source/UIData/Tools/GraphCompactor.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -826,15 +826,7 @@ void ApplyVisibility(Visual to, VisibilityDescription fromVisibility, Compositio
826826

827827
foreach (var (isVisible, progress) in compositeVisibility.Sequence)
828828
{
829-
if (progress == 0)
830-
{
831-
// The 0 progress value is already handled.
832-
continue;
833-
}
834-
else
835-
{
836-
animation.InsertKeyFrame(progress, isVisible);
837-
}
829+
animation.InsertKeyFrame(progress, isVisible);
838830
}
839831

840832
to.StartAnimation("IsVisible", animation);

source/UIDataCodeGen/CodeGen/CSharp/CSharpInstantiatorGenerator.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,15 @@ void WriteSetPropertyImpl(
727727
protected override void WriteAnimatedVisualStart(CodeBuilder builder, IAnimatedVisualInfo info)
728728
{
729729
// Start the instantiator class.
730-
builder.WriteLine($"sealed class {info.ClassName} : {Interface_IAnimatedVisual.GetQualifiedName(_s)}");
730+
if (info.ImplementCreateAndDestroyMethods)
731+
{
732+
builder.WriteLine($"sealed class {info.ClassName} : {Interface_IAnimatedVisual2.GetQualifiedName(_s)}");
733+
}
734+
else
735+
{
736+
builder.WriteLine($"sealed class {info.ClassName} : {Interface_IAnimatedVisual.GetQualifiedName(_s)}");
737+
}
738+
731739
builder.OpenScope();
732740
}
733741

@@ -750,7 +758,9 @@ IEnumerable<string> GetConstructorParameters(IAnimatedVisualInfo info)
750758
// Called by the base class to write the end of the AnimatedVisual class.
751759
protected override void WriteAnimatedVisualEnd(
752760
CodeBuilder builder,
753-
IAnimatedVisualInfo info)
761+
IAnimatedVisualInfo info,
762+
CodeBuilder createAnimations,
763+
CodeBuilder destroyAnimations)
754764
{
755765
// Write the constructor for the AnimatedVisual class.
756766
builder.WriteLine($"internal {info.ClassName}(");
@@ -787,6 +797,21 @@ protected override void WriteAnimatedVisualEnd(
787797
builder.WriteLine("void IDisposable.Dispose() => _root?.Dispose();");
788798
builder.WriteLine();
789799

800+
if (info.ImplementCreateAndDestroyMethods)
801+
{
802+
builder.WriteLine($"public void {CreateAnimationsMethod}()");
803+
builder.OpenScope();
804+
builder.WriteCodeBuilder(createAnimations);
805+
builder.CloseScope();
806+
builder.WriteLine();
807+
808+
builder.WriteLine($"public void {DestroyAnimationsMethod}()");
809+
builder.OpenScope();
810+
builder.WriteCodeBuilder(destroyAnimations);
811+
builder.CloseScope();
812+
builder.WriteLine();
813+
}
814+
790815
// WinUI3 doesn't ever do a version check. It's up to the user to make sure
791816
// the version they're using is compatible.
792817
if (SourceInfo.WinUIVersion.Major < 3)
@@ -1042,13 +1067,20 @@ IEnumerable<string> GetConstructorArguments(IAnimatedVisualInfo info)
10421067

10431068
void WriteInstantiateAndReturnAnimatedVisual(CodeBuilder builder, IAnimatedVisualInfo info)
10441069
{
1045-
builder.WriteLine("return");
1070+
builder.WriteLine("var res = ");
10461071
builder.Indent();
10471072
builder.WriteLine($"new {info.ClassName}(");
10481073
builder.Indent();
10491074
builder.WriteCommaSeparatedLines(GetConstructorArguments(info));
10501075
builder.WriteLine(");");
10511076
builder.UnIndent();
1077+
1078+
if (info.ImplementCreateAndDestroyMethods)
1079+
{
1080+
builder.WriteLine($"res.{CreateAnimationsMethod}();");
1081+
}
1082+
1083+
builder.WriteLine("return res;");
10521084
builder.UnIndent();
10531085
}
10541086
}

source/UIDataCodeGen/CodeGen/CodegenConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,5 +113,7 @@ Version winUIVersion
113113
/// The version of WinUI to target.
114114
/// </summary>
115115
public Version WinUIVersion { get; set; }
116+
117+
public bool ImplementCreateAndDestroyMethods => WinUIVersion >= Version.Parse("2.7");
116118
}
117119
}

source/UIDataCodeGen/CodeGen/Cppwinrt/CppwinrtInstantiatorGenerator.cs

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ sealed class CppwinrtInstantiatorGenerator : InstantiatorGeneratorBase
3939
// from the TryCreateAnimatedVisual method.
4040
readonly string _animatedVisualTypeName;
4141

42+
readonly string _animatedVisualTypeName2;
43+
4244
// True iff the generated code implements IDynamicAnimatedVisualSource.
4345
readonly bool _isIDynamic;
4446

@@ -99,6 +101,7 @@ public static CppwinrtCodegenResult CreateFactoryCode(CodegenConfiguration confi
99101
_sourceClassName = SourceInfo.ClassName;
100102

101103
_animatedVisualTypeName = Interface_IAnimatedVisual.GetQualifiedName(_s);
104+
_animatedVisualTypeName2 = Interface_IAnimatedVisual2.GetQualifiedName(_s);
102105
}
103106

104107
static string FieldAssignment(string fieldName) => fieldName is not null ? $"{fieldName} = " : string.Empty;
@@ -497,7 +500,16 @@ protected override void WriteAnimatedVisualStart(
497500
builder.WriteLine($"class {info.ClassName} : public winrt::implements<{info.ClassName},");
498501
builder.Indent();
499502
builder.Indent();
500-
builder.WriteLine($"winrt::{_animatedVisualTypeName},");
503+
504+
if (info.ImplementCreateAndDestroyMethods)
505+
{
506+
builder.WriteLine($"winrt::{_animatedVisualTypeName2},");
507+
}
508+
else
509+
{
510+
builder.WriteLine($"winrt::{_animatedVisualTypeName},");
511+
}
512+
501513
builder.WriteLine($"IClosable>");
502514
builder.UnIndent();
503515
builder.UnIndent();
@@ -1069,16 +1081,27 @@ void WriteInstantiateHighestCompatibleAnimatedVisual(
10691081
if (SourceInfo.WinUIVersion.Major >= 3)
10701082
{
10711083
var info = animatedVisualInfos.First();
1072-
builder.WriteBreakableLine($"return winrt::make<{info.ClassName}>(", CommaSeparate(GetConstructorArguments(info)), ");");
1084+
builder.WriteBreakableLine($"auto result = winrt::make<{info.ClassName}>(", CommaSeparate(GetConstructorArguments(info)), ");");
1085+
if (info.ImplementCreateAndDestroyMethods)
1086+
{
1087+
builder.WriteLine($"result.{CreateAnimationsMethod}();");
1088+
}
1089+
1090+
builder.WriteLine("return result;");
10731091
}
10741092
else
10751093
{
10761094
foreach (var info in animatedVisualInfos.OrderByDescending(avi => avi.RequiredUapVersion))
10771095
{
1078-
builder.WriteLine();
10791096
builder.WriteLine($"if ({info.ClassName}::IsRuntimeCompatible())");
10801097
builder.OpenScope();
1081-
builder.WriteBreakableLine($"return winrt::make<{info.ClassName}>(", CommaSeparate(GetConstructorArguments(info)), ");");
1098+
builder.WriteBreakableLine($"auto result = winrt::make<{info.ClassName}>(", CommaSeparate(GetConstructorArguments(info)), ");");
1099+
if (info.ImplementCreateAndDestroyMethods)
1100+
{
1101+
builder.WriteLine($"result.{CreateAnimationsMethod}();");
1102+
}
1103+
1104+
builder.WriteLine("return result;");
10821105
builder.CloseScope();
10831106
}
10841107

@@ -1265,7 +1288,9 @@ void WriteIsRuntimeCompatibleMethod(CodeBuilder builder, IAnimatedVisualInfo inf
12651288
// Called by the base class to write the end of the AnimatedVisual class.
12661289
protected override void WriteAnimatedVisualEnd(
12671290
CodeBuilder builder,
1268-
IAnimatedVisualInfo info)
1291+
IAnimatedVisualInfo info,
1292+
CodeBuilder createAnimations,
1293+
CodeBuilder destroyAnimations)
12691294
{
12701295
if (SourceInfo.UsesCanvasEffects ||
12711296
SourceInfo.UsesCanvasGeometry)
@@ -1345,6 +1370,21 @@ protected override void WriteAnimatedVisualEnd(
13451370
WritePropertyImpl(builder, "float2", "Size", propertyImplBuilder);
13461371
}
13471372

1373+
if (info.ImplementCreateAndDestroyMethods)
1374+
{
1375+
builder.WriteLine($"void {CreateAnimationsMethod}()");
1376+
builder.OpenScope();
1377+
builder.WriteCodeBuilder(createAnimations);
1378+
builder.CloseScope();
1379+
builder.WriteLine();
1380+
1381+
builder.WriteLine($"void {DestroyAnimationsMethod}()");
1382+
builder.OpenScope();
1383+
builder.WriteCodeBuilder(destroyAnimations);
1384+
builder.CloseScope();
1385+
builder.WriteLine();
1386+
}
1387+
13481388
WriteIsRuntimeCompatibleMethod(builder, info);
13491389

13501390
// Close the scope for the instantiator class.

source/UIDataCodeGen/CodeGen/Cx/CxInstantiatorGenerator.cs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ sealed class CxInstantiatorGenerator : InstantiatorGeneratorBase
3636
// from the TryCreateAnimatedVisual method.
3737
readonly string _animatedVisualTypeName;
3838

39+
readonly string _animatedVisualTypeName2;
40+
3941
/// <summary>
4042
/// Returns the Cx code for a factory that will instantiate the given <see cref="Visual"/> as a
4143
/// Windows.UI.Composition Visual.
@@ -68,6 +70,7 @@ public static CxCodegenResult CreateFactoryCode(CodegenConfiguration configurati
6870
_wuc = $"{_winUINamespace}::Composition";
6971
_sourceClassName = SourceInfo.ClassName;
7072
_animatedVisualTypeName = Interface_IAnimatedVisual.GetQualifiedName(_s);
73+
_animatedVisualTypeName2 = Interface_IAnimatedVisual2.GetQualifiedName(_s);
7174

7275
// Temporary until IAnimatedVisualSource2 makes it into WinUI3.
7376
_isAnimatedIcon = SourceInfo.WinUIVersion >= new Version(2, 6) && SourceInfo.WinUIVersion.Major < 3;
@@ -449,7 +452,16 @@ protected override void WriteAnimatedVisualStart(
449452
// Start writing the instantiator.
450453
builder.WriteLine($"ref class {info.ClassName} sealed");
451454
builder.Indent();
452-
builder.WriteLine($": public {_animatedVisualTypeName}");
455+
456+
if (info.ImplementCreateAndDestroyMethods)
457+
{
458+
builder.WriteLine($": public {_animatedVisualTypeName2}");
459+
}
460+
else
461+
{
462+
builder.WriteLine($": public {_animatedVisualTypeName}");
463+
}
464+
453465
builder.UnIndent();
454466
builder.OpenScope();
455467

@@ -994,7 +1006,13 @@ void WriteInstantiateHighestCompatibleAnimatedVisual(
9941006
if (SourceInfo.WinUIVersion.Major >= 3)
9951007
{
9961008
var info = animatedVisualInfos.First();
997-
builder.WriteBreakableLine($"return {_s.New(info.ClassName)}(", CommaSeparate(GetConstructorArguments(info)), ");");
1009+
builder.WriteBreakableLine($"auto result = {_s.New(info.ClassName)}(", CommaSeparate(GetConstructorArguments(info)), ");");
1010+
if (info.ImplementCreateAndDestroyMethods)
1011+
{
1012+
builder.WriteLine($"result.{CreateAnimationsMethod}();");
1013+
}
1014+
1015+
builder.WriteLine("return result;");
9981016
}
9991017
else
10001018
{
@@ -1003,7 +1021,13 @@ void WriteInstantiateHighestCompatibleAnimatedVisual(
10031021
builder.WriteLine();
10041022
builder.WriteLine($"if ({info.ClassName}::IsRuntimeCompatible())");
10051023
builder.OpenScope();
1006-
builder.WriteBreakableLine($"return {_s.New(info.ClassName)}(", CommaSeparate(GetConstructorArguments(info)), ");");
1024+
builder.WriteBreakableLine($"auto result = {_s.New(info.ClassName)}(", CommaSeparate(GetConstructorArguments(info)), ");");
1025+
if (info.ImplementCreateAndDestroyMethods)
1026+
{
1027+
builder.WriteLine($"result.{CreateAnimationsMethod}();");
1028+
}
1029+
1030+
builder.WriteLine("return result;");
10071031
builder.CloseScope();
10081032
}
10091033

@@ -1157,7 +1181,9 @@ void WriteIsRuntimeCompatibleMethod(CodeBuilder builder, IAnimatedVisualInfo inf
11571181
// Called by the base class to write the end of the AnimatedVisual class.
11581182
protected override void WriteAnimatedVisualEnd(
11591183
CodeBuilder builder,
1160-
IAnimatedVisualInfo info)
1184+
IAnimatedVisualInfo info,
1185+
CodeBuilder createAnimations,
1186+
CodeBuilder destroyAnimations)
11611187
{
11621188
if (SourceInfo.UsesCanvasEffects ||
11631189
SourceInfo.UsesCanvasGeometry)
@@ -1246,6 +1272,21 @@ protected override void WriteAnimatedVisualEnd(
12461272
WritePropertyImpl(builder, isVirtual: true, "float2", "Size", propertyImplBuilder);
12471273
}
12481274

1275+
if (info.ImplementCreateAndDestroyMethods)
1276+
{
1277+
builder.WriteLine($"public void {CreateAnimationsMethod}()");
1278+
builder.OpenScope();
1279+
builder.WriteCodeBuilder(createAnimations);
1280+
builder.CloseScope();
1281+
builder.WriteLine();
1282+
1283+
builder.WriteLine($"public void {DestroyAnimationsMethod}()");
1284+
builder.OpenScope();
1285+
builder.WriteCodeBuilder(destroyAnimations);
1286+
builder.CloseScope();
1287+
builder.WriteLine();
1288+
}
1289+
12491290
WriteIsRuntimeCompatibleMethod(builder, info);
12501291

12511292
// Close the scope for the instantiator class.

source/UIDataCodeGen/CodeGen/IAnimatedVisualInfo.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ interface IAnimatedVisualInfo
2424
/// </summary>
2525
uint RequiredUapVersion { get; }
2626

27+
/// <summary>
28+
/// Do we need to implement CreateAnimations and DestroyAnimations method.
29+
/// Available after WinUI 2.7 with new interface IAnimatedVisual2.
30+
/// </summary>
31+
bool ImplementCreateAndDestroyMethods { get; }
32+
2733
/// <summary>
2834
/// Gets the XAML LoadedImageSurface nodes of the AnimatedVisual.
2935
/// </summary>

0 commit comments

Comments
 (0)