• [UWP]使用离散式关键帧播放动画


    这篇文章介绍离散式关键帧,并使用它做些有趣的动画。

    1. 什么是离散式关键帧

    以DoubleAnimationUsingKeyFrames为例,它支持四种Double的关键帧,其中EasingDoubleKeyFrame、LinearDoubleKeyFrame和SplineDoubleKeyFrame可以归类为连续式关键帧,而DiscreteDoubleKeyFrame则是离散式关键帧。

    DoubleAnimationUsingKeyFrames包含一个关键帧的集合,动画开始后,每当达到某个关键帧指定的Time,动画的值也会同时到达这个关键帧指定的Value。下面这段XAML介绍了一个典型的LinearDoubleKeyFrame的用法:

    <StackPanel>
        <StackPanel.Resources>
            <Storyboard x:Name="myStoryboard">
                <DoubleAnimationUsingKeyFrames
                  Storyboard.TargetName="myRectangle"
                  Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
                    <LinearDoubleKeyFrame Value="1" KeyTime="0:0:0"/>
                    <LinearDoubleKeyFrame Value="1.2" KeyTime="0:0:4"/>
                    <LinearDoubleKeyFrame Value="2" KeyTime="0:0:5"/>
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
        </StackPanel.Resources>
    </StackPanel>
    

    对于连续式的关键帧,两个关键帧之间会进行插值,以上面的XAML为例,当动画运行到4.5秒的时候,DobuleAnimationUsingKeyFrames会根据第二和第三个LinearDoubleKeyFrame的值计算出1.6作为内插的值赋予目标属性ScaleY。EasingDoubleKeyFrame和SplineDoubleKeyFrame也是相同的原理,只是它们的插值计算方式复杂一些。

    而离散式关键帧不同,它用在不能插值的数据类型, 例如True/False、Visible/Collapsed这些数据类型,它们之间没有过渡,只能用离散的方式设置值。一段典型的DiscreteObjectKeyFrame示例如下:

    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalRoot" Storyboard.TargetProperty="Visibility">
        <DiscreteObjectKeyFrame KeyTime="0:0:0">
            <DiscreteObjectKeyFrame.Value>
                <Visibility>Collapsed</Visibility>
            </DiscreteObjectKeyFrame.Value>
        </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
    

    2. 了解下电影的原理

    在电影里,一幅静止的图像被称作一“格”(Frame),只要达到每秒24格,人们的眼睛就会被欺骗,以为看到的是运动的画面。人的双眼及其数据传输系统每秒可以识别10-12格画面,大脑的视觉处理中心会将每格画面保留1/15秒。如果在前一格画面尚且保留的1/15秒内大脑又收到一幅新的画面,那么就产生了画面在连续运动的感觉,这是电影得以实现的认知学基础。

    3. 用DiscreteDoubleKeyFrame播放动画

    DiscreteObjectKeyFrame是最常用的离散式关键帧,UWP还提供了其它三种离散式关键帧:DiscreteColorKeyFrame、DiscreteDoubleKeyFrame和DiscretePointKeyFrame。如果不是追求动画效果,日常工作中DiscreteDoubleKeyFrame基本上没什么作为(在Github上DiscreteObjectKeyFrame有132K的搜索结果,DiscreteDoubleKeyFrame只有17K)。但只要了解了电影的原理,配合设计师的话DiscreteDoubleKeyFrame也可以大展拳脚。

    <ScrollViewer Background="Transparent"
                  VerticalScrollBarVisibility="Disabled"
                  HorizontalScrollBarVisibility="Disabled">
        <Grid  Width="2900">
            <Image  Stretch="None"
                    AutomationProperties.AccessibilityView="Raw"
                    Source="/Assets/Images/heart.png"
                    Height="100"
                    Loaded="OnHeartLoaded"
                    RenderTransformOrigin="0.5,0.5">
                <Image.RenderTransform>
                    <CompositeTransform />
                </Image.RenderTransform>
            </Image>
        </Grid>
    </ScrollViewer>
    

    上面的XAML是一个Like按钮(模仿某个不存在的网站)的ControlTemplate,ScrollViewer用于裁剪超出范围的内容,里面包含一张由29张100 X 100的图片拼接而成的长图片:

    private Storyboard _checkStoryboard;
    private CompositeTransform _heartTransform;
    
    private void OnHeartLoaded(object sender, RoutedEventArgs e)
    {
        _heartTransform = (sender as Image).RenderTransform as CompositeTransform;
        _checkStoryboard = new Storyboard();
    
    
        var keyFrames = new DoubleAnimationUsingKeyFrames();
        Storyboard.SetTarget(keyFrames, _heartTransform);
        Storyboard.SetTargetProperty(keyFrames, nameof(CompositeTransform.TranslateX));
        TimeSpan start = TimeSpan.Zero;
        for (var i = 0; i < 28; i++)
        {
            var keyFrame = new DiscreteDoubleKeyFrame
            {
                KeyTime = TimeSpan.FromSeconds((i + 1d) / 28d),
                Value = -(i + 1) * 100
            };
            keyFrames.KeyFrames.Add(keyFrame);
        }
    
        _checkStoryboard.Children.Add(keyFrames);
    
        _checkStoryboard.FillBehavior = FillBehavior.HoldEnd;
    }
    
    private void OnChecked(object sender, RoutedEventArgs e)
    {
        _checkStoryboard.Begin();
    }
    
    

    在CodeBehind的OnChecked函数中启动一个Storybord,使用DiscreteDoubleKeyFrame让Image在一秒内向左平移100像素,这样就达到了播放动画的效果:

    换一张Demo试试,这次使用了12帧每秒,看上去就有点卡顿:

    4. 结语

    这篇文章的代码在WPF和UWP上的实现几乎一样,有兴趣的话也可以在WPF上试试。

    LikeButton的动画抄自Codepen,在CSS中离散动画实现起来很简洁:

    .heart {
       100px;
      height: 100px;
      background: url("https://cssanimation.rocks/images/posts/steps/heart.png") no-repeat;
      background-position: 0 0;
      cursor: pointer;
      transition: background-position 1s steps(28);
      transition-duration: 0s;
      
      &.is-active {
        transition-duration: 1s;
        background-position: -2800px 0;
      }
    }
    

    更多关于steps的内容可参考下面这篇文章
    CSS3 animation属性中的steps功能符深入介绍

    5. 参考

    情节提要动画 - UWP applications Microsoft Docs

    关键帧动画以及缓动函数动画 - UWP applications Microsoft Docs

    DiscreteDoubleKeyFrame Class (Windows.UI.Xaml.Media.Animation) - Windows UWP applications Microsoft Docs

    6. 源码

    design_and_animation_lab

  • 相关阅读:
    Git查询
    HDU-3038 How Many Answers Are Wrong 并查集
    CodeForcesEducationalRound40-D Fight Against Traffic 最短路
    HDU-6109 数据分割 并查集(维护根节点)
    ZOJ-3261 Connections in Galaxy War 并查集 离线操作
    AtCoderBeginner091-C 2D Plane 2N Points 模拟问题
    HDU-1878 欧拉回路 欧拉回路
    [笔记-图论]Floyd
    [笔记-图论]Bellman-Ford
    [笔记-图论]Dijkstra
  • 原文地址:https://www.cnblogs.com/dino623/p/using_DiscreteDoubleKeyFrame_to_play_animation.html
Copyright © 2020-2023  润新知