天天看點

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>