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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM