这个动画原来是用VS11 beta+SL5做的,回到家用vs2010跑了一下,没跑起来,重新修改了一下,在vs2010+sl5环境下成功。
截图如下:
图片有点大,VS11下的太阳效果更好一点。
思路很简单,波浪的部分是一个Canvas,然后用PahtGeometry填充,就可以设置波浪的背景了,对cavas或者path做个无限循环位移的动画就可以了。太阳升起落下是一个Rotation动画,然后把动画选装的中心点设置为RenderTransformOrigin="6.5,0",这个数据可以调整。
源代码可以从这里下载:http://download.csdn.net/detail/coaxhappy/4459305,如果没有分的可以从下面拷贝代码过去,写这个动画的目的就是学习如何从C#代码里控制动画,完成一些稍微复杂的动画和UI操作。
代码如下:
MainPage.xaml
<UserControl x:Class="WaterSunshine.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ec="http://schemas.microsoft.com/expression/2010/controls"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:ee="http://schemas.microsoft.com/expression/2010/effects"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="600"
d:DesignWidth="1200"
mc:Ignorable="d">
<UserControl.Resources>
<Storyboard x:Name="Storyboard3"
AutoReverse="False"
RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="pathTest" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)">
<EasingDoubleKeyFrame KeyTime="0" Value="-50" />
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="Storyboard1" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)">
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:12" Value="180" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="White">
<Grid VerticalAlignment="Top" d:LayoutOverrides="Width">
<Grid.Effect>
<!--
<ee:BloomEffect BaseIntensity="5"
BaseSaturation="0"
BloomIntensity="2" />
-->
<DropShadowEffect />
</Grid.Effect>
<Grid.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0" Color="#FF208EEA" />
<GradientStop Offset="1" Color="#FFD4FBF2" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
<Canvas x:Name="canvas"
Height="500"
VerticalAlignment="Top">
<Canvas.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0.009" Color="#FF1C85EE" />
<GradientStop Offset="1" Color="#FFFDFDFD" />
</LinearGradientBrush>
</Canvas.Background>
<Ellipse x:Name="ellipse"
Canvas.Left="50"
Width="100"
Height="100"
Canvas.ZIndex="0"
RenderTransformOrigin="6.5,0">
<Ellipse.RenderTransform>
<CompositeTransform />
</Ellipse.RenderTransform>
<Ellipse.Effect>
<BlurEffect Radius="15" />
</Ellipse.Effect>
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.3,0.2">
<GradientStop Offset="0.009" Color="#FFEEE4AB" />
<GradientStop Offset="1" Color="#FFEAAD0C" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Path x:Name="pathTest"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Data=""
Fill="{StaticResource bgBrush}"
RenderTransformOrigin="0.5,0.5"
StrokeThickness="0"
UseLayoutRounding="False">
<Path.RenderTransform>
<CompositeTransform />
</Path.RenderTransform>
</Path>
</Canvas>
</Grid>
</UserControl>
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using WaterSunshine.Common;
namespace WaterSunshine
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.SizeChanged += new SizeChangedEventHandler(MainPage_SizeChanged);
}
void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
{
double waveBlockWidth = LayoutRoot.ActualWidth + 200;
canvas.Width = waveBlockWidth;
double startPositionX = -100d;
double startPositionY = LayoutRoot.ActualHeight * ConstValue.WAVE_START_POINTION_PROPORTION;
Canvas.SetTop(ellipse, LayoutRoot.ActualHeight * 0.9d);
//canvas.Margin = new Thickness(-100, 0, -100, 0);
pathTest.Width = waveBlockWidth;// LayoutRoot.ActualWidth + 100;
pathTest.Height = LayoutRoot.ActualHeight;
Point startPoint = new Point(startPositionX, startPositionY);
PathGeometry pathGeometry = pathTest.Data as PathGeometry;
pathGeometry.Figures.Clear();
pathGeometry.Figures.Insert(0, CreatePathFigure(startPoint, ConstValue.WAVE_HEIGHT_HEIGHT, ConstValue.WAVE_LENGTH, LayoutRoot.ActualWidth + 200d
, ConstValue.WAVE_PATH_STROKE_BRUSH, ConstValue.WAVE_PATH_STROKE_THICKNESS));
PathFigure pathFigureBounds = new PathFigure();
pathFigureBounds.StartPoint = startPoint;
LineSegment lineSegment1 = new LineSegment();
lineSegment1.Point = startPoint;
LineSegment lineSegment2 = new LineSegment();
lineSegment2.Point = new Point(startPositionX, LayoutRoot.ActualHeight);
LineSegment lineSegment3 = new LineSegment();
lineSegment3.Point = new Point(LayoutRoot.ActualWidth + 100, LayoutRoot.ActualHeight);
LineSegment lineSegment4 = new LineSegment();
lineSegment4.Point = new Point(LayoutRoot.ActualWidth + 100, startPositionY);
pathFigureBounds.Segments.Add(lineSegment1);
pathFigureBounds.Segments.Add(lineSegment2);
pathFigureBounds.Segments.Add(lineSegment3);
pathFigureBounds.Segments.Add(lineSegment4);
pathGeometry.Figures.Add(pathFigureBounds);
(this.Resources["Storyboard3"] as Storyboard).Begin();
(this.Resources["Storyboard1"] as Storyboard).Begin();
}
private PathFigure CreatePathFigure(Point startPoint, double waveHeight, double waveLength, double totalLength, Brush strokeBrush, double strokeThickness)
{
PathFigure pathFigure = new PathFigure();
pathFigure.StartPoint = startPoint;
double waveCount = Math.Ceiling((totalLength) / waveLength);
for (int i = 0; i < waveCount; i++)
{
PathSegment pathSegment = CreateWaveSegment(new Point(startPoint.X + i * waveLength, startPoint.Y), waveHeight, waveLength);
pathFigure.Segments.Add(pathSegment);
}
return pathFigure;
}
private PathSegment CreateWaveSegment(Point startPoint, double waveHeight, double waveLength)
{
BezierSegment bezierSegment = new BezierSegment();
bezierSegment.Point1 = new Point(startPoint.X, startPoint.Y);
bezierSegment.Point2 = new Point(startPoint.X + waveLength / 2d, startPoint.Y + waveHeight);
bezierSegment.Point3 = new Point(startPoint.X + waveLength, startPoint.Y);
return bezierSegment;
}
}
}
App.xaml
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WaterSunshine.App"
>
<Application.Resources>
<ResourceDictionary Source="Resources/Theme1.xaml" />
</Application.Resources>
</Application>
Theme1.xaml(拷贝时,注意项目结构Reources/Theme1.xaml)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<LinearGradientBrush x:Key="bgBrush" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0.009" Color="#FF0E8FE8" />
<GradientStop Offset="1" Color="#FFB0E1F3" />
</LinearGradientBrush>
</ResourceDictionary>
ConstValue.cs(Common/ConstValue.cs)
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace WaterSunshine.Common
{
public class ConstValue
{
public const double WAVE_START_POINTION_PROPORTION = 0.8d;
public const double WAVE_HEIGHT_HEIGHT = 10;
public const double WAVE_LENGTH = 50;
public static Brush WAVE_PATH_STROKE_BRUSH = new SolidColorBrush(Colors.Black);
public const double WAVE_PATH_STROKE_THICKNESS = 0d;
}
}