• WPF(动画)


    在动画中,可以使用移动的元素、颜色变化、变换等制作平滑的变换效果。WPF使动画的制作非常简单。还可以连续改变任意依赖属性的值。不同的动画类可以根据其类型,连续改变不同属性的值。

    动画的主要元素如下:

    • 时间轴---定义了值随时间的变化方式。有不同类型的时间轴,可用于改变不同类型的值。所有时间轴的基类都是Timeline。为了连续改变double值,可以使用DoubleAnimation类。Int32Animation类是int值的动画类。PointAnimation类用于连续改变点,ColorAnimation类用于连续改变颜色。
    • 故事板---用于合并动画。Storyboard类派生自基类TimelineGroup,TimelineGroup又派生自基类Timeline。使用DoubleAnimation类,可以连续改变double,使用Storyboard类可以合并所有应连接在一起的动画。
    • 触发器---通过触发器可以启动和停止动画。前面介绍了属性触发器,当属性值变化时,属性触发器就会激活。还可以创建事件触发器,当事件发生时,事件触发器就会激活。 

    添加一个当Loaded完成后让椭圆的宽度自动变化的XAML代码: 

    <Window x:Class="WpfAppLearn1.TimeLine"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfAppLearn1"
            mc:Ignorable="d"
            Title="TimeLine" Height="450" Width="439">
        <Canvas>
            <Ellipse x:Name="ellipse" Height="100" Width="100" Canvas.Left="45" Canvas.Top="180" Fill="Red">
                <Ellipse.Triggers>
                    <EventTrigger RoutedEvent="Ellipse.Loaded">
                        <EventTrigger.Actions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetProperty="Width" RepeatBehavior="1x" 
                                                     Duration="0:0:6" AutoReverse="True" 
                                                     FillBehavior="Stop" From="100" To="300" 
                                                     Completed="DoubleAnimation_Completed"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger.Actions>
                    </EventTrigger>
                </Ellipse.Triggers>
            </Ellipse>
        </Canvas>
    </Window>
    Timeline属性说明
    AutoReverse指定连续改变的值是否在动画结束后返回初始值(默认为False)
    SpeedRatio可以改变动画的移动速度。在这个属性中,可以定义父子元素的相对关系。(默认值为1)
    BeginTime

    指定从触发器事件激活到动画开始移动之间的时间长度,即延时启动动画。

    (默认值为0,值可以为null表示永不播放)

    这和SpeedRatio属性有关:若将SpeedRatio设置为2,把BeginTime设置为6秒,动画就在3秒后开始。

    AccelerationRatio定义加速度(默认值为0)(在动画中,值不一定是线性变化的。可以指定加减速度)
    DecelerationRatio定义减速度(默认值为0)(和加速度的总和不能超过1)
    Duration指定动画重复一次的时间长度
    RepeatBehavior指定动画的重复次数或者重复时间(默认值为1,表示次数时数字后面加上x,否则就表示时间,Forever表示永久)
    FillBehavior

    指定动画在到达其有效期末尾后的行为。(默认值为HoldEnd)

    • HoldEnd:在达到活动期的终点后,时间线将保持其进度,直至其父级的活动期和保持期结束为止
    • Stop:如果时间线超出活动期,而其父级在活动期内,则该时间线将停止

    这里说明一下FillBehavior的用法:

    可以看到XAML中有一个Completed属性,这是一个事件表示动画完成后的响应。

    private void DoubleAnimation_Completed(object sender, EventArgs e)
    {
        this.ellipse.Width = 10;
    }
    • 若是将FillBehavior设置为HoldEnd的话,响应事件后并不会将Width设置为10,因为时间线并没有停止,如果去单独加个按钮设置也一样。只有该为Stop停止时间线后设置才有效。
    • Storyboard其实也继承于Timeline,也可以对其设置上表中的值。当Storyboard中只有一个Timeline时,对Storyboard设置任一个属性后,所有属于Storyboard的Timeline的FillBehavior值都以Storyboard的FillBehavior为准。当有多个时,就以Storyboard的值为准。XAML在将这段解析为代码时,只有一个未设置属性时相当于Storyboard=new(),当有多个时相当于Storyboard.Children.Add().

    关键帧动画 

    通过使用加减数比和缓动函数,就可以用非线性的方式制作动画。如果需要为动画指定几个值,就可以使用关键帧动画。 

    <Window x:Class="WpfAppLearn1.TimeLine"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfAppLearn1"
            mc:Ignorable="d"
            Title="TimeLine" Height="350" Width="328">
        <Canvas Background="#FFEAE7E7">
            <Ellipse x:Name="ellipse" Height="20" Width="20">
                <Ellipse.Fill>
                    <SolidColorBrush x:Name="ellipseBrush" Color="Red"/>
                </Ellipse.Fill>
                <Ellipse.RenderTransform>
                    <TransformGroup>
                        <TranslateTransform x:Name="ellipseMove" X="0" Y="0"/>
                    </TransformGroup>
                </Ellipse.RenderTransform>
                <Ellipse.Triggers>
                    <EventTrigger RoutedEvent="Ellipse.Loaded">
                        <BeginStoryboard>
                            <Storyboard RepeatBehavior="Forever" AutoReverse="True">
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="X" Storyboard.TargetName="ellipseMove">
                                    <LinearDoubleKeyFrame KeyTime="0:0:2" Value="30"/>
                                    <DiscreteDoubleKeyFrame KeyTime="0:0:4" Value="80"/>
                                    <SplineDoubleKeyFrame KeySpline="0.5,0.0, 0.9,0.0" KeyTime="0:0:10" Value="150"/>
                                    <LinearDoubleKeyFrame KeyTime="0:0:20" Value="300"/>
                                </DoubleAnimationUsingKeyFrames>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Y" Storyboard.TargetName="ellipseMove">
                                    <SplineDoubleKeyFrame KeySpline="0.5,0.0 0.9,0.0" KeyTime="0:0:2" Value="50"/>
                                    <EasingDoubleKeyFrame KeyTime="0:0:20" Value="300">
                                        <EasingDoubleKeyFrame.EasingFunction>
                                            <BounceEase/>
                                        </EasingDoubleKeyFrame.EasingFunction>
                                    </EasingDoubleKeyFrame>
                                </DoubleAnimationUsingKeyFrames>
                                <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipseBrush" Storyboard.TargetProperty="Color">
                                    <ColorAnimationUsingKeyFrames.KeyFrames>
                                        <LinearColorKeyFrame KeyTime="0:0:10" Value="Gold" />
                                        <LinearColorKeyFrame KeyTime="0:0:20" Value="Red" />
                                    </ColorAnimationUsingKeyFrames.KeyFrames>
                                </ColorAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Ellipse.Triggers>
            </Ellipse>
        </Canvas>
    </Window>

     关键帧动画将每一个状态制定为一个关键帧,关键帧动画时间线自动连接各个关键帧,并计算过渡状态,完成动画。因此,某种程度上,我们也可以把From/To/By 动画看成是只有两个状态的特殊关键帧动画。

    插值算法

    在关键帧动画中,我们除了定义关键帧外,还需要定义两个关键帧之间的插值算法,这样系统才能根据关键帧和插值算法生成中间状态。WPF系统内置四种插值算法:

    • 线性:    两个关键帧之间均匀变化

    • 离散:    两个关键帧之间突变(到达时间点的时候硬切换,没有过渡效果)

    • 样条:    使用贝塞尔曲线实现更精确的加速和减速控制

    • 缓动:    使用缓动函数曲线实现弹性变化


    可见状态管理器 

    Visual State Manager提供了控制动画的另一种方式,控件可以有特定的状态。状态定义了到达该状态时应用于控件的外观。状态切换定义了一种状态变成另一种状态时会发生什么。

    <Window x:Class="WpfAppLearn1.VisualState1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfAppLearn1"
            mc:Ignorable="d"
            Title="VisualState" Height="246" Width="379">
        <Canvas HorizontalAlignment="Left" VerticalAlignment="Top">
            <Button Content="Sleeping" Width="75" Canvas.Left="56" Canvas.Top="47" Click="BtnSleep_Click"/>
            <Button Content="Playing" Width="75" Canvas.Left="56" Canvas.Top="97" Click="BtnPlay_Click"/>
            <Button Content="Crying" Width="75" Canvas.Left="56" Canvas.Top="147" Click="BtnCry_Click"/>
            <Ellipse x:Name="ellipse1" Height="100" Stroke="Black" Width="100" Canvas.Left="216" Canvas.Top="54">
                <Ellipse.Fill>
                    <SolidColorBrush x:Name="brush1" Color="Aqua"/>
                </Ellipse.Fill>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Sleeping">
                            <Storyboard>
                                <ColorAnimation To="LightBlue" Storyboard.TargetName="brush1" 
                                                Storyboard.TargetProperty="Color" Duration="0:0:5"/>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Playing">
                            <Storyboard>
                                <ColorAnimation To="Gold" Storyboard.TargetName="brush1" 
                                                Storyboard.TargetProperty="Color" Duration="0:0:5"/>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Crying">
                            <Storyboard>
                                <ColorAnimation To="Red" Storyboard.TargetName="brush1" 
                                                Storyboard.TargetProperty="Color" Duration="0:0:5"/>
                            </Storyboard>
                        </VisualState>
                        <VisualStateGroup.Transitions>
                            <VisualTransition x:Name="ToSleeping" To="Sleeping">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetProperty="Width" Duration="0:0:5" To="50"/>
                                </Storyboard>
                            </VisualTransition>
                            <!--若是从Crying切换到Sleeping就不会执行上面的切换状态,只会执行下面的-->
                            <VisualTransition x:Name="CryingToSleeping" From="Crying" To="Sleeping">
                                <Storyboard>
                                    <ColorAnimation From="Black" To="White" Storyboard.TargetName="brush1" 
                                                    Storyboard.TargetProperty="Color" Duration="0:0:5"/>
                                </Storyboard>
                            </VisualTransition>
                            <!--GeneratedDuration:表示延迟切换-->
                            <VisualTransition To="Playing" GeneratedDuration="0:0:0.5"/>
                        </VisualStateGroup.Transitions>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
            </Ellipse>
        </Canvas>
    </Window>
    private void BtnSleep_Click(object sender, RoutedEventArgs e)
    {
        VisualStateManager.GoToElementState(ellipse1, "Sleeping", true);
    }
    
    private void BtnPlay_Click(object sender, RoutedEventArgs e)
    {
        VisualStateManager.GoToElementState(ellipse1, "Playing", true);
    }
    
    private void BtnCry_Click(object sender, RoutedEventArgs e)
    {
        VisualStateManager.GoToElementState(ellipse1, "Crying", true);
    }
    1. VisualStateGroup.Transitions表示状态从From值切换到To值时应执行的效果,没有From表示从任意状态。
    2. VisualState表示状态变更为该值时应执行的效果。 
    3. 点击按钮变换状态时,先执行Transitions中效果再执行VisualState中效果。
    4. 若是从Crying切换到Sleeping就不会执行ToSleeping切换状态,只会执行CryingToSleeping。

  • 相关阅读:
    每日一水 POJ8道水题
    编译和使用 MySQL C++ Connector
    j2ee model1模型完成分页逻辑的实现 详解!
    DB查询分析器访问EXCEL时,要在表名前后加上中括弧或双引号
    指向结构体变量的指针
    EOSS V3.0 企业运营支撑系统(基于RBAC原理的权限管理)
    MybatisGen1.0 Mybatis JavaBean Mapper生成工具
    The table name must be enclosed in double quotation marks or sqare bracket while accessing EXCEL by
    资源-Android:Android
    软件-开发软件:Android Studio
  • 原文地址:https://www.cnblogs.com/bridgew/p/16138034.html
Copyright © 2020-2023  润新知