gpt4 book ai didi

c# - 如何使动画的持续时间动态化?

转载 作者:行者123 更新时间:2023-11-30 18:13:24 26 4
gpt4 key购买 nike

假设我们有一个动画,当用户将光标移到矩形上时,它会将矩形的宽度从 50 更改为 150,并在用户移动光标时从 150 更改为 50离开。让每个动画的持续时间为 1 秒

如果用户将光标移到矩形上,一切正常,然后等待 1 秒动画完成,然后将光标移离矩形。两个动画总共需要 2 秒,它们的速度正是我们所期望的。

但是如果用户在第一个动画 (50 -> 150) 完成之前将光标移开,第二个动画的持续时间将为 1 秒,但速度会很慢。我的意思是,第二个动画将使矩形的宽度不是从 150 到 50 而是从 120 到 50 或从 70 到 50 动画,如果你很快就把光标移开了。但是对于同样的 1 秒!

所以我想了解的是如何使“向后”动画的持续时间动态。动态基于第一个动画停止的时间点。或者,如果我将 FromTo 值指定为 150 和 50,将 Duration 指定为 1 秒并且矩形宽度将为 100 – WPF 将计算为动画本身已经完成了 50%。

我正在测试使用动画的不同方式,例如触发器、样式中的 EventTrigger 和 VisualStateGroups,但没有成功。

这是一个显示我的问题的 XAML 示例。如果您想自己看看我在说什么,请将光标移到矩形上,等待 1-2 秒(第一个动画完成),然后将光标移开。之后,将光标移到矩形上大约 0.25 秒,然后将其移开。您会看到矩形的宽度变化非常缓慢。

<Rectangle Width="50"
Height="100"
HorizontalAlignment="Left"
Fill="Black">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
To="150"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>

此外,我想解释一下我希望看到的计算结果。因此,让我们想象另一个从 100 到 1100 并且持续时间为 2 秒 的动画。如果我们在 300 处停止它,它必须开始回到 100 但不会持续 2 秒,而是:

((300 - 100) / (1100 - 100)) * 2s = 0.4s

如果我们在 900 处停止,持续时间将为:

((900 - 100) / (1100 - 100)) * 2s = 1.6s

如果我们让动画正常结束,它将是:

((1100 - 100) / (1100 - 100)) * 2s = 2s

最佳答案

WPF 提供了编写自定义动画的可能性。

您可以使用 MinSpeed 属性创建一个:

public class MinSpeedDoubleAnimation : DoubleAnimation
{
public static readonly DependencyProperty MinSpeedProperty =
DependencyProperty.Register(
nameof(MinSpeed), typeof(double?), typeof(MinSpeedDoubleAnimation));

public double? MinSpeed
{
get { return (double?)GetValue(MinSpeedProperty); }
set { SetValue(MinSpeedProperty, value); }
}

protected override Freezable CreateInstanceCore()
{
return new MinSpeedDoubleAnimation();
}

protected override double GetCurrentValueCore(
double defaultOriginValue, double defaultDestinationValue,
AnimationClock animationClock)
{
var destinationValue = To ?? defaultDestinationValue;
var originValue = From ?? defaultOriginValue;
var duration = Duration != Duration.Automatic ? Duration :
animationClock.NaturalDuration;
var speed = (destinationValue - originValue) / duration.TimeSpan.TotalSeconds;

if (MinSpeed.HasValue && Math.Abs(speed) < MinSpeed)
{
speed = Math.Sign(speed) * MinSpeed.Value;
}

var value = originValue + speed * animationClock.CurrentTime.Value.TotalSeconds;

return speed > 0 ?
Math.Min(destinationValue, value) :
Math.Max(destinationValue, value);
}
}

并像这样使用它:

<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Width"
To="150" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<local:MinSpeedDoubleAnimation
Storyboard.TargetProperty="Width"
To="50" MinSpeed="100"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>

为了完整起见,这里也是最简单的代码隐藏解决方案,没有任何触发器和 Storyboard :

<Rectangle Width="50" Height="100" HorizontalAlignment="Left" Fill="Black" 
MouseEnter="RectangleMouseEnter" MouseLeave="RectangleMouseLeave"/>

使用这些事件处理程序:

private void RectangleMouseEnter(object sender, MouseEventArgs e)
{
var element = (FrameworkElement)sender;
var animation = new DoubleAnimation(150, TimeSpan.FromSeconds(1));
element.BeginAnimation(FrameworkElement.WidthProperty, animation);
}

private void RectangleMouseLeave(object sender, MouseEventArgs e)
{
var element = (FrameworkElement)sender;
var duration = (element.ActualWidth - 50) / 100;
var animation = new DoubleAnimation(50, TimeSpan.FromSeconds(duration));
element.BeginAnimation(FrameworkElement.WidthProperty, animation);
}

关于c# - 如何使动画的持续时间动态化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52540425/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com