WPF 图片浏览 伪3D效果

首先上效果图:

因项目要求,需要把图片以“好看”、“炫”的效果展示出来,特地研究了一下WPF关于3D方面的制作,奈何最终成果只是能够画出一个立方体并使之旋转。

项目时间仅剩两天,只好放弃3D另找出路,于是就想起了Flash中各种“炫丽”的动画效果,图片按椭圆排列,并且旋转。

于是开始代码,然后发现关于椭圆啊、正玄余玄、x,y,r等等数学知识都忘得光光了,仅有思路没有进展,无奈之下开始百度恶补数学知识。图形变换、3D是很考验数学知识的,本人对于3D方面的学习就败在数学之下,高中数学学的还不错的,现在……哎,不提也罢。

然后找到这么一篇博文——javascript-按圆形排列DIV元素(三)实例---- 图片按椭圆形转动,是js代码,在此感谢这位船长op大大的无私奉献。

下面正式上代码:

定义ImageInfo类,实现INotifyPropertyChanged接口,属性没有写说明,不过看名称我想各位也能知道是什么含义了。

public class ImageInfo : INotifyPropertyChanged

    {

        private int _zIndex;



        public int ZIndex

        {

            get { return _zIndex; }

            set

            {

                if (value != _zIndex)

                {

                    _zIndex = value;

                    this.NotifyPropertyChanged("ZIndex");

                }

            }

        }

        private double _left;



        public double Left

        {

            get { return _left; }

            set

            {

                if (value != _left)

                {

                    _left = value;

                    this.NotifyPropertyChanged("Left");

                }

            }

        }

        private double _top;



        public double Top

        {

            get { return _top; }

            set

            {

                if (value != _top)

                {

                    _top = value;

                    this.NotifyPropertyChanged("Top");

                }

            }

        }

        private double _width;



        public double Width

        {

            get { return _width; }

            set

            {

                if (value != _width)

                {

                    _width = value;

                    this.NotifyPropertyChanged("Width");

                }

            }

        }

        private double _height;



        public double Height

        {

            get { return _height; }

            set

            {

                if (value != _height)

                {

                    _height = value;

                    this.NotifyPropertyChanged("Height");

                }

            }

        }



        private double _opacity = 1.0;



        public double Opactity

        {

            get { return _opacity; }

            set 

            {

                if (value != _opacity)

                {

                    _opacity = value;

                    this.NotifyPropertyChanged("Opactity");

                }

            }

        }



        private string _imagePath;



        public string ImagePath

        {

            get { return _imagePath; }

            set

            {

                if (value != _imagePath)

                {

                    _imagePath = value;

                    this.NotifyPropertyChanged("ImagePath");

                }

            }

        }



        public ImageInfo(string path)

        {

            this.ImagePath = path;

        }



        public event PropertyChangedEventHandler PropertyChanged;



        private void NotifyPropertyChanged(String propertyName)

        {

            PropertyChangedEventHandler handler = PropertyChanged;

            if (null != handler)

            {

                handler(this, new PropertyChangedEventArgs(propertyName));

            }

        }

    }
ViewModel Code

在xaml中binding ImageInfo 中的对应的属性,在后台代码中使用计时器来定时更改ImageInfo中的属性,当属性值发生改变时就会通知到界面,于是就实现了动画效果了。

<Window

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:WPF_ImageShow" x:Class="WPF_ImageShow.MainWindow"

        Title="MainWindow" Height="600" Width="800" >

    <Window.Resources>

        <local:DoubleConverter x:Key="doubleConverter"/>

    </Window.Resources>

    <Grid>

        <ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" Loaded="lv_Loaded"

            ScrollViewer.VerticalScrollBarVisibility="Disabled" x:Name="lv" Background="Black">

            <!--<ListView.ItemTemplate>

                <DataTemplate>

                    <Border>

                        <StackPanel>

                            <Image Source="{Binding ImagePath, Mode=OneWay}" x:Name="img" 

                                            Stretch="UniformToFill" Width="{Binding Width, Mode=OneWay}"

                                            Height="{Binding Height, Mode=OneWay}"/>

                            <Rectangle RenderTransformOrigin="1,0.5"  Height="{Binding Height, Converter={StaticResource doubleConverter}, Mode=OneWay}">

                                <Rectangle.Fill>

                                    <VisualBrush Visual="{Binding ElementName=img}" />

                                </Rectangle.Fill>

                                <Rectangle.RenderTransform>

                                    <TransformGroup>

                                        <ScaleTransform ScaleY="-1" />

                                    </TransformGroup>

                                </Rectangle.RenderTransform>

                                <Rectangle.OpacityMask>

                                    <LinearGradientBrush StartPoint="0,0"   EndPoint="0,1">

                                        <GradientStop Offset="0.3"     Color="Transparent" />

                                        <GradientStop Offset="1"   Color="#44000000" />

                                    </LinearGradientBrush>

                                </Rectangle.OpacityMask>

                            </Rectangle>

                        </StackPanel>

                    </Border>

                </DataTemplate>

            </ListView.ItemTemplate>-->

            <ListView.Resources>

                <Style TargetType="{x:Type ListViewItem}">

                    <Setter Property="Template">

                        <Setter.Value>

                            <ControlTemplate TargetType="{x:Type ListViewItem}" >

                                <Border>

                                    <StackPanel>

                                        <Image Source="{Binding ImagePath, Mode=OneWay}" x:Name="img" 

                                            Stretch="UniformToFill" Width="{Binding Width, Mode=OneWay}"

                                            Height="{Binding Height, Mode=OneWay}"/>

                                        <Rectangle RenderTransformOrigin="1,0.5"  Height="{Binding Height, Converter={StaticResource doubleConverter}, Mode=OneWay}">

                                            <Rectangle.Fill>

                                                <VisualBrush Visual="{Binding ElementName=img}" />

                                            </Rectangle.Fill>

                                            <Rectangle.RenderTransform>

                                                <TransformGroup>

                                                    <ScaleTransform ScaleY="-1" />

                                                </TransformGroup>

                                            </Rectangle.RenderTransform>

                                            <Rectangle.OpacityMask>

                                                <LinearGradientBrush StartPoint="0,0"   EndPoint="0,1">

                                                    <GradientStop Offset="0.3"     Color="Transparent" />

                                                    <GradientStop Offset="1"   Color="#44000000" />

                                                </LinearGradientBrush>

                                            </Rectangle.OpacityMask>

                                        </Rectangle>

                                    </StackPanel>

                                </Border>

                            </ControlTemplate>

                        </Setter.Value>

                    </Setter>

                    <Setter Property="Opacity" Value="{Binding Opactity, Mode=OneWay}"/>

                    <Setter Property="Canvas.Left" Value="{Binding Left, Mode=OneWay}"/>

                    <Setter Property="Canvas.Top" Value="{Binding Top, Mode=OneWay}"/>

                    <Setter Property="Panel.ZIndex" Value="{Binding ZIndex, Mode=OneWay}"/>

                </Style>

            </ListView.Resources>

            <ListView.ItemsPanel>

                <ItemsPanelTemplate>

                    <Canvas/>

                </ItemsPanelTemplate>

            </ListView.ItemsPanel>

        </ListView>

    </Grid>

</Window>
XAML Code
 /// <summary>

        /// 设置动画

        /// </summary>

        void Run()

        {

            //动画速率

            double speed = 0.0;

            //定时器,定时修改ImageInfo中各属性,从而实现动画效果

            DispatcherTimer timer = new DispatcherTimer();

            //时间间隔

            timer.Interval = TimeSpan.FromMilliseconds(100);

            timer.Tick += (ss, ee) =>

            {

                #region

                //设置圆心x,y

                double centerX = this.ActualWidth / 2;

                double centerY = this.ActualHeight / 2 - 50;//减去适当的值,因为会设置最下面的图片最大,上面的图片较小



                //设置图片最大的宽、高

                double maxWidth = 300;

                double maxHeight = 200;



                //设置椭圆的长边和短边

                double a = centerX - maxWidth / 2.0;

                double b = centerY - maxHeight / 2.0;



                //运动一周后恢复为0

                speed = speed < 360 ? speed : 0.0;

                //运运的速度 此“增值”和  timer.Interval对动画的流畅性有影响

                speed += 0.5;

                //运动距离,即运动的弧度数;

                var ainhd = speed * Math.PI / 180;

                //每个图片之间相隔的角度

                var angle = (360.0 / data.Count) * Math.PI / 180.0;

                //图片序号

                int index = 0;

                foreach (var img in data)

                {

                    //最下面一张图ZIndex最大,Opacity最大,长宽最大



                    img.ZIndex = (int)img.Top;

                    //当前图片与最下面一张图片的Y的比值

                    var allpers = img.Top / (centerY + b);

                    //不要小于0.2,太小了就看不见了,可以适当调整

                    allpers = Math.Max(0.2, allpers);

                    //设置图片大小

                    img.Width = allpers * maxWidth;

                    img.Height = allpers * maxHeight;

                    //设置透明度

                    img.Opactity = Math.Max(allpers * 1.5, 0.4);



                    //公式:x=sin * a //+ centerX因为默认wpf默认左上角为坐标原点;//- img.Width / 2.0是以图片中心点作为运动轨迹

                    img.Left = Math.Sin((angle * index + ainhd)) * a + centerX - img.Width / 2.0;//x=sin * a

                    //y=cos * b

                    img.Top = Math.Cos((angle * index + ainhd)) * b + centerY - img.Height / 2.0;



                    index++;

                }

                #endregion

            };

            //启动计时器,开始动画

            timer.Start();

        }



        private void lv_Loaded(object sender, RoutedEventArgs e)

        {

            //准备数据源 ObservableCollection<T>

            data = new ObservableCollection<ImageInfo>();

            //获取程序所在目录中的images文件夹

            DirectoryInfo di = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "images");

            //添加此目录中的图片文件到data中

            foreach (var file in di.GetFiles())

            {

                //验证是否为图片文件 (可以写一个方法来进行验证,此处仅支持jpg和png)

                if (file.Extension.ToLower() == ".jpg" || file.Extension.ToLower() == ".png")

                {

                    data.Add(new ImageInfo(file.FullName));

                }

            }

            //设置ListView的ItemsSource

            lv.ItemsSource = data;



            Run();

        }
View Code

最后上一个简单的Demo:WPF_ImageShow

你可能感兴趣的:(WPF)