常常在實作系統的時候,會為了強調出 RIA中Rich的威力,會希望讓物件被加到畫面上或是被移除的時候能套用一段動畫,來強調這件事的發生,這篇就來看看在Flex中和WPF/Silverlight裡,怎麼分別做到這種效果~
常常在實作系統的時候,會為了強調出 RIA中Rich的威力,會希望讓物件被加到畫面上或是被移除的時候能套用一段動畫,來強調這件事的發生,而在Flex中的物件很親切的提供了addedEffect和removedEffect兩個屬性可以供我們設定,只要針對物件的這兩個屬性加以指定給予某個特效,在新增/移除該物件到某個容器的時候,就會自動播放該動畫,讓我們看看下面的例子:
原始碼如下:
<?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和程式碼:
<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。
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;
}
}
}
最後一樣附上這次的原始碼,請自行服用: