111 lines
3.4 KiB
C#
111 lines
3.4 KiB
C#
|
|
using Avalonia.Animation.Easings;
|
|||
|
|
using Avalonia.Animation;
|
|||
|
|
using Avalonia;
|
|||
|
|
using Avalonia.Controls;
|
|||
|
|
using Avalonia.Xaml.Interactivity;
|
|||
|
|
using Irihi.Avalonia.Shared.Helpers;
|
|||
|
|
using Avalonia.Controls.Presenters;
|
|||
|
|
using Avalonia.Data;
|
|||
|
|
using Avalonia.Media;
|
|||
|
|
using Avalonia.Styling;
|
|||
|
|
|
|||
|
|
|
|||
|
|
namespace Plugin.Cowain.Wcs.Controls;
|
|||
|
|
|
|||
|
|
public class GridColumnAnimationBehavior : Behavior<Grid>
|
|||
|
|
{
|
|||
|
|
private IDisposable? _columnSubscription;
|
|||
|
|
|
|||
|
|
public static readonly StyledProperty<int> GridColumnProperty =
|
|||
|
|
AvaloniaProperty.Register<GridColumnAnimationBehavior, int>(
|
|||
|
|
nameof(GridColumn),
|
|||
|
|
defaultBindingMode: BindingMode.TwoWay);
|
|||
|
|
|
|||
|
|
public int GridColumn
|
|||
|
|
{
|
|||
|
|
get => GetValue(GridColumnProperty);
|
|||
|
|
set => SetValue(GridColumnProperty, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void OnAttached()
|
|||
|
|
{
|
|||
|
|
base.OnAttached();
|
|||
|
|
|
|||
|
|
if (AssociatedObject is not null)
|
|||
|
|
{
|
|||
|
|
// 开始监听布局更新或直接触发初始动画
|
|||
|
|
AssociatedObject.AttachedToVisualTree += HandleAttached;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void OnDetaching()
|
|||
|
|
{
|
|||
|
|
if (AssociatedObject is not null)
|
|||
|
|
{
|
|||
|
|
AssociatedObject.AttachedToVisualTree -= HandleAttached;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_columnSubscription?.Dispose();
|
|||
|
|
base.OnDetaching();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void HandleAttached(object? sender, VisualTreeAttachmentEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (AssociatedObject is Grid grid && grid.Parent is ContentPresenter contentPresenter)
|
|||
|
|
{
|
|||
|
|
// 使用绑定监听Grid.Column变化
|
|||
|
|
_columnSubscription = contentPresenter.GetObservable(Grid.ColumnProperty)
|
|||
|
|
.Subscribe(column =>
|
|||
|
|
{
|
|||
|
|
if (column != GridColumn)
|
|||
|
|
{
|
|||
|
|
AnimateColumnChange(grid, column, GridColumn);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void AnimateColumnChange(Grid grid, int fromColumn, int toColumn)
|
|||
|
|
{
|
|||
|
|
var contentPresenter = grid.Parent as ContentPresenter;
|
|||
|
|
if (contentPresenter == null) return;
|
|||
|
|
|
|||
|
|
// 创建水平移动动画
|
|||
|
|
var transform = new TranslateTransform();
|
|||
|
|
contentPresenter.RenderTransform = transform;
|
|||
|
|
|
|||
|
|
var _animation = new Animation
|
|||
|
|
{
|
|||
|
|
Duration = TimeSpan.FromSeconds(0.3),
|
|||
|
|
Easing = new CubicEaseInOut(),
|
|||
|
|
Children =
|
|||
|
|
{
|
|||
|
|
new KeyFrame
|
|||
|
|
{
|
|||
|
|
Cue = new Cue(0d),
|
|||
|
|
Setters =
|
|||
|
|
{
|
|||
|
|
new Setter
|
|||
|
|
{
|
|||
|
|
Property = TranslateTransform.XProperty,
|
|||
|
|
Value = fromColumn * -grid.ColumnDefinitions[fromColumn].ActualWidth
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
new KeyFrame
|
|||
|
|
{
|
|||
|
|
Cue = new Cue(1d),
|
|||
|
|
Setters =
|
|||
|
|
{
|
|||
|
|
new Setter
|
|||
|
|
{
|
|||
|
|
Property = TranslateTransform.XProperty,
|
|||
|
|
Value = toColumn * -grid.ColumnDefinitions[toColumn].ActualWidth
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
_animation.RunAsync(contentPresenter);
|
|||
|
|
}
|
|||
|
|
}
|