4

我找了这个特别的东西,因为我觉得它很重要而且很令人费解,但是我没有找到任何关于这件事的东西。我正在考虑的是 WPF 和 Silverlight 动画中的时间缩放。

假设我们有一个持续 4 秒的 DoubleAnimation 并在 0 到 100 之间设置一个属性的动画。它是自动反转的,或者有一个互补动画可以反转它的效果,这并不重要。假设触发这个动画的事件是一个简单的 MouseOver。

这就是问题所在:我将光标悬停在一个元素上。该属性在 4 秒内从 0 变为 100。我将光标移开 1 秒,属性从 100 变为 75,然后我将鼠标悬停回来。现在该属性在 4 秒内从 75 变为 100。对用户来说很明显,动画运行速度慢了 4 倍。有没有办法缩放动画的时间?如果我想让这个动画在 1 秒内从 75 运行到 100,我会怎么做?我自己可能正在考虑一个转换器,它需要四个参数(绝对开始和结束、实际开始和整个间隔的时间跨度),然后吐出适当的时间。有没有更优雅的方式?

我注意到当动画很快时这通常不是问题。当动画运行在 0.2s 或 0.1s 时,人类并没有真正观察到速度上的差异,也许所有的动画都应该尽可能快,以免恶化体验。但是请从理论上处理这个问题(因此没有代码示例)。我只是好奇是否有任何适当的方法来缩放动画时间。

如果在网络上的某个地方有我的问题的答案,请直接把我带到那里。

帕维尔

PS不要介意我的英语,我不是母语人士;)

4

3 回答 3

0

在让动画以您描述的方式线性表现时,我遇到了同样的问题。我找不到在 XAML 中使用 WPF 触发器而无需编写代码隐藏的解决方案。

然后我开始使用VisualStateManager而不是触发器(在 WPF 4 和 Silverlight 中受支持)。所有动画的表现都与您期望的一样!

我建议使用 Expression Blend 4 来使用 VisualStateManager,因为使用 UI 配置对象的各种状态只需要几秒钟。

于 2012-07-27T09:18:35.253 回答
0

我做了更多的研究。看来,缩放动画时间的唯一好方法是使用 MultiConverter,它接受边界值(例如我之前示例中的 0 和 100)、动画属性的当前值以及完整动画的运行时间(例如我的例子中的4s)。然后它应该计算应该做多少百分比的动画(所以如果当前值是75,并且全范围是0-100,那么剩下25%的动画),返回值应该是前面提到的百分比原始时间跨度(4s 的 25% 是 1s)。也许这不是实现目标的最优雅的方式,但它似乎应该工作。

于 2012-06-05T14:15:06.160 回答
0

我知道这不是您确切问题的答案,但解决此问题的一种方法是捕获MouseEnterand MouseLeave,检查当前动画状态并暂停或恢复它:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="AnimationTest.MainPage"
    Width="640" Height="480">
    <UserControl.Resources>
        <Storyboard x:Name="Rotate" AutoReverse="True">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" Storyboard.TargetName="textBlock">
                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:4" Value="100"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock x:Name="textBlock" Margin="197,216,200,215" TextWrapping="Wrap" Text="My Funky Text" FontSize="32" RenderTransformOrigin="0.5,0.5" MouseEnter="textBlock_MouseEnter" MouseLeave="textBlock_MouseLeave">
            <TextBlock.RenderTransform>
                <CompositeTransform/>
            </TextBlock.RenderTransform>
        </TextBlock>
    </Grid>
</UserControl>

代码:

private void textBlock_MouseEnter(object sender, MouseEventArgs e)
{
    var state = Rotate.GetCurrentState();
    if (state == ClockState.Stopped || state == ClockState.Filling) { Rotate.Begin(); } else Rotate.Resume();
}

private void textBlock_MouseLeave(object sender, MouseEventArgs e)
{
    Rotate.Pause();
}
于 2012-06-05T07:28:53.083 回答