我想知道是否有任何类可以使用GridLength
设置KeyFrames
值的动画?我看过以下网站,但没有一个网站使用KeyFrames
:
有什么建议吗?
答案 0 :(得分:1)
创建附加行为并为其设置动画。
当然,GridLength显然不是数字类型,因此不清楚它是如何动画的。为了证明我可以创建一个附加的行为,如:
public class AnimatableProperties
{
public static readonly DependencyProperty WidthProperty =
DependencyProperty.RegisterAttached("Width",
typeof(double),
typeof(DependencyObject),
new PropertyMetadata(-1, (o, e) =>
{
AnimatableProperties.OnWidthChanged((Grid)o, (double)e.NewValue);
}));
public static void SetWidth(DependencyObject o,
double e)
{
o.SetValue(AnimatableProperties.WidthProperty, e);
}
public static double GetWidth(DependencyObject o)
{
return (double)o.GetValue(AnimatableProperties.WidthProperty);
}
private static void OnWidthChanged(DependencyObject target,
double e)
{
target.SetValue(Grid.WidthProperty, new GridLength(e));
}
}
这将重新生成网格宽度作为double类型的数字属性。有了它,你可以自由地为它设置动画。
P.S。显然,使用Grid的宽度并没有太大意义,因为它已经加倍了。任何其他基于GridLength的属性都可以根据上面的示例使用双包装器进行编程,然后通过该包装器进行动画处理。
答案 1 :(得分:0)
这是相当直接的,但您需要使用适配器,因为您不能使用DoubleAnimator直接为ColumnDefinition类上的Width设置动画,因为ColumnDefinition不是double。这是我的代码:
public class ColumnDefinitionDoubleAnimationAdapter : Control
{
#region Dependency Properties
public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(nameof(Width), typeof(double), typeof(ColumnDefinitionDoubleAnimationAdapter), new PropertyMetadata((double)0, WidthChanged));
private static void WidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var columnDefinitionDoubleAnimationAdapter = (ColumnDefinitionDoubleAnimationAdapter)d;
columnDefinitionDoubleAnimationAdapter.Width = (double)e.NewValue;
}
#endregion
#region Fields
private ColumnDefinition _ColumnDefinition;
#endregion
#region Constructor
public ColumnDefinitionDoubleAnimationAdapter(ColumnDefinition columnDefinition)
{
_ColumnDefinition = columnDefinition;
}
#endregion
#region Public Properties
public double Width
{
get
{
return (double)GetValue(WidthProperty);
}
set
{
SetValue(WidthProperty, value);
_ColumnDefinition.Width = new GridLength(value);
}
}
#endregion
}
不幸的是,上面的效率非常低,因为它会一次又一次地创建一个GridLength,因为ColumnDefinition.Width.Value应该是只读的。
这是一种动画制作方法。使用基于任务的异步非常重要,否则故事板将超出范围并导致不良行为。无论如何这是一个好习惯,所以如果你需要,你可以等待动画:
public async static Task AnimateColumnWidth(ColumnDefinition columnDefinition, double from, double to, TimeSpan duration, IEasingFunction ease)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
var storyboard = new Storyboard();
var animation = new DoubleAnimation();
animation.EasingFunction = ease;
animation.Duration = new Duration(duration);
storyboard.Children.Add(animation);
animation.From = from;
animation.To = to;
var columnDefinitionDoubleAnimationAdapter = new ColumnDefinitionDoubleAnimationAdapter(columnDefinition);
Storyboard.SetTarget(animation, columnDefinitionDoubleAnimationAdapter);
Storyboard.SetTargetProperty(animation, new PropertyPath(ColumnDefinitionDoubleAnimationAdapter.WidthProperty));
storyboard.Completed += (a, b) =>
{
taskCompletionSource.SetResult(true);
};
storyboard.Begin();
await taskCompletionSource.Task;
}
一个示例用法:
private async void TheMenu_HamburgerToggled(object sender, EventArgs e)
{
TheMenu.IsOpen = !TheMenu.IsOpen;
var twoSeconds = TimeSpan.FromMilliseconds(120);
var ease = new CircleEase { EasingMode = TheMenu.IsOpen ? EasingMode.EaseIn : EasingMode.EaseOut };
if (TheMenu.IsOpen)
{
await UIUtilities.AnimateColumnWidth(MenuColumn, 40, 320, twoSeconds, ease);
}
else
{
await UIUtilities.AnimateColumnWidth(MenuColumn, 320, 40, twoSeconds, ease);
}
}