用WPF轻松打造iTunes CoverFlow效果

<script language='javascript' src='http://www.shiqiaotou.com/donetk/Header.js'></script>

                                    用WPF轻松打造iTunes CoverFlow效果
                                                       周银辉

先Show一下:
CoverFlow1.png
CoverFlow2.png

下面这一张是苹果的iTunes软件:
iTunes.png

苹果iTunes播放器的CoverFlow效果羡煞旁人,不过有了WPF,我们也可以轻松实现哈,今天费了半天的时间终于搞定,呵呵...

感兴趣的话可以这里下载源代码
(说明:上传源代码时由于图片较大,所以就没传图片了,程序取的是用户" 我的图片"文件夹下的*.jpg图片,你可以修改代码中的路径或在"我的图片"文件夹下放几张jpg图片就可以看到效果了)

图片是使用3DTools 提供的2D到3D映射的方式贴图上去的,每张图片都帖在一个3D模型上,我们只需要让程序来安排这些模型的摆放位置就可以了

3D模型的摆放是按照如下方法进行的,其中3个传出参数angle指定模型源Y轴的旋转角度,offsetX指定模型的X轴方向上的平移量,offsetZ指定模型在Z轴方向上的平移量

  /// <summary>
        
/// 依照InteractiveVisual3D在列表中的序号来变换其位置等
        
/// </summary>
        
/// <param name="index">在列表中的序号</param>
        
/// <param name="midIndex">列表中被作为中间项的序号</param>

         private   void  GetTransformOfInteractiveVisual3D( int  index,  double  midIndex,  out   double  angle,  out   double  offsetX,  out   double  offsetZ)
        
{
            
double disToMidIndex = index - midIndex;


            
//旋转,两翼的图片各旋转一定的度数
            angle = 0;
            
if (disToMidIndex < 0)
            
{
                angle 
= this.ModelAngle;//左边的旋转N度
            }

            
else if (disToMidIndex > 0)
            
{
                angle 
= (-this.ModelAngle);//右边的旋转-N度
            }

            
         

            
//平移,两翼的图片逐渐向X轴负和正两个方向展开
            offsetX = 0;//中间的不平移
            if (Math.Abs(disToMidIndex) <= 1)
            
{
                offsetX 
= disToMidIndex * this.MidModelDistance;
            }

            
else if (disToMidIndex != 0)
            
{
                offsetX 
= disToMidIndex * this.XDistanceBetweenModels + (disToMidIndex > 0 ? this.MidModelDistance : -this.MidModelDistance);
            }

            

            
//两翼的图片逐渐向Z轴负方向移动一点,造成中间突出(离观众较近的效果)
            offsetZ = Math.Abs(disToMidIndex) * -this.ZDistanceBetweenModels;
          
        }

点击图片或指定当前应该被突出显示的图片时的动画效果是这样实现的,先使用上面的方法计算出决定模型位置的几个便量的新值(即上面的几个传出参数),然后在使用动画(DoubleAnimation)让这几个值由旧值过度到新值.
   /// <summary>
        
/// 重新布局3D内容
        
/// </summary>

         private   void  ReLayoutInteractiveVisual3D()
        
{
            
int j=0;
            
for (int i = 0; i < this.viewport3D.Children.Count; i++)
            
{
                InteractiveVisual3D iv3d 
=  this.viewport3D.Children[i] as InteractiveVisual3D;
                
if(iv3d != null)
                
{
                    
double angle = 0;
                    
double offsetX = 0;
                    
double offsetZ = 0;
                    
this.GetTransformOfInteractiveVisual3D(j++this.CurrentMidIndex,out angle,out offsetX,out offsetZ);


                    NameScope.SetNameScope(
thisnew NameScope());
                    
this.RegisterName("iv3d", iv3d);
                    Duration time 
= new Duration(TimeSpan.FromSeconds(0.3));

                    DoubleAnimation angleAnimation 
= new DoubleAnimation(angle, time);
                    DoubleAnimation xAnimation 
= new DoubleAnimation(offsetX, time);
                    DoubleAnimation zAnimation 
= new DoubleAnimation(offsetZ, time);

                    Storyboard story 
= new Storyboard();
                    story.Children.Add(angleAnimation);
                    story.Children.Add(xAnimation);
                    story.Children.Add(zAnimation);

                    Storyboard.SetTargetName(angleAnimation, 
"iv3d");
                    Storyboard.SetTargetName(xAnimation, 
"iv3d");
                    Storyboard.SetTargetName(zAnimation, 
"iv3d");

                    Storyboard.SetTargetProperty(
                        angleAnimation,
                        
new PropertyPath("(ModelVisual3D.Transform).(Transform3DGroup.Children)[0].(RotateTransform3D.Rotation).(AxisAngleRotation3D.Angle)"));

                    Storyboard.SetTargetProperty(
                        xAnimation,
                        
new PropertyPath("(ModelVisual3D.Transform).(Transform3DGroup.Children)[1].(TranslateTransform3D.OffsetX)"));
                    Storyboard.SetTargetProperty(
                        zAnimation,
                        
new PropertyPath("(ModelVisual3D.Transform).(Transform3DGroup.Children)[1].(TranslateTransform3D.OffsetZ)"));

                    story.Begin(
this);

                }

            }

        }

文章来源于 http://www.cnblogs.com/zhouyinhui 版权归原作者所有<script language='javascript' src='http://www.shiqiaotou.com/donetk/Footer.js'></script>
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Media3D; using System.Windows.Media.Effects; namespace WPFDemo { public partial class Rotate3DContainer : Grid, Container { private Storyboard front2BackStory; private Storyboard back2FrontStory; private Border frontWarpper; private Border backWarpper; public Rotate3DContainer() { InitializeComponent(); this.Loaded += new RoutedEventHandler(Container_Loaded); } private void Container_Loaded(object sender, RoutedEventArgs e) { Init(); } private void Init() { if (this.Children.Count == 2) { UIElement[] array = new UIElement[2]; this.Children.CopyTo(array, 0); this.Children.Clear(); frontWarpper = new Border() { Child = array[0], HorizontalAlignment=HorizontalAlignment.Left, VerticalAlignment=VerticalAlignment.Top, Background = Brushes.Transparent }; backWarpper = new Border() { Child = array[1], Opacity = 0, Visibility = Visibility.Hidden, HorizontalAlignment=HorizontalAlignment.Left, VerticalAlignment=VerticalAlignment.Top, Background = Brushes.Transparent }; Viewport3D viewport = Get3DView(); viewport.HorizontalAlignment = HorizontalAlignment.Left; viewport.VerticalAlignment = VerticalAlignment.Top; viewport.Height = frontWarpper.Child.DesiredSize.Height; viewport.Width = frontWarpper.Child.DesiredSize.Width; front2BackStory = new Storyboard() { Children = new TimelineCollection() { GetShowHideAnimation(viewport, 0, 1100), GetShowHideAnimation(backWarpper, 1000, -1), GetShowHideAnimation(frontWarpper, -1, 50), GetFadeAnimation(frontWarpper, 0, -1, 50), GetFadeAnimation(backWarpper, 1, 1050, 50), GetCameraMoveAnimation(0, 0, 0.5, 0, 0, 1.1, 50, 500,viewport), GetRotateAnimation(0, -180, 0.3, 0.3, 50, 1000) } }; back2FrontStory = new Storyboard() { Children = new TimelineCollection() { GetShowHideAnimation(viewport, 0, 1100), GetShowHideAnimation(frontWarpper, 1000, -1), GetShowHideAnimation(backWarpper, -1, 50), GetFadeAnimation(backWarpper, 0, -1, 50), GetFadeAnimation(frontWarpper, 1, 1050, 50), GetCameraMoveAnimation(0, 0, 0.5, 0, 0, 1.1, 50, 500, viewport), GetRotateAnimation(180, 360, 0.3, 0.3, 50, 1000) } }; this.Effect = new DropShadowEffect() { BlurRadius = 10, Opacity = 0.8 }; this.Children.Add(frontWarpper); this.Children.Add(backWarpper); this.Children.Add(viewport); array = null; } } private DoubleAnimation GetFadeAnimation(UIElement target, int toOpacity, int beginTime, int duration) { DoubleAnimation result = new DoubleAnimation(toOpacity, new Duration(TimeSpan.FromMilliseconds(duration))); if (beginTime >= 0) { result.BeginTime = TimeSpan.FromMilliseconds(beginTime); } Storyboard.SetTarget(result, target); Storyboard.SetTargetProperty(result, new PropertyPath("Opacity")); return result; } private Point3DAnimation GetCameraMoveAnimation(double x1, double y1, double z1, double x2, double y2, double z2, int beginTime, int duration, Viewport3D view) { Point3DAnimation result = new Point3DAnimation(new Point3D(x1, y1, z1), new Point3D(x2, y2, z2), new Duration(TimeSpan.FromMilliseconds(duration))) { AutoReverse = true, BeginTime = TimeSpan.FromMilliseconds(beginTime), DecelerationRatio = 0.3 }; Storyboard.SetTarget(result, view); Storyboard.SetTargetProperty(result, new PropertyPath("Camera.Position")); return result; } private DoubleAnimation GetRotateAnimation(double fromDegree, double toDegree, double accelerationRatio, double decelerationRatio, int beginTime, int duration) { DoubleAnimation result = new DoubleAnimation(fromDegree, toDegree, new Duration(TimeSpan.FromMilliseconds(duration)), FillBehavior.HoldEnd) { AccelerationRatio = accelerationRatio, DecelerationRatio = decelerationRatio, BeginTime = TimeSpan.FromMilliseconds(beginTime) }; Storyboard.SetTargetName(result, "AxisAngleRotation3D"); Storyboard.SetTargetProperty(result, new PropertyPath("Angle")); return result; } Viewport3D Get3DView() { Viewport3D viewport = new Viewport3D() { Camera = new PerspectiveCamera(new Point3D(0, 0, 0.5), new Vector3D(0, 0, -1), new Vector3D(0, 1, 0), 90), Visibility = Visibility.Hidden }; viewport.Children.Add(GetLightVisual3D()); viewport.Children.Add(GetSceneVisual3D(frontWarpper, backWarpper)); return viewport; } ModelVisual3D GetLightVisual3D() { Model3DGroup group = new Model3DGroup(); group.Children.Add(new DirectionalLight(Color.FromRgb(0x44, 0x44, 0x44), new Vector3D(0, 0, -1))); group.Children.Add(new AmbientLight(Color.FromRgb(0xBB, 0xBB, 0xBB))); return new ModelVisual3D() { Content = group }; } ModelVisual3D GetSceneVisual3D(Border frontElement, Border backElement) { MeshGeometry3D meshgmod = new MeshGeometry3D() { TriangleIndices = new Int32Collection(new int[] { 0, 1, 2, 2, 3, 0 }), TextureCoordinates = new PointCollection(new Point[]{new Point(0, 1),new Point(1, 1),new Point(1, 0),new Point(0, 0)}), Positions = new Point3DCollection(new Point3D[]{new Point3D(-0.5, -0.5, 0),new Point3D(0.5, -0.5, 0),new Point3D(0.5, 0.5, 0),new Point3D(-0.5, 0.5, 0)}) }; VisualBrush frontBrush = new VisualBrush(frontElement.Child) { Stretch = Stretch.Uniform }; VisualBrush backBrush = new VisualBrush(backElement.Child) { Stretch = Stretch.Uniform, RelativeTransform = new ScaleTransform(-1, 1, 0.5, 0) }; AxisAngleRotation3D rotate = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0); this.RegisterName("AxisAngleRotation3D", rotate); GeometryModel3D gmode3d = new GeometryModel3D() { Geometry = meshgmod, Material = new DiffuseMaterial(frontBrush), BackMaterial = new DiffuseMaterial(backBrush), Transform = new RotateTransform3D(rotate) }; return new ModelVisual3D() { Content = gmode3d }; } ObjectAnimationUsingKeyFrames GetShowHideAnimation(UIElement element, int showTime, int hideTime) { ObjectAnimationUsingKeyFrames frame = new ObjectAnimationUsingKeyFrames(); Storyboard.SetTarget(frame, element); Storyboard.SetTargetProperty(frame, new PropertyPath("Visibility")); if (showTime >= 0) { frame.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Visible, TimeSpan.FromMilliseconds(showTime))); } if (hideTime >= 0) { frame.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Hidden, TimeSpan.FromMilliseconds(hideTime))); } return frame; } public void Turn(bool isReverse) { Storyboard target = null; DoubleAnimation direction = null; double fromAngle = 0; double step = 180; if (frontWarpper.Opacity != 0) { target = front2BackStory; } else { fromAngle = 180; target = back2FrontStory; } direction = (DoubleAnimation)target.Children[6]; if (!isReverse) { step = -180; } direction.From = fromAngle; direction.To = fromAngle + step; target.Begin(this); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值