這兩天領導讓我做個噴泉的效果,要把一個個UserControl從一個位置噴出,然后,最后落在最終需要在的位置。
噴泉效果說白了,就是兩個步驟:1、放大,從0放大到需要的倍數;2、縮小,平移,從放大的倍數還原到UserControl的原始大小,並且定位到最終的位置。
雖然,只有兩步,但是,作為寫動畫的新手,還是有點費事的,所以,采用了先用Blend設計,然后再轉換為C#代碼的過程。
一、Blend設計單個UserControl的放大和移動效果
1、在Blend里,新建個項目,然后,在Grid下,放個Canvas,在Canvas下放個Image(先拿Image來設計)
2、在Blend左側的時間線,選中image控件,然后點擊上面的+號,會彈出新增動畫資源的彈窗,點擊確定。
3、根據需要,拖拽左側的時間線(黃線)到對應位置,然后,對紅框中的Image控件,進行放大、縮小、位置調整等操作。
4、XAML部分,產生了相應的代碼
<Window.Resources> <Storyboard x:Key="StoryboardFountain"> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="image"> <EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:5" Value="5"/> <EasingDoubleKeyFrame KeyTime="0:0:10" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="image"> <EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:5" Value="5"/> <EasingDoubleKeyFrame KeyTime="0:0:10" Value="1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="image"> <EasingDoubleKeyFrame KeyTime="0:0:5" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:10" Value="-186.5"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="image"> <EasingDoubleKeyFrame KeyTime="0:0:5" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:10" Value="-107"/> </DoubleAnimationUsingKeyFrames> </Storyboard> <Storyboard x:Key="Storyboard1"/> </Window.Resources> <Window.Triggers> <EventTrigger RoutedEvent="FrameworkElement.Loaded"> <BeginStoryboard Storyboard="{StaticResource StoryboardFountain}"/> </EventTrigger> </Window.Triggers> <Grid> <Canvas HorizontalAlignment="Center" VerticalAlignment="Center"> <Image x:Name="image" Source="C:\Users\dell\Pictures\WP_20160112_18_55_33_Raw_LI.jpg" Width="50" Height="50" Canvas.Left="-0.5" Canvas.Top="-0.5" RenderTransformOrigin="0.5,0.5"> <Image.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Image.RenderTransform> </Image> </Canvas> </Grid>
二、把XAML代碼轉換為C#
有了XAML代碼,轉換成C#代碼,就方便多了,只要把對應的部分相關轉換,然后啟動動畫,就OK了
TransformGroup部分轉換為如下的方式
if (uc.RenderTransform as TransformGroup == null) { TransformGroup tg = new TransformGroup(); uc.RenderTransform = tg; tg.Children.Add(new ScaleTransform()); tg.Children.Add(new TranslateTransform()); }
由於,實際上只用到了ScaleTransform和TranslateTransform,所以,就只寫了兩個
DoubleAnimationUsingKeyFrames部分轉換為如下的方式
EasingDoubleKeyFrame edf1 = new EasingDoubleKeyFrame(Init, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(i + first_value))); EasingDoubleKeyFrame edf2 = new EasingDoubleKeyFrame(Mul, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(i + middle_value))); EasingDoubleKeyFrame edf3 = new EasingDoubleKeyFrame(Org, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(i + end_value))); DoubleAnimationUsingKeyFrames daukf1 = new DoubleAnimationUsingKeyFrames(); daukf1.KeyFrames.Add(edf1); daukf1.KeyFrames.Add(edf2); daukf1.KeyFrames.Add(edf3); storyboard.Children.Add(daukf1); Storyboard.SetTarget(daukf1, uc); Storyboard.SetTargetProperty(daukf1, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));
對比過XAML代碼和C#代碼以后,就發現,其實XAML轉C#,還是沒有那么困難的,就是把相應的位置進行相關的添加值,可以直接從XAML里復制過來,如(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX),誰能記得住呢,反正我記不住,太笨了。
寫好了一個UserControl的效果以后,多個的實現起來,就容易了,無外乎就是for循環,設置參數而已。
定義一個UCShow的類,里面包含了UC和最后要定位的位置,如下,將需要展示的集合,都添加到一個List里就ok了。
public class UcShow { private UIElement uc; private double top; private double left; public UIElement Uc { get { return uc; } set { uc = value; } } public double Top { get { return top; } set { top = value; } } public double Left { get { return left; } set { left = value; } } }
效果如下:
噴泉效果的代碼如下:
class Fountain { /// <summary> /// 噴泉效果 /// </summary> /// <param name="cav">畫布</param> /// <param name="uclist">展示集合</param> /// <param name="pL">噴出點左</param> /// <param name="pT">噴出點上</param> /// <param name="Mul">放大倍數</param> /// <param name="middle_value">放大時間點</param> /// <param name="end_value">還原時間點</param> public void FountainAnimation(Canvas cav,List<UcShow> uclist, double pL = 0, double pT = 0, double Mul = 10, double middle_value = 0.5, double end_value = 1) { if (uclist.Count <= 0) { return; } Storyboard storyboard = new Storyboard(); double Init = 0; double Org = 1; double first_value = 0; for (int i = 0; i < uclist.Count; i++) { UIElement uc = uclist[i].Uc; double Top = uclist[i].Top; double Left = uclist[i].Left; Canvas.SetLeft(uc, pL); Canvas.SetTop(uc, pT); if (uc.RenderTransform as TransformGroup == null) { uc.RenderTransformOrigin = new Point(0.5, 0.5); TransformGroup tg = new TransformGroup(); uc.RenderTransform = tg; tg.Children.Add(new ScaleTransform()); tg.Children.Add(new TranslateTransform()); } double first = i * 0.05 + first_value; double middle = i * 0.05 + middle_value; double end = i * 0.05 + end_value; EasingDoubleKeyFrame edf0 = new EasingDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0)));//所有元素起點都是0 EasingDoubleKeyFrame edf1 = new EasingDoubleKeyFrame(Init, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(first))); EasingDoubleKeyFrame edf2 = new EasingDoubleKeyFrame(Mul, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(middle))); EasingDoubleKeyFrame edf3 = new EasingDoubleKeyFrame(Org, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(end))); DoubleAnimationUsingKeyFrames daukf1 = new DoubleAnimationUsingKeyFrames(); daukf1.KeyFrames.Add(edf0); daukf1.KeyFrames.Add(edf1); daukf1.KeyFrames.Add(edf2); daukf1.KeyFrames.Add(edf3); storyboard.Children.Add(daukf1); Storyboard.SetTarget(daukf1, uc); Storyboard.SetTargetProperty(daukf1, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)")); DoubleAnimationUsingKeyFrames daukf2 = new DoubleAnimationUsingKeyFrames(); daukf2.KeyFrames.Add(edf0); daukf2.KeyFrames.Add(edf1); daukf2.KeyFrames.Add(edf2); daukf2.KeyFrames.Add(edf3); storyboard.Children.Add(daukf2); Storyboard.SetTarget(daukf2, uc); Storyboard.SetTargetProperty(daukf2, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)")); DoubleAnimationUsingKeyFrames daukf3 = new DoubleAnimationUsingKeyFrames(); EasingDoubleKeyFrame edf31 = new EasingDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(middle))); EasingDoubleKeyFrame edf32 = new EasingDoubleKeyFrame(Top, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(end))); daukf3.KeyFrames.Add(edf31); daukf3.KeyFrames.Add(edf32); storyboard.Children.Add(daukf3); Storyboard.SetTarget(daukf3, uc); Storyboard.SetTargetProperty(daukf3, new PropertyPath("(Canvas.Top)")); DoubleAnimationUsingKeyFrames daukf4 = new DoubleAnimationUsingKeyFrames(); EasingDoubleKeyFrame edf41 = new EasingDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(middle))); EasingDoubleKeyFrame edf42 = new EasingDoubleKeyFrame(Left, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(end))); daukf4.KeyFrames.Add(edf41); daukf4.KeyFrames.Add(edf42); storyboard.Children.Add(daukf4); Storyboard.SetTarget(daukf4, uc); Storyboard.SetTargetProperty(daukf4, new PropertyPath("(Canvas.Left)"));
cav.Children.Add(uc); } storyboard.FillBehavior = FillBehavior.HoldEnd; storyboard.Begin(); } }