WPF/SL动画时间缩放

4

我寻找这个特定的事情,因为我认为它是相当重要且令人困惑的问题,但我没有在这方面找到任何东西。我考虑的是WPF和Silverlight动画中的时间缩放。

假设我们有一个持续4秒的DoubleAnimation,将属性从0动画到100。它是自动反转的,或者有一个补充动画来反转其效果,这并不重要。假设触发此动画的事件是简单的鼠标悬停。

问题在于:我将光标悬停在元素上。属性在4秒内从0到100。我将光标移开1秒钟,属性从100到75,然后我再次悬停。现在属性在4秒内从75到100。对于用户来说,很明显动画运行得慢了4倍。是否有任何方法可以缩放动画的时间?如果我想让此动画在1秒内从75到100运行,该怎么办呢?我自己想到了一种可能的解决方案,即创建一个转换器,它会接受四个参数(绝对开始和结束、实际开始和整个间隔的时间跨度),然后输出正确的时间。是否有更优雅的方式?

我注意到,当动画速度很快时,通常不会出现问题。当动画在0.2秒或0.1秒内运行时,人类实际上无法观察到速度差异,也许所有动画都应尽可能快以不降低体验。但请理论上考虑这个问题(因此没有代码示例)。我只是好奇是否有任何适当的方法可以缩放动画时间。

如果在web上有答案,请直接指引我去看。

Paweł

附言:不要介意我的英语,我不是母语使用者;)

3个回答

0

我曾经遇到过与您描述的相同问题,即如何使动画呈线性行为。在不编写代码的情况下,我无法使用XAML中的WPF触发器找到解决方案。

然后我开始使用VisualStateManager而不是触发器(它支持WPF 4和Silverlight)。所有的动画都表现得完美,就像您期望的那样!

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


0
我做了更多的研究。似乎缩放动画时间的唯一好方法是使用MultiConverter,它需要输入边界值(例如前面的例子中的0和100)、动画属性的当前值以及完整动画的运行时间(例如我的例子中的4秒)。然后应该计算完成了动画的百分比(例如当前值为75,而全范围为0-100,则剩余25%的动画),并且返回值应该是原始时间跨度的前述百分比(4s的25%为1s)。也许这不是实现目标最优雅的方式,但它看起来应该能够工作。

0

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

<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();
}

谢谢,但正如你自己所说 - 这并没有回答我的具体问题 :) - Paweł Motyl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接