CompositeTransition.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using Avalonia;
  6. using Avalonia.Animation;
  7. using Avalonia.Animation.Easings;
  8. using Avalonia.Media;
  9. using Avalonia.Styling;
  10. using Avalonia.VisualTree;
  11. namespace ControlCatalog.Pages
  12. {
  13. /// <summary>
  14. /// Example custom IPageTransition: horizontal slide combined with cross-fade.
  15. /// Both pages slide and fade simultaneously for a smooth blended effect.
  16. /// </summary>
  17. public class CompositeTransition : IPageTransition
  18. {
  19. public CompositeTransition() { }
  20. public CompositeTransition(TimeSpan duration)
  21. {
  22. Duration = duration;
  23. }
  24. public TimeSpan Duration { get; set; } = TimeSpan.FromMilliseconds(300);
  25. public Easing TransitionEasing { get; set; } = new LinearEasing();
  26. public async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
  27. {
  28. if (cancellationToken.IsCancellationRequested)
  29. return;
  30. var tasks = new List<Task>();
  31. var parent = GetVisualParent(from, to);
  32. var distance = parent.Bounds.Width > 0 ? parent.Bounds.Width : 500d;
  33. if (from != null)
  34. {
  35. var anim = new Avalonia.Animation.Animation
  36. {
  37. FillMode = FillMode.Forward,
  38. Easing = TransitionEasing,
  39. Duration = Duration,
  40. Children =
  41. {
  42. new KeyFrame
  43. {
  44. Cue = new Cue(0d),
  45. Setters =
  46. {
  47. new Setter(TranslateTransform.XProperty, 0d),
  48. new Setter(Visual.OpacityProperty, 1d)
  49. }
  50. },
  51. new KeyFrame
  52. {
  53. Cue = new Cue(1d),
  54. Setters =
  55. {
  56. new Setter(TranslateTransform.XProperty, forward ? -distance : distance),
  57. new Setter(Visual.OpacityProperty, 0d)
  58. }
  59. }
  60. }
  61. };
  62. tasks.Add(anim.RunAsync(from, cancellationToken));
  63. }
  64. if (to != null)
  65. {
  66. to.IsVisible = true;
  67. var anim = new Avalonia.Animation.Animation
  68. {
  69. FillMode = FillMode.Forward,
  70. Easing = TransitionEasing,
  71. Duration = Duration,
  72. Children =
  73. {
  74. new KeyFrame
  75. {
  76. Cue = new Cue(0d),
  77. Setters =
  78. {
  79. new Setter(TranslateTransform.XProperty, forward ? distance : -distance),
  80. new Setter(Visual.OpacityProperty, 0d)
  81. }
  82. },
  83. new KeyFrame
  84. {
  85. Cue = new Cue(1d),
  86. Setters =
  87. {
  88. new Setter(TranslateTransform.XProperty, 0d),
  89. new Setter(Visual.OpacityProperty, 1d)
  90. }
  91. }
  92. }
  93. };
  94. tasks.Add(anim.RunAsync(to, cancellationToken));
  95. }
  96. await Task.WhenAll(tasks);
  97. if (from != null && !cancellationToken.IsCancellationRequested)
  98. from.IsVisible = false;
  99. }
  100. private static Visual GetVisualParent(Visual? from, Visual? to)
  101. {
  102. var p1 = (from ?? to)!.GetVisualParent();
  103. if (from != null && to != null &&
  104. !ReferenceEquals(from.GetVisualParent(), to.GetVisualParent()))
  105. throw new ArgumentException("Transition elements have different parents.");
  106. return p1 ?? throw new ArgumentException("Transition elements have no parent.");
  107. }
  108. }
  109. }