Demo中实现两种方式旋转3照片墙动画,分别是:计时器旋转和WPF动画旋转。

ps:WPF动画旋转角度计算还需优化,Demo只是提供思路,借鉴和学习。

1.计时器旋转

XAML:

<UserControl x:Class="System.Windows.Controls.PhotoWallControl"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" xmlns:ctr="clr-namespace:System.Windows.Controls"mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"><UserControl.Resources><Style TargetType="{x:Type ctr:VirtualImage}"><Setter Property="Cursor" Value="Hand"/><Setter Property="Template"><Setter.Value><ControlTemplate><Grid Margin="30"><Grid.RowDefinitions><RowDefinition Height="7*"/><RowDefinition Height="3*"/></Grid.RowDefinitions><Image x:Name="image" Source="{TemplateBinding ctr:VirtualImage.Image}" Width="{TemplateBinding ctr:VirtualImage.Width}" Height="{TemplateBinding ctr:VirtualImage.Height}"/><Rectangle Grid.Row="1" Margin="0 2 0 0"><Rectangle.RenderTransform><TransformGroup><SkewTransform AngleX="20"/></TransformGroup></Rectangle.RenderTransform><Rectangle.Fill><VisualBrush Visual="{Binding ElementName=image}"><VisualBrush.RelativeTransform><ScaleTransform ScaleY="-1" CenterY=".5"></ScaleTransform></VisualBrush.RelativeTransform></VisualBrush></Rectangle.Fill><Rectangle.OpacityMask><LinearGradientBrush StartPoint="0,0" EndPoint="0,1"><GradientStop Color="Black" Offset="0"></GradientStop><GradientStop Color="Transparent" Offset=".6"></GradientStop></LinearGradientBrush></Rectangle.OpacityMask></Rectangle></Grid></ControlTemplate></Setter.Value></Setter></Style></UserControl.Resources><Canvas x:Name="canvas" Background="Black"></Canvas>
</UserControl>

后代代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;namespace System.Windows.Controls {/// <summary>/// PhotoWallControl.xaml 的交互逻辑/// </summary>public partial class PhotoWallControl : UserControl {#region 字段/// <summary>/// 旋转计时器/// </summary>DispatcherTimer timer;/// <summary>/// 椭圆中心点X/// </summary>private double centerX;/// <summary>/// 椭圆中心点Y/// </summary>private double centerY;/// <summary>/// 椭圆长轴半径/// </summary>private double a;/// <summary>/// 椭圆短轴半径/// </summary>private double b;#endregion#region 属性/// <summary>/// 图片数据源/// </summary>public IEnumerable<VirtualImage> ItemsSource { get; set; }/// <summary>/// 图片的尺寸/// </summary>public Size ImageSize { get; set; }/// <summary>/// 旋转动画时间(毫秒)/// </summary>public double Duration { get; set; }#endregion#region 私有方法/// <summary>/// 清空界面展示照片/// </summary>private void ClearVirtualPhotos() {for (int i = this.canvas.Children.Count - 1; i >= 0; i--) {if (this.canvas.Children[i] is VirtualImage)this.canvas.Children.RemoveAt(i);}}/// <summary>/// 加载界面展示照片/// </summary>private void LoadVirtualPhotos() {if (this.Width == double.NaN || this.Height == double.NaN)throw new ArgumentException("请显示设置控件的宽高!");//设置圆心x,ythis.centerX = this.Width / 2;this.centerY = this.Height / 2 - 0;//减去适当的值,因为会设置最下面的图片最大,上面的图片较小//设置椭圆的长边和短边this.a = centerX - this.ImageSize.Width / 2.0;this.b = centerY - this.ImageSize.Height / 2.0;//每个图片之间相隔的角度var angle = (360.0 / this.ItemsSource.Count());//与X轴正相交角度,初始值正下方为90°double rotatAngle = 90;//说明:以最下方正图为起始点,顺时针摆放图片//注1:centerX因为默认wpf默认左上角为坐标原点//注2:this.ImageSize / 2,是以图片中心点运动轨迹//注3:椭圆公式:x=a*cosθ;y = b*sinθforeach (var virtualImage in this.ItemsSource) {//x,y为图片在Canvas中的坐标double x = a * Math.Cos(rotatAngle * Math.PI / 180.0) + centerX;double y = b * Math.Sin(rotatAngle * Math.PI / 180.0) + centerY;//当前图片坐标点与正下方图片坐标点的比值double allpers = y / (centerY + b);//比值最小不低于0.3allpers = Math.Max(0.3, allpers);//设置图片透明度virtualImage.Opacity = Math.Max(allpers * 1.5, 0.4);//设置图片尺寸virtualImage.Size = new Size(this.ImageSize.Width * allpers, this.ImageSize.Height * allpers);//设置图片中心点在Canvas坐标系中的位置virtualImage.Point = new Point(x - virtualImage.Size.Width / 2, y - virtualImage.Size.Height / 2);//记录图片在椭圆中与X轴正相交的角度virtualImage.Angle = rotatAngle;//向画布添加图片this.canvas.Children.Add(virtualImage);//注册图片点击事件virtualImage.Click += PhotoWallControl_Click;//下一张图片rotatAngle += angle;}}//获取点中图片旋转至正下方的旋转角度private double GetImageRotatAngle(VirtualImage image) {//注:由于记录坐标是以X轴延长线为起点,顺时针旋转角度。所以关于象限的计算方式以下为准。if (image.Angle >= 0 && image.Angle <= 90) { //第二象限return 90 - image.Angle;}else if (image.Angle > 90 && image.Angle < 270) { //第三、四象限return image.Angle - 90;}else { //第一象限return 360 - image.Angle + 90;}}//获取旋转方向private SweepDirection GetRotatDirection(VirtualImage image) {if (image.Angle > 90 && image.Angle < 270)return SweepDirection.Counterclockwise;elsereturn SweepDirection.Clockwise;}//获取图片旋转结束后的角度private double GetImageRotatEndAngle(VirtualImage image, double rotatAngle, SweepDirection rotatDirection) {if (rotatDirection == SweepDirection.Clockwise) { //顺时针return (image.Angle + rotatAngle) % 360;}else { //逆时针var angle = image.Angle - rotatAngle;while (angle < 0)angle = 360 + angle;return angle % 360;}}/// <summary>/// 图片点击事件,旋转动画/// </summary>void PhotoWallControl_Click(object sender, RoutedEventArgs e) {//计算点中图片旋转到正下方旋转角度Ndouble rotatAngle = this.GetImageRotatAngle(sender as VirtualImage);if (rotatAngle == 0) return;//计算点中图片旋转方向SweepDirection rotatDirection = this.GetRotatDirection(sender as VirtualImage);//每次旋转角度double everyRotatAngle = rotatAngle / this.Duration;//当前旋转角度double currentRotatAngle = 0.0;//定时器,定时修改ImageInfo中各属性,从而实现动画效果if (timer != null) timer.Stop();timer = new DispatcherTimer();//时间间隔timer.Interval = TimeSpan.FromMilliseconds(1);timer.Tick += (ss, ee) => {//图片序号int index = 0;currentRotatAngle += everyRotatAngle;//计算其余图片旋转N度后的坐标点foreach (var virtualImage in this.ItemsSource) {//获取旋转后的角度double rotatEndAngle = this.GetImageRotatEndAngle(virtualImage, everyRotatAngle, rotatDirection);if (currentRotatAngle >= rotatAngle)rotatEndAngle -= currentRotatAngle - rotatAngle;//减去多余的旋转角度//x=cos * avar x = Math.Cos(rotatEndAngle * Math.PI / 180) * a + centerX;//y=sin * bvar y = Math.Sin(rotatEndAngle * Math.PI / 180) * b + centerY;//当前图片与最下面一张图片的Y的比值var allpers = y / (centerY + b);//不要小于0.3,太小了就看不见了,可以适当调整allpers = Math.Max(0.3, allpers);//设置尺寸virtualImage.Size = new Size(allpers * this.ImageSize.Width, allpers * this.ImageSize.Height);//设置坐标virtualImage.Point = new Point(x - virtualImage.Width / 2, y - virtualImage.Height / 2);//设置透明度virtualImage.Opacity = Math.Max(allpers * 1.5, 0.4);//设置角度virtualImage.Angle = rotatEndAngle;index++;}//旋转结束if (currentRotatAngle >= rotatAngle) {timer.Stop();}};timer.Start();}#endregion#region 公开方法/// <summary>/// 照片墙实例/// </summary>public PhotoWallControl() {InitializeComponent();this.ImageSize = new Size(300, 300);this.Duration = 30;}/// <summary>/// 刷新数据源展示/// </summary>public void RefreshSource() {if (this.ItemsSource == null)this.ClearVirtualPhotos();else {this.ClearVirtualPhotos();this.LoadVirtualPhotos();}}#endregion}/// <summary>/// 展示图片/// </summary>public class VirtualImage : ButtonBase {#region 依赖属性public ImageSource Image {get { return (ImageSource)GetValue(ImageProperty); }set { SetValue(ImageProperty, value); }}// Using a DependencyProperty as the backing store for Image.  This enables animation, styling, binding, etc...public static readonly DependencyProperty ImageProperty =DependencyProperty.Register("Image", typeof(ImageSource), typeof(VirtualImage), new PropertyMetadata(null));#endregion/// <summary>/// 实例化/// </summary>public VirtualImage(string imgPath) {if (string.IsNullOrWhiteSpace(imgPath)) return;this.Image = new BitmapImage(new Uri(imgPath));}/// <summary>/// 实例化/// </summary>public VirtualImage() : this(null) { }/// <summary>/// 在椭圆中心点建立坐标系,以X轴延长线为起点,顺时针旋转,图片在椭圆中的角度。/// </summary>public double Angle { get; set; }/// <summary>/// 图片的尺寸。/// </summary>public Size Size {get { return new Size(base.Width, base.Height); }set { base.Width = value.Width; base.Height = value.Height; }}/// <summary>/// 以Canvas建立的坐标系,图片在坐标系中坐标点。/// </summary>public Point Point {get { return new Point(Canvas.GetLeft(this), Canvas.GetTop(this)); }set { Canvas.SetLeft(this, value.X); Canvas.SetTop(this, value.Y); Canvas.SetZIndex(this, (int)value.Y); }}}
}

2.WPF动画旋转 

XAML:

<UserControl x:Class="System.Windows.Controls.PhotoWallAnimation"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" xmlns:ctr="clr-namespace:System.Windows.Controls"mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"><UserControl.Resources><Style TargetType="{x:Type ctr:VirtualImage}"><Setter Property="Cursor" Value="Hand"/><Setter Property="Template"><Setter.Value><ControlTemplate><Grid Margin="30"><Grid.RowDefinitions><RowDefinition Height="7*"/><RowDefinition Height="3*"/></Grid.RowDefinitions><Image x:Name="image" Source="{TemplateBinding ctr:VirtualImage.Image}" Width="{TemplateBinding ctr:VirtualImage.Width}" Height="{TemplateBinding ctr:VirtualImage.Height}"/><Rectangle Grid.Row="1" Margin="0 2 0 0"><Rectangle.RenderTransform><TransformGroup><SkewTransform AngleX="20"/></TransformGroup></Rectangle.RenderTransform><Rectangle.Fill><VisualBrush Visual="{Binding ElementName=image}"><VisualBrush.RelativeTransform><ScaleTransform ScaleY="-1" CenterY=".5"></ScaleTransform></VisualBrush.RelativeTransform></VisualBrush></Rectangle.Fill><Rectangle.OpacityMask><LinearGradientBrush StartPoint="0,0" EndPoint="0,1"><GradientStop Color="Black" Offset="0"></GradientStop><GradientStop Color="Transparent" Offset=".6"></GradientStop></LinearGradientBrush></Rectangle.OpacityMask></Rectangle></Grid></ControlTemplate></Setter.Value></Setter></Style></UserControl.Resources><Canvas x:Name="canvas" Background="Black"><!--<Ellipse Stroke="Orange" Panel.ZIndex="1000" StrokeThickness="1" Width="700" Height="300" Canvas.Left="150" Canvas.Top="150"></Ellipse><Grid ShowGridLines="True" Width="{Binding ElementName=canvas,Path=ActualWidth}" Height="{Binding ElementName=canvas,Path=ActualHeight}"><Grid.RowDefinitions><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions></Grid>--></Canvas>
</UserControl>

后台代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;namespace System.Windows.Controls {/// <summary>/// PhotoWallAnimation.xaml 的交互逻辑/// </summary>public partial class PhotoWallAnimation : UserControl {#region 字段/// <summary>/// 椭圆中心点X/// </summary>private double centerX;/// <summary>/// 椭圆中心点Y/// </summary>private double centerY;/// <summary>/// 椭圆长轴半径/// </summary>private double a;/// <summary>/// 椭圆短轴半径/// </summary>private double b;#endregion#region 属性/// <summary>/// 图片数据源/// </summary>public IEnumerable<VirtualImage> ItemsSource { get; set; }/// <summary>/// 图片的尺寸/// </summary>public Size ImageSize { get; set; }#endregion#region 私有方法/// <summary>/// 清空界面展示照片/// </summary>private void ClearVirtualPhotos() {for (int i = this.canvas.Children.Count - 1; i >= 0; i--) {if (this.canvas.Children[i] is VirtualImage)this.canvas.Children.RemoveAt(i);}}/// <summary>/// 加载界面展示照片/// </summary>private void LoadVirtualPhotos() {if (this.Width == double.NaN || this.Height == double.NaN)throw new ArgumentException("请显示设置控件的宽高!");//设置圆心x,ythis.centerX = this.Width / 2;this.centerY = this.Height / 2 - 0;//减去适当的值,因为会设置最下面的图片最大,上面的图片较小//设置椭圆的长边和短边this.a = centerX - this.ImageSize.Width / 2.0;this.b = centerY - this.ImageSize.Height / 2.0;//每个图片之间相隔的角度var angle = (360.0 / this.ItemsSource.Count());//与X轴正相交角度,初始值正下方为90°double rotatAngle = 90;//说明:以最下方正图为起始点,顺时针摆放图片//注1:centerX因为默认wpf默认左上角为坐标原点//注2:this.ImageSize / 2,是以图片中心点运动轨迹//注3:椭圆公式:x=a*cosθ;y = b*sinθforeach (var virtualImage in this.ItemsSource) {//x,y为图片在Canvas中的坐标double x = a * Math.Cos(rotatAngle * Math.PI / 180.0) + centerX;double y = b * Math.Sin(rotatAngle * Math.PI / 180.0) + centerY;//当前图片坐标点与正下方图片坐标点的比值double allpers = y / (centerY + b);//比值最小不低于0.3allpers = Math.Max(0.3, allpers);//设置图片透明度virtualImage.Opacity = Math.Max(allpers * 1.5, 0.4);//设置图片尺寸virtualImage.Size = new Size(this.ImageSize.Width * allpers, this.ImageSize.Height * allpers);//设置图片中心点在Canvas坐标系中的位置virtualImage.Point = new Point(x - virtualImage.Size.Width / 2, y - virtualImage.Size.Height / 2);//记录图片在椭圆中与X轴正相交的角度virtualImage.Angle = rotatAngle;//向画布添加图片this.canvas.Children.Add(virtualImage);//注册图片点击事件virtualImage.Click += PhotoWallControl_Click;//下一张图片rotatAngle += angle;}}/// <summary>/// 图片点击事件,旋转动画/// </summary>void PhotoWallControl_Click(object sender, RoutedEventArgs e) {//计算点中图片旋转到正下方旋转角度Ndouble rotatAngle = this.GetImageRotatAngle(sender as VirtualImage);if (rotatAngle == 0) return;//计算点中图片旋转方向SweepDirection rotatDirection = this.GetRotatDirection(sender as VirtualImage);//定义动画故事版Storyboard storyboard = new Storyboard();//旋转重点,计算旋转椭圆中心点以及轴半径。//以X轴延长线,旋转90°,计算左上角坐标点double x90 = this.a * Math.Cos(90 * Math.PI / 180.0) + this.centerX;double y90 = this.b * Math.Sin(90 * Math.PI / 180.0) + this.centerY;//以X轴延长线,旋转180°,计算左上角坐标点double x180 = this.a * Math.Cos(180 * Math.PI / 180.0) + this.centerX;double y180 = this.b * Math.Sin(180 * Math.PI / 180.0) + this.centerY;//以X轴延长线,旋转270°,计算左上角坐标点double x270 = this.a * Math.Cos(270 * Math.PI / 180.0) + this.centerX;double y270 = this.b * Math.Sin(270 * Math.PI / 180.0) + this.centerY;//以X轴延长线,旋转360°,计算左上角坐标点double x360 = this.a * Math.Cos(360 * Math.PI / 180.0) + this.centerX;double y360 = this.b * Math.Sin(360 * Math.PI / 180.0) + this.centerY;//计算旋转后比值double allpers90 = y90 / y90;double allpers180 = y180 / y90;double allpers270 = y270 / y90;double allpers360 = y360 / y90;Size imageSize90 = new Size(this.ImageSize.Width * allpers90, this.ImageSize.Height * allpers90);Size imageSize180 = new Size(this.ImageSize.Width * allpers180, this.ImageSize.Height * allpers180);Size imageSize270 = new Size(this.ImageSize.Width * allpers270, this.ImageSize.Height * allpers270);Size imageSize360 = new Size(this.ImageSize.Width * allpers360, this.ImageSize.Height * allpers360);Point imagePoint90 = new Point(x90 - imageSize90.Width / 2, y90 - imageSize90.Height / 2);Point imagePoint180 = new Point(x180 - imageSize180.Width / 2, y180 - imageSize180.Height / 2);Point imagePoint270 = new Point(x270 - imageSize270.Width / 2, y270 - imageSize270.Height / 2);Point imagePoint360 = new Point(x360 - imageSize360.Width / 2, y360 - imageSize360.Height / 2);//已知椭圆4个远端点,可计算得出椭圆的中心点以及半径double rotatA = (imagePoint360.X - imagePoint180.X) / 2;double rotatB = (imagePoint90.Y - imagePoint270.Y) / 2;//double rotatCenterX = x180 + rotatA;//double rotatCenterY = y270 + rotatB;//计算其余图片旋转N度后的坐标点foreach (var image in this.ItemsSource) {//获取旋转后的角度double rotatEndAngle = this.GetImageRotatEndAngle(image, rotatAngle, rotatDirection);//x,y为图片左上角在Canvas中的坐标double x = this.a * Math.Cos(rotatEndAngle * Math.PI / 180.0) + this.centerX;double y = this.b * Math.Sin(rotatEndAngle * Math.PI / 180.0) + this.centerY;//当前图片坐标点与正下方图片坐标点的比值double allpers = y / (this.centerY + this.b);//比值最小不低于0.3allpers = Math.Max(0.3, allpers);//旋转结束图片透明度double endOpacity = Math.Max(allpers * 1.5, 0.4);//旋转结束图片尺寸Size endImageSize = new Size(this.ImageSize.Width * allpers, this.ImageSize.Height * allpers);//旋转结束图片中心点在Canvas坐标系中的位置Point endImagePoint = new Point(x - endImageSize.Width / 2, y - endImageSize.Height / 2);//记录图片在椭圆中与X轴正相交的角度image.Angle = rotatEndAngle;//准备动画var duration = new Duration(TimeSpan.FromSeconds(0.5));//旋转动画ArcSegment arcX = new ArcSegment(endImagePoint, new Size(rotatA, rotatB), 0, false, rotatDirection, true);ArcSegment arcY = new ArcSegment(endImagePoint, new Size(rotatA, rotatB), 0, false, rotatDirection, true);PathFigure figureX = new PathFigure() { StartPoint = image.Point, Segments = new PathSegmentCollection() { arcX } };PathFigure figureY = new PathFigure() { StartPoint = image.Point, Segments = new PathSegmentCollection() { arcY } };DoubleAnimationUsingPath xAnimation = new DoubleAnimationUsingPath() {Duration = duration,Source = PathAnimationSource.X,PathGeometry = new PathGeometry() { Figures = new PathFigureCollection(new PathFigure[] { figureX }) }};DoubleAnimationUsingPath yAnimation = new DoubleAnimationUsingPath() {Duration = duration,Source = PathAnimationSource.Y,PathGeometry = new PathGeometry() { Figures = new PathFigureCollection(new PathFigure[] { figureY }) }};Storyboard.SetTarget(xAnimation, image);Storyboard.SetTarget(yAnimation, image);Storyboard.SetTargetProperty(xAnimation, new PropertyPath(Canvas.LeftProperty));Storyboard.SetTargetProperty(yAnimation, new PropertyPath(Canvas.TopProperty));//图片置顶var zIndexAnimation = new Int32Animation((int)image.Point.Y, (int)endImagePoint.Y, duration);Storyboard.SetTarget(zIndexAnimation, image);Storyboard.SetTargetProperty(zIndexAnimation, new PropertyPath(Canvas.ZIndexProperty));//透明度动画var opacityAnimation = new DoubleAnimation(image.Opacity, endOpacity, duration);Storyboard.SetTarget(opacityAnimation, image);Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(FrameworkElement.OpacityProperty));//尺寸动画var widthAnimation = new DoubleAnimation(image.Width, endImageSize.Width, duration);var heightAnimation = new DoubleAnimation(image.Height, endImageSize.Height, duration);Storyboard.SetTarget(widthAnimation, image);Storyboard.SetTarget(heightAnimation, image);Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(FrameworkElement.WidthProperty));Storyboard.SetTargetProperty(heightAnimation, new PropertyPath(FrameworkElement.HeightProperty));//添加故事版storyboard.Children.Add(xAnimation);storyboard.Children.Add(yAnimation);storyboard.Children.Add(widthAnimation);storyboard.Children.Add(heightAnimation);storyboard.Children.Add(opacityAnimation);storyboard.Children.Add(zIndexAnimation);//动画结束后清除画板,不然属性无法设置。xAnimation.Completed += (ss, ee) => {image.BeginAnimation(Canvas.LeftProperty, null);Canvas.SetLeft(image, endImagePoint.X);};yAnimation.Completed += (ss, ee) => {image.BeginAnimation(Canvas.TopProperty, null);Canvas.SetTop(image, endImagePoint.Y);};zIndexAnimation.Completed += (ss, ee) => {image.BeginAnimation(Canvas.ZIndexProperty, null);Canvas.SetZIndex(image, (int)endImagePoint.Y);};opacityAnimation.Completed += (ss, ee) => {image.BeginAnimation(FrameworkElement.OpacityProperty, null);image.Opacity = endOpacity;};widthAnimation.Completed += (ss, ee) => {image.BeginAnimation(FrameworkElement.WidthProperty, null);image.Width = endImageSize.Width;};heightAnimation.Completed += (ss, ee) => {image.BeginAnimation(FrameworkElement.HeightProperty, null);image.Height = endImageSize.Height;};}//所有图片启动动画storyboard.Begin();}//获取点中图片旋转至正下方的旋转角度private double GetImageRotatAngle(VirtualImage image) {//注:由于记录坐标是以X轴延长线为起点,顺时针旋转角度。所以关于象限的计算方式以下为准。if (image.Angle >= 0 && image.Angle <= 90) { //第二象限return 90 - image.Angle;}else if (image.Angle > 90 && image.Angle < 270) { //第三、四象限return image.Angle - 90;}else { //第一象限return 360 - image.Angle + 90;}}//获取旋转方向private SweepDirection GetRotatDirection(VirtualImage image) {if (image.Angle > 90 && image.Angle < 270)return SweepDirection.Counterclockwise;elsereturn SweepDirection.Clockwise;}//获取图片旋转结束后的角度private double GetImageRotatEndAngle(VirtualImage image, double rotatAngle, SweepDirection rotatDirection) {if (rotatDirection == SweepDirection.Clockwise) { //顺时针return (image.Angle + rotatAngle) % 360;}else { //逆时针var angle = image.Angle - rotatAngle;while (angle < 0)angle = 360 + angle;return angle % 360;}}#endregion#region 公开方法/// <summary>/// 照片墙实例/// </summary>public PhotoWallAnimation() {InitializeComponent();this.ImageSize = new Size(300, 300);}/// <summary>/// 刷新数据源展示/// </summary>public void RefreshSource() {if (this.ItemsSource == null)this.ClearVirtualPhotos();else {this.ClearVirtualPhotos();this.LoadVirtualPhotos();}}#endregion}
}

运行效果

完整Demo下载:WPF3D照片墙Demo

WPF仿3D照片墙旋转动画Demo相关推荐

  1. HTML5——3D立方体旋转动画

    效果图: 代码如下: <!DOCTYPE html> <html> <head><meta charset="UTF-8">< ...

  2. html5中怎么让文字旋转动画效果图,HTML5中实现的CSS 3D文字旋转动画

    一个基于HTML5的网页文字3D旋转动画效果,支持中文和英文字符,浏览请注意要使用支持CSS3技术的浏览器,比如Opera.Chrome等,主要结合transition 和 animation来实现, ...

  3. wpf仿苹果桌面图标动画效果

    开局一张图后面全靠编. 源码下载地址:https://download.csdn.net/download/musx01230/10912990

  4. Android 高仿优酷旋转菜单

    这是一个很早版本的优酷菜单,效果挺不错的,实现起来也挺简单的.废话不说,直接上代码: 首先是xml文件: <RelativeLayout xmlns:android="http://s ...

  5. 旋转立体相册制作html,用CSS3制作3D动态旋转相册

    最近做一个网站,想弄一个炫酷的效果,所以想到了用CSS3做一个图片3D旋转的效果.[实际就是做一个3D动态旋转相册,自己发挥哦] 下面直接上代码了. -------------------start- ...

  6. html5+css3实现3D正方体动画相册2种+3D旋转木马立体动画相册+表白文字加动画爱心+炫酷万花筒五件套含音乐

    1.html+css+jquery实现,电脑和手机均已兼容,完整源码下载 2.3D旋转木马立体动画相册 3.3D正方体旋转动画相册2中实现方式: 第一种方式: 第二种方式: 4.表白示爱文字+动画爱心 ...

  7. 仿微信打开红包旋转动画

    介绍   公司的项目中包含IM模块,其中包含红包功能,在做打开红包的时候,觉得打开的按钮若不旋转感觉太过单调,没有乐趣,所以参考微信的红包,打开的时候,"开"字旋转起来.这里主要用 ...

  8. 代码创建 WPF 旋转动画

    原文:代码创建 WPF 旋转动画 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a771948524/article/details/9304001 ...

  9. android仿优酷菜单,Android编程实现仿优酷旋转菜单效果(附demo源码)

    本文实例讲述了Android编程实现仿优酷旋转菜单效果.分享给大家供大家参考,具体如下: 首先,看下效果: 不好意思,不会制作动态图片,只好上传静态的了,如果谁会,请教教我吧. 首先,看下xml文件: ...

最新文章

  1. mfc编辑框显示数据_Excel表格技巧—Excel表格中怎么给数据分等级
  2. 自定义负载均衡策略:
  3. 以前看过一个压缩过的.exe,运行会播放长达半小时的动画,却只有60KB,个人认为其中的原理...
  4. MySQL备份失败,一波三折的问题分析和处理
  5. 将PostgreSQL数据库扩展到每个月12亿条记录的经验教训
  6. Oracle Golden Gate 系列十二 -- GG 数据初始化装载二 基于SCN 的初始化 说明 与 示例...
  7. Raffi Krikorian 为“在运行中进行架构重写”提供了指南
  8. Linux之web服务
  9. webpack模块化原理-ES module
  10. 编译x264出现错误:No working C compiler found.
  11. PC版微信/QQ防撤回工具(支持最新版)
  12. 【无人机组装与调试】第一章 概述
  13. oracle 挖掘日志,使用Oracle的Logminer工具进行日志挖掘
  14. 微博图床php上传,php利用微博当图床
  15. 计算机工作理想湿度,计算机理想的工作温度七月的盛夏,碧空中没有一丝云彩,只剩下纯(9)...
  16. lsnrctl 未找到命令
  17. cascader 动态加载 回显_elementUI的cascader级联选择控件的默认值(回显)问题
  18. 淘系技术内容中台负责人接受采访回应“淘宝为什么要做媒体化升级”
  19. 虚幻4场景渲染源码分析概述
  20. 【MindInsight】在win下安装MindInsight遇到“ No module named apos;fcntlapos;“问题

热门文章

  1. Android 基础知识3:四大组件之 Broadcast(广播)
  2. 上海证券通信笔试总结
  3. python如何计算圆周率到千万位
  4. HBase 列族数据库
  5. html中marquee标签添加2条,HTMLmarquee标签
  6. 大白话详解决策树模型算法(一)
  7. [个人经验] 双系统ubuntu分区经验
  8. 隐藏PPT2003与PPT2007幻灯片中的声音图标
  9. 测试相关各软件下载地址
  10. vue踩坑系列——backgroundImage路径问题