[Silverlight][WPF][Flex] 我要我的物件浮出來、褪出去 - 善用事件套用物件出現與移除的動畫

常常在實作系統的時候,會為了強調出 RIA中Rich的威力,會希望讓物件被加到畫面上或是被移除的時候能套用一段動畫,來強調這件事的發生,這篇就來看看在Flex中和WPF/Silverlight裡,怎麼分別做到這種效果~

 

常常在實作系統的時候,會為了強調出 RIA中Rich的威力,會希望讓物件被加到畫面上或是被移除的時候能套用一段動畫,來強調這件事的發生,而在Flex中的物件很親切的提供了addedEffectremovedEffect兩個屬性可以供我們設定,只要針對物件的這兩個屬性加以指定給予某個特效,在新增/移除該物件到某個容器的時候,就會自動播放該動畫,讓我們看看下面的例子:

原始碼如下:

Flex_OnLoadAnimation.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx">
	<s:layout>
		<s:BasicLayout/>
	</s:layout>

	<fx:Script>


		<![CDATA[
			import mx.containers.*;
			import mx.graphics.SolidColor;
			
			import spark.components.BorderContainer;
			import spark.effects.Fade;
			
			protected function btnAddControl_clickHandler(event:MouseEvent):void
			{
				var borderContainer : BorderContainer = new BorderContainer();
				
				borderContainer.width = 100;
				
				borderContainer.height = 100;
				
				borderContainer.backgroundFill = new SolidColor( 0xff0000 , 1);
				
				var addedEffect : Fade = new Fade();
				
				addedEffect.duration = 1000;
				
				addedEffect.alphaFrom = 0;
				
				addedEffect.alphaTo = 1;
				
				var removedEffect : Fade = new Fade();
				
				removedEffect.duration = 300;
				
				removedEffect.alphaFrom = 1;
				
				removedEffect.alphaTo = 0;
				
				borderContainer.setStyle( "addedEffect" , addedEffect );
				
				borderContainer.setStyle( "removedEffect" , removedEffect );
				
				this.tileGroup.addElement( borderContainer );
			}

			protected function btnRemoveControl_clickHandler(event:MouseEvent):void
			{
				if( this.tileGroup.numChildren > 0 )
				{
					this.tileGroup.removeElementAt( this.tileGroup.numChildren - 1 );
				}
			}

		]]>

	</fx:Script>

	<s:BorderContainer left="10" right="10" top="10" bottom="10" borderColor="#646464" 
					   borderWeight="2" cornerRadius="10">
		<s:TileGroup id="tileGroup" horizontalGap="10" verticalGap="10" orientation="rows" 
					 top="10" bottom="50" left="10" right="10">
		</s:TileGroup>
		<s:HGroup height="40" horizontalCenter="0" bottom="0" verticalAlign="middle" gap="10" 
				  paddingLeft="5" paddingTop="5" paddingBottom="5" paddingRight="5">
			<s:Button label="Add Control" width="120" id="btnAddControl" 
					  click="btnAddControl_clickHandler(event)"/>
			<s:Button label="Remove Control" width="120" id="btnRemoveControl" 
					  click="btnRemoveControl_clickHandler(event)"/>
		</s:HGroup>
	</s:BorderContainer>
</s:Application>

就這麼簡單,很輕鬆就能套用動畫(這是直接針對要被加入/移除的物件加特效的作法,還有另一種是直接針對容器加特效的作法,之後另開其他文章介紹)。

 

而在WPF和Silverlight要做到類似的效果,該怎麼辦呢?這邊就跟大家分享我自己的因應之道(如果有更高明的技巧也請不吝分享給我喔!!),利用物件的Loaded事件就可以做到加入時就撥放動畫了~但是比較麻煩的是當物件要被移除前也要播動畫,那怎麼辦呢?(絕對不是反過來利用Unloaded事件嘿~)要移除物件時播放動畫,就得動個小手腳了,要反過來先播放動畫,再利用動畫的Completed事件來移除物件才行,請看以下的範例:

(*若無法正常瀏覽本WPF版範例,煩請參考[Windows7]使用IE9、FireFox與Chrome瀏覽WPF Browser Application(.XBAP)的方式一文調整瀏覽器設定)

來看看WPF的Xaml和程式碼:

Page1.xaml

<Page x:Class="Wpf_OnLoadAnimation.Page1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" Title="Page1"
        d:DesignWidth="800" d:DesignHeight="600" Width="Auto" Height="Auto">
    <Border BorderThickness="2" CornerRadius="10" BorderBrush="#FF646464" Margin="10">
        <Grid x:Name="LayoutRoot">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="50" />
            </Grid.RowDefinitions>
            <StackPanel Orientation="Horizontal" Grid.Row="1" d:LayoutOverrides="Height"
                    HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0">
                <Button Content="Add Control" HorizontalAlignment="Center" x:Name="btnAddGrid"
                        VerticalAlignment="Center" Click="btnAddGrid_Click" Padding="5" Width="130" />
                <Button Content="Remove Control" HorizontalAlignment="Center" x:Name="btnRemoveLast"
                        VerticalAlignment="Center" Margin="10,0,0,0" Padding="5" Width="130"
                        Click="btnRemoveLast_Click" />
            </StackPanel>
            <WrapPanel x:Name="wrpPanel" Margin="10,10,10,10" />
        </Grid>
    </Border>
</Page>

程式的部份得注意的是要避免動畫的播放和停止互相干擾,所以在動畫播放完畢之前將畫面先設為IsEnabled = false

Page1.xaml.cs

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace Wpf_OnLoadAnimation
{
    /// <summary>
    /// Interaction logic for Page1.xaml
    /// </summary>
    public partial class Page1 : Page
    {
        public Page1()
        {
            InitializeComponent();

        }

        private void btnAddGrid_Click( object sender , System.Windows.RoutedEventArgs e )
        {
            Grid myGrid = new Grid { Background = Brushes.Red , Width = 100 , Height = 100 , Margin = new Thickness( 2 ) };

            myGrid.Loaded += new RoutedEventHandler( MyGrid_Loaded );

            wrpPanel.Children.Add( myGrid );
        }

        void MyGrid_Loaded( object sender , RoutedEventArgs e )
        {
            Grid grid = sender as Grid;

            DoubleAnimation showAnimation = new DoubleAnimation { Duration = new Duration( TimeSpan.FromMilliseconds( 1000 ) ) , };
            showAnimation.From = 0;
            showAnimation.To = 1;
            Storyboard.SetTargetProperty( showAnimation , new PropertyPath( Grid.OpacityProperty ) );
            Storyboard strbStoryBoard = new Storyboard();
            strbStoryBoard.Children.Add( showAnimation );
            strbStoryBoard.Begin( grid );
        }

        private void btnRemoveLast_Click( object sender , RoutedEventArgs e )
        {
            if( this.wrpPanel.Children.Count > 0 )
            {
                this.IsEnabled = false;

                Grid grid = this.wrpPanel.Children.OfType<Grid>().Last() as Grid;

                DoubleAnimation hideAnimation = new DoubleAnimation { Duration = new Duration( TimeSpan.FromMilliseconds( 300 ) ) , };
                hideAnimation.From = 1;
                hideAnimation.To = 0;
                Storyboard.SetTargetProperty( hideAnimation , new PropertyPath( Grid.OpacityProperty ) );
                Storyboard strbStoryBoard = new Storyboard();
                strbStoryBoard.Children.Add( hideAnimation );

                strbStoryBoard.Completed += new EventHandler( strbStoryBoard_Completed );

                strbStoryBoard.Begin( grid );

            }

        }

        void strbStoryBoard_Completed( object sender , EventArgs e )
        {
            this.wrpPanel.Children.RemoveAt( this.wrpPanel.Children.Count - 1 );

            this.IsEnabled = true;
        }
    }
}

 

最後一樣附上這次的原始碼,請自行服用: