Browse Source

Add minor performance improvements.

Include rotate 3d transition for carousel control.
pull/7402/head
Jan-Peter Zurek 4 years ago
parent
commit
e5758fc073
  1. 1
      samples/ControlCatalog/Pages/CarouselPage.xaml
  2. 3
      samples/ControlCatalog/Pages/CarouselPage.xaml.cs
  3. 6
      src/Avalonia.Visuals/Animation/PageSlide.cs
  4. 153
      src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs
  5. 24
      src/Avalonia.Visuals/Media/Rotate3DTransform.cs

1
samples/ControlCatalog/Pages/CarouselPage.xaml

@ -29,6 +29,7 @@
<ComboBoxItem>None</ComboBoxItem>
<ComboBoxItem>Slide</ComboBoxItem>
<ComboBoxItem>Crossfade</ComboBoxItem>
<ComboBoxItem>3D Rotation</ComboBoxItem>
</ComboBox>
</StackPanel>

3
samples/ControlCatalog/Pages/CarouselPage.xaml.cs

@ -45,6 +45,9 @@ namespace ControlCatalog.Pages
case 2:
_carousel.PageTransition = new CrossFade(TimeSpan.FromSeconds(0.25));
break;
case 3:
_carousel.PageTransition = new Rotate3DTransition(TimeSpan.FromSeconds(0.5), _orientation.SelectedIndex == 0 ? PageSlide.SlideAxis.Horizontal : PageSlide.SlideAxis.Vertical);
break;
}
}
}

6
src/Avalonia.Visuals/Animation/PageSlide.cs

@ -10,7 +10,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Animation
{
/// <summary>
/// Transitions between two pages by sliding them horizontally.
/// Transitions between two pages by sliding them horizontally or vertically.
/// </summary>
public class PageSlide : IPageTransition
{
@ -62,7 +62,7 @@ namespace Avalonia.Animation
public Easing SlideOutEasing { get; set; } = new LinearEasing();
/// <inheritdoc />
public async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
public virtual async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
@ -155,7 +155,7 @@ namespace Avalonia.Animation
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
private static IVisual GetVisualParent(IVisual? from, IVisual? to)
protected static IVisual GetVisualParent(IVisual? from, IVisual? to)
{
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;

153
src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs

@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Media;
using Avalonia.Styling;
namespace Avalonia.Animation;
public class Rotate3DTransition: PageSlide
{
/// <summary>
/// Creates a new instance if the <see cref="Rotate3DTransition"/>
/// </summary>
/// <param name="duration">How long the rotation should take place</param>
/// <param name="orientation">The orientation of the rotation</param>
public Rotate3DTransition(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal)
: base(duration, orientation)
{}
/// <summary>
/// Creates a new instance if the <see cref="Rotate3DTransition"/>
/// </summary>
public Rotate3DTransition() { }
/// <inheritdoc />
public override async Task Start(Visual? @from, Visual? to, bool forward, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
var tasks = new List<Task>();
var parent = GetVisualParent(from, to);
var (rotateProperty, center) = Orientation switch
{
SlideAxis.Vertical => (Rotate3DTransform.AngleXProperty, parent.Bounds.Height),
SlideAxis.Horizontal => (Rotate3DTransform.AngleYProperty, parent.Bounds.Width),
_ => throw new ArgumentOutOfRangeException()
};
var depthSetter = new Setter {Property = Rotate3DTransform.DepthProperty, Value = center};
var centerZSetter = new Setter {Property = Rotate3DTransform.CenterZProperty, Value = -center / 2};
if (from != null)
{
var animation = new Animation
{
Duration = Duration,
Children =
{
new KeyFrame
{
Setters =
{
new Setter { Property = rotateProperty, Value = 0d },
new Setter { Property = Visual.ZIndexProperty, Value = 2 },
centerZSetter,
depthSetter,
},
Cue = new Cue(0d)
},
new KeyFrame
{
Setters =
{
new Setter { Property = rotateProperty, Value = 45d * (forward ? -1 : 1) },
new Setter { Property = Visual.ZIndexProperty, Value = 1 },
centerZSetter,
depthSetter
},
Cue = new Cue(0.5d)
},
new KeyFrame
{
Setters =
{
new Setter { Property = rotateProperty, Value = 90d * (forward ? -1 : 1) },
new Setter { Property = Visual.ZIndexProperty, Value = 1 },
centerZSetter,
depthSetter
},
Cue = new Cue(1d)
}
}
};
tasks.Add(animation.RunAsync(from, null, cancellationToken));
}
if (to != null)
{
to.IsVisible = true;
var animation = new Animation
{
Duration = Duration,
Children =
{
new KeyFrame
{
Setters =
{
new Setter { Property = rotateProperty, Value = 90d * (forward ? 1 : -1) },
new Setter { Property = Visual.ZIndexProperty, Value = 1 },
centerZSetter,
depthSetter
},
Cue = new Cue(0d)
},
new KeyFrame
{
Setters =
{
new Setter { Property = Visual.ZIndexProperty, Value = 1 },
new Setter { Property = rotateProperty, Value = 45d * (forward ? 1 : -1) },
centerZSetter,
depthSetter
},
Cue = new Cue(0.5d)
},
new KeyFrame
{
Setters =
{
new Setter { Property = rotateProperty, Value = 0d },
new Setter { Property = Visual.ZIndexProperty, Value = 2 },
centerZSetter,
depthSetter,
},
Cue = new Cue(1d)
}
}
};
tasks.Add(animation.RunAsync(to, null, cancellationToken));
}
await Task.WhenAll(tasks);
if (from != null && !cancellationToken.IsCancellationRequested)
{
from.IsVisible = false;
from.ZIndex = 1;
}
if (to != null && !cancellationToken.IsCancellationRequested)
{
to.ZIndex = 2;
}
}
}

24
src/Avalonia.Visuals/Media/Rotate3DTransform.cs

@ -9,6 +9,8 @@ namespace Avalonia.Media;
/// </summary>
public class Rotate3DTransform : Transform
{
private readonly bool _isInitializing;
/// <summary>
/// Defines the <see cref="AngleX"/> property.
/// </summary>
@ -76,12 +78,14 @@ public class Rotate3DTransform : Transform
double centerY,
double centerZ) : this()
{
_isInitializing = true;
AngleX = angleX;
AngleY = angleY;
AngleZ = angleZ;
CenterX = centerX;
CenterY = centerY;
CenterZ = centerZ;
_isInitializing = false;
}
/// <summary>
@ -148,21 +152,22 @@ public class Rotate3DTransform : Transform
}
/// <summary>
/// Gets the transform's <see cref="Matrix"/>.
/// Gets the transform's <see cref="Matrix"/>.
/// </summary>
public override Matrix Value
{
get
{
var matrix44 = Matrix4x4.Identity;
var centerSum = CenterX + CenterY + CenterZ;
if (centerSum != 0) matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ);
matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ);
if (AngleX != 0) matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(AngleX));
if (AngleY != 0) matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(AngleY));
if (AngleZ != 0) matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(AngleZ));
matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(AngleX));
matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(AngleY));
matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(AngleZ));
matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ);
if (centerSum != 0) matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ);
if (Depth != 0)
{
@ -186,5 +191,8 @@ public class Rotate3DTransform : Transform
}
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) => RaiseChanged();
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
if (!_isInitializing) RaiseChanged();
}
}

Loading…
Cancel
Save