天天看点

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

如同Flash一样,WPF的亮点之一也在于其擅于表现平滑的动画效果,但以移动动画来说,仅凭简单的起始位置、目标位置,所产生的动画仍会非常生硬,这种动画忽略了移动开始时的加速过程与移动结束时的减速过程。

WPF在关键帧动画中提供了样条内插(Spline)型的关键帧,用以控制变化的速率曲线,但这东西实在有些复杂,且不够形象化,我研究很久也没明白如何实现“缓入——缓出”的效果,随后我从一本经典牛X却鲜有人知的过时的FlashMX教程中提取了一个缓动函数,我们将用这个函数来较真实地模拟电梯的升降行为。

至于那本牛X的书,我以后会为大家介绍,我个人认为,那本书应当作为平面动画编程的必修经典,而它却被粗烂地印刷,并一直摆在书店里不引人注目的位置。

进入正题:

首先在界面设计器中添加一个 Rectangle ,用以代表直升电梯,然后添加4个 RadioButton 代表几个楼层的呼叫按钮。

稍加美化,即为下图所示:

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

RadioButton 的样式直接用来当电梯按钮,略显生硬,我们用下面的代码来美化一下它:

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

Code

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        <Style TargetType="RadioButton">

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            <Setter Property="Foreground" Value="#ADB7BD"/>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            <Setter Property="FontSize" Value="32"/>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            <Setter Property="Cursor" Value="Hand"/>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            <Setter Property="Template">

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                <Setter.Value>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                    <ControlTemplate TargetType="RadioButton">

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                        <ContentPresenter/>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                        <ControlTemplate.Triggers>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                            <Trigger Property="IsChecked" Value="True">

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                <Trigger.EnterActions>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                    <BeginStoryboard>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                        <Storyboard>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                            <ColorAnimation To="#BD5E00" Duration="0:0:0.3" BeginTime="0:0:0.1" Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)"/> 

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                        </Storyboard>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                    </BeginStoryboard>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                </Trigger.EnterActions>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                <Trigger.ExitActions>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                            <ColorAnimation Duration="0:0:0.2" BeginTime="0:0:0.2" Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)"/>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                                </Trigger.ExitActions>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                            </Trigger>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                        </ControlTemplate.Triggers>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                    </ControlTemplate>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                </Setter.Value>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            </Setter>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        </Style>

现在就比较帅了:

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

接下来为所有 RadioButton 添加统一的事件处理函数:

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

至此界面部分的全部代码如下,需要注意的是,所有元素都需要手动调整一下它们在Grid中的对齐方位,将其设为 Left 和 Top。要知道,设计器会在你拖动它们的时候为其胡乱改变对其方位,这会使你的元素没有统一的定位标准,导致几乎没法用代码统一操控它们的位置。

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

<Window x:Class="缓动动画.Window1"

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    Title="Window1" Height="398" Width="381" x:Name="window" Background="{StaticResource back}" Loaded="window_Loaded">

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    <Window.Resources>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    </Window.Resources>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    <Grid>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        <Rectangle Fill="{StaticResource box}" Margin="45,265,0,0" Name="rectangle1" HorizontalAlignment="Left" Width="50" Height="50" VerticalAlignment="Top" />

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        <RadioButton Checked="RadioButton_Checked" HorizontalAlignment="Left" Margin="123,205,0,0" VerticalAlignment="Top">1F</RadioButton>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        <RadioButton Checked="RadioButton_Checked" HorizontalAlignment="Left" Margin="123,125,0,0" VerticalAlignment="Top">2F</RadioButton>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        <RadioButton Checked="RadioButton_Checked" HorizontalAlignment="Left" Margin="123,45,0,0" VerticalAlignment="Top">3F</RadioButton>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        <RadioButton Checked="RadioButton_Checked" HorizontalAlignment="Left" Margin="123,285,0,0" VerticalAlignment="Top" IsChecked="True">B1</RadioButton>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    </Grid>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

</Window>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

在后台书写事件处理函数代码:

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

请不要惊讶我使用中文命名函数,假如你看过我自己写的程序的源代码,你就会对此保持沉默。

这就是传说中的中文函数“开始升降”:

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

在这个函数中,我们创建了一个 Thickness 的关键帧动画,Thickness 通常用来代表一个元素的上下左右4边,比如 Border 四个边的粗细就是用 Thickness 描述的,而这里的 Margin 属性也是 Thickness 类型。

一些要点我写在了图里,这里就不累述了。

“缓动计算”,是的,又一个神奇的中文函数,你可以在下面完整的源码中看看它是如何运算的,至少我是对它的内容毫无兴趣。

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Collections.Generic;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Linq;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Text;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Controls;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Data;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Documents;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Input;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Media;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Media.Imaging;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Navigation;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Shapes;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

using System.Windows.Media.Animation;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

namespace 缓动动画

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

{

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    /**//// <summary>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    /// Window1.xaml 的交互逻辑

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    /// </summary>

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    public partial class Window1 : Window

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        public Window1()

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            InitializeComponent();

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        }

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        private void window_Loaded(object sender, RoutedEventArgs e)

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        Storyboard s = new Storyboard();

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        public double 缓动计算(TimeSpan 总时间, TimeSpan 现在时间, double 初始值, double 变动量)

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            var t = 现在时间.TotalSeconds /( 总时间.TotalSeconds / 2);

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            if (t < 1) return (变动量 / 2 * Math.Pow(t, 5) + 初始值);

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            return (变动量 / 2 * (Math.Pow(t - 2, 5) + 2) + 初始值);

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        private void RadioButton_Checked(object sender, RoutedEventArgs e)

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            开始升降((sender as RadioButton).Margin.Top - 5);

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

        public void 开始升降(double 目标高度)

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            ThicknessAnimationUsingKeyFrames d = new ThicknessAnimationUsingKeyFrames();

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            d.Duration = new Duration(TimeSpan.FromSeconds(Math.Abs((目标高度-rectangle1.Margin.Top)/80)));

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            for (int i = 0; i < 100; i++)

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                var t = new Thickness();

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                t.Left = rectangle1.Margin.Left;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                t.Right = rectangle1.Margin.Right;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                t.Bottom = rectangle1.Margin.Bottom;

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                t.Top=缓动计算(d.Duration.TimeSpan, TimeSpan.FromSeconds(d.Duration.TimeSpan.TotalSeconds / 100 * i), rectangle1.Margin.Top, 目标高度-rectangle1.Margin.Top);

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

                d.KeyFrames.Add(new LinearThicknessKeyFrame(t, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(d.Duration.TimeSpan.TotalSeconds / 100 * i))));

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            }

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            s.Children.Add(d);

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            Storyboard.SetTargetName(d, rectangle1.Name);

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            Storyboard.SetTargetProperty(d, new PropertyPath(Rectangle.MarginProperty));

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

            s.Begin(rectangle1);

WPF界面设计技巧(7)—模拟电梯升降的缓动动画
WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    }

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

}

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

现在编译运行吧,随便点击一个楼层,你将会看到电梯平缓的起步,然后平缓的停靠在你所选的楼层上。

WPF界面设计技巧(7)—模拟电梯升降的缓动动画

当然,即使是这样具有缓动效果的电梯,乘客也是很难生还的,但至少会比生硬的上飞下坠要好很多啦。

<a href="http://files.cnblogs.com/SkyD/WPF_ANI_1.rar">源代码下载</a>