天天看點

C# WPF 低仿網易雲音樂(PC)Banner動畫控件

原文: C# WPF 低仿網易雲音樂(PC)Banner動畫控件

由于技術有限沒能做到一模一樣的動畫,隻是粗略地做了一下。動畫有點生硬,還有就是沒做出網易雲音樂的立體感。代碼非常簡單粗暴,而且我也寫有很多注釋,這裡就不多啰嗦了,直接貼代碼。

算了,啰嗦幾句。原理是這樣的,在自定義使用者控件内添加3個border(左、中、右,以下分别簡稱為:b1、b2、b3),對border進行縮放和移動動畫。往右切換時b1放大平移到b2的位置,b2縮小平移到b3的位置,b3平移到b1的位置,動畫結束後重新記錄3個border的左、中、右位置,然後如此循環。一次滾動有三個動畫,分别寫了3個方法來定義。

可加上透明動畫、陰影,應該會更加好看些。

沒有實作調用的方法,隻是個純動畫項目,圖檔也是寫死在前台代碼中,需要在項目中使用時自行簡單地修改即可。

低仿效果

C# WPF 低仿網易雲音樂(PC)Banner動畫控件
網易雲音樂原版
C# WPF 低仿網易雲音樂(PC)Banner動畫控件

代碼

背景

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
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 網易雲音樂Banner動畫.Controls
{
    /// <summary>
    /// CloudMusicBanner.xaml 的互動邏輯
    /// </summary>
    public partial class CloudMusicBanner : UserControl
    {

        //代碼所用涉及時間機關均是:秒
        #region 一些變量
        //左、中、右三張banner的位置
        double leftlocation = 0, centerlocation = 0, rightlocation = 0;
        //每張banner的動畫執行時間
        double AnimationTime = 0.4;
        //非中間banner的遮蓋層透明度
        double bopacity = 0.65;
        //沒有互動時動畫自動執行間隔時間
        double timeranimation_time = 4;
        //動畫播放狀态(目前動畫是否在執行)
        bool isplay = false;
        //三個banner border變量,用于暫時儲存
        Border b_left, b_center, b_right;
        //通用緩動函數,提升動畫流暢感
        EasingFunctionBase easeFunction;
        //banner集合,用于定位和記錄border的位置(左,中,右)
        Dictionary<Location, Border> Banners = new Dictionary<Location, Border>();
        DispatcherTimer timeranimation;
        #endregion

        public CloudMusicBanner()
        {
            InitializeComponent();

            //将三張banner(border)添加到banner集合
            Banners.Add(Location.Left, left);
            Banners.Add(Location.Center, center);
            Banners.Add(Location.Right, right);

            //控件加載完成後
            Loaded += (e, c) =>
            {
                //首次啟動設定三張banner的位置、大小資訊
                SetLocation(Location.Left, left);
                SetLocation(Location.Center, center);
                SetLocation(Location.Right, right);

                //啟動定時器,用于自動播放滾動動畫
                TimerAnimationStart();
            };

            //初始化緩動函數
            //quadraticease的easeout mode是從快到慢
            //參考了部落格:http://www.cnblogs.com/xwlyun/archive/2012/09/11/2680579.html
            easeFunction = new QuadraticEase()
            {
                EasingMode = EasingMode.EaseOut
            };

            //初始化定時器
            timeranimation = new DispatcherTimer();
            //設定定時器的間隔時間
            timeranimation.Interval = TimeSpan.FromSeconds(timeranimation_time);

        }

        #region 互動事件

        private void UserControl_MouseEnter(object sender, MouseEventArgs e)
        {
            //滑鼠移入控件時顯示兩個“左/右”圖示按鈕
            toleftbtn.Opacity = 1;
        }

        private void UserControl_MouseLeave(object sender, MouseEventArgs e)
        {
            //滑鼠移出控件時隐藏兩個“左/右”圖示按鈕

            toleftbtn.Opacity = 0;
        }

        private void toleftbtn_Click(object sender, RoutedEventArgs e)
        {
            //向左圖示按鈕點選
            LeftAnimation();
        }

        private void torightbtn_Click(object sender, RoutedEventArgs e)
        {
            RightAnimation();
        }
        #endregion

        //左切換動畫時三張banner向右滾動
        /*
         * 即中間的border移動至:右
         * 右邊的border移動至:左
         * 左邊的border移動至:中
         */
        #region 左切換動畫
        public void LeftAnimation()
        {
            //啟動動畫時停止定時器
            timeranimation.Stop();
            //設定動畫播放狀态為真
            isplay = true;

            //啟動相應的動畫
            LefttoCenterAnimation();

            CentertoRightAnimation();

            RighttoLeftAnimation();


        }
        //【僅注釋此方法,以下代碼均大多重複故不再注釋】
        #region 左切換動畫-中向右動畫
        public void CentertoRightAnimation()
        {
            //記錄動畫結束後的位置,即當動畫結束後中間的BORDER移動到右變成了右,代碼:Banners[Location.Right] = b_center;
            b_center = Banners[Location.Center];

            //設定一下border的顯示層級
            Grid.SetZIndex(Banners[Location.Center], 2);

            //擷取透明遮蓋圖層,設定透明度
            /*
             * <Grid Background="Black" Panel.ZIndex="2"></Grid>
             * 透明遮蓋圖層在設計代碼中的每個border内
             * 
             */
            GetOpacityGrid(b_center).Opacity = bopacity;

            //定義一個縮放轉換對象(用于banner從大到小的動畫)
            ScaleTransform scale = new ScaleTransform();
            //需要設定中心點y坐标為控件的高度,不設定的話border是靠在頂部執行動畫的。
            scale.CenterY = this.ActualHeight;

            //定義一個水準移動轉換對象
            TranslateTransform ts = new TranslateTransform();

            //定義一個轉換集合
            TransformGroup group = new TransformGroup();
            //将上面的縮放、平移轉換對象添加到集合
            group.Children.Add(scale);
            group.Children.Add(ts);

            //将轉換集合賦予給中心banner
            Banners[Location.Center].RenderTransform = group;


            //定義一個縮放動畫
            DoubleAnimation scaleAnimation = new DoubleAnimation()
            {
                //從1(100%即預設比例)
                From = 1,
                //到0.95(95%即從預設比例縮小到95%的比例大小)
                To = 0.95,
                //設定緩動函數
                EasingFunction = easeFunction,
                //動畫執行所需時間
                Duration = TimeSpan.FromSeconds(AnimationTime)


            };

            //定義一個移動動畫(用于banner從左到右.....移動動畫等)
            DoubleAnimation moveAnimation = new DoubleAnimation()
            {
                //從中心banner位置
                From = centerlocation,
                //移動到右banner位置
                To = rightlocation,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)

            };
            //啟動縮放動畫
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);

            //啟動平移動畫
            ts.BeginAnimation(TranslateTransform.XProperty, moveAnimation);








        }



        #endregion
        #region 左切換動畫-右向左動畫
        public void RighttoLeftAnimation()
        {
            b_right = Banners[Location.Right];

            Grid.SetZIndex(Banners[Location.Right], 1);
            GetOpacityGrid(b_right).Opacity = bopacity;

            ScaleTransform scale = new ScaleTransform();   //縮放  
            scale.CenterY = this.ActualHeight;
            TranslateTransform ts = new TranslateTransform();//平移


            TransformGroup group = new TransformGroup();
            group.Children.Add(scale);
            group.Children.Add(ts);


            Banners[Location.Right].RenderTransform = group;


            DoubleAnimation scaleAnimation = new DoubleAnimation()
            {
                From = 0.85,
                To = 0.95,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)


            };

            DoubleAnimation moveAnimation = new DoubleAnimation()
            {

                From = rightlocation,
                To = leftlocation,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)

            };

            //scaleAnimation.Completed += new EventHandler(scaleAnimation_Completed);  
            //  AnimationClock clock = scaleAnimation.CreateClock();  
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);

            //啟動平移動畫
            ts.BeginAnimation(TranslateTransform.XProperty, moveAnimation);








        }



        #endregion
        #region 左切換動畫-左向中動畫
        public void LefttoCenterAnimation()
        {
            b_left = Banners[Location.Left];

            Grid.SetZIndex(Banners[Location.Left], 3);

            GetOpacityGrid(b_left).Opacity = 0;

            ScaleTransform scale = new ScaleTransform();   //縮放  

            //scale.CenterX = 0;
            scale.CenterY = this.ActualHeight;
            TranslateTransform ts = new TranslateTransform();//平移


            TransformGroup group = new TransformGroup();
            group.Children.Add(scale);
            group.Children.Add(ts);


            Banners[Location.Left].RenderTransform = group;


            DoubleAnimation scaleAnimation = new DoubleAnimation()
            {

                From = 0.95,
                To = 1,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)


            };

            DoubleAnimation moveAnimation = new DoubleAnimation()
            {

                From = leftlocation,
                To = centerlocation,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)

            };

            scaleAnimation.Completed += new EventHandler(LeftAnimation_Completed);
            //  AnimationClock clock = scaleAnimation.CreateClock();  
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);

            //啟動平移動畫
            ts.BeginAnimation(TranslateTransform.XProperty, moveAnimation);









        }





        #endregion

        #region 動畫結束
        private void LeftAnimation_Completed(object sender, EventArgs e)
        {
            //動畫結束後将banner集合的位置重新設定
            Banners[Location.Left] = b_right;
            Banners[Location.Center] = b_left;
            Banners[Location.Right] = b_center;
            //此時動畫結束
            isplay = false;
            //啟動定時器
            TimerAnimationStart();
        }
        #endregion
        #endregion

        #region 右切換動畫
        public void RightAnimation()
        {
            timeranimation.Stop();

            isplay = true;

            LefttoRightAnimation();

            CentertoLeftAnimation();

            RighttoCenterAnimation();


        }

        #region 右切換動畫-左向右動畫
        public void LefttoRightAnimation()
        {
            b_left = Banners[Location.Left];
            Grid.SetZIndex(Banners[Location.Left], 1);
            GetOpacityGrid(b_left).Opacity = bopacity;
            ScaleTransform scale = new ScaleTransform();   //縮放  
            scale.CenterY = this.ActualHeight;


            TranslateTransform ts = new TranslateTransform();//平移


            TransformGroup group = new TransformGroup();
            group.Children.Add(scale);

            group.Children.Add(ts);


            Banners[Location.Left].RenderTransform = group;



            DoubleAnimation scaleAnimation = new DoubleAnimation()
            {
                From = 0.85,
                To = 0.95,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)


            };
            DoubleAnimation moveAnimation = new DoubleAnimation()
            {

                From = leftlocation,
                To = rightlocation,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)

            };

            scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);

            //啟動平移動畫
            ts.BeginAnimation(TranslateTransform.XProperty, moveAnimation);








        }



        #endregion
        #region 右切換動畫-中向左動畫
        public void CentertoLeftAnimation()
        {
            b_center = Banners[Location.Center];

            Grid.SetZIndex(Banners[Location.Center], 2);
            GetOpacityGrid(b_center).Opacity = bopacity;

            ScaleTransform scale = new ScaleTransform();   //縮放  
            scale.CenterY = this.ActualHeight;
            TranslateTransform ts = new TranslateTransform();//平移


            TransformGroup group = new TransformGroup();
            group.Children.Add(scale);
            group.Children.Add(ts);


            Banners[Location.Center].RenderTransform = group;


            DoubleAnimation scaleAnimation = new DoubleAnimation()
            {
                From = 1,
                To = 0.95,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)


            };

            DoubleAnimation moveAnimation = new DoubleAnimation()
            {

                From = centerlocation,
                To = leftlocation,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)

            };

            //scaleAnimation.Completed += new EventHandler(scaleAnimation_Completed);  
            //  AnimationClock clock = scaleAnimation.CreateClock();  
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);

            //啟動平移動畫
            ts.BeginAnimation(TranslateTransform.XProperty, moveAnimation);








        }



        #endregion
        #region 右切換動畫-右向中動畫
        public void RighttoCenterAnimation()
        {
            b_right = Banners[Location.Right];
            //SetZindex(b_right);
            Grid.SetZIndex(Banners[Location.Right], 3);

            GetOpacityGrid(b_right).Opacity = 0;

            ScaleTransform scale = new ScaleTransform();   //縮放  

            //scale.CenterX = 0;
            scale.CenterY = this.ActualHeight;
            TranslateTransform ts = new TranslateTransform();//平移


            TransformGroup group = new TransformGroup();
            group.Children.Add(scale);
            group.Children.Add(ts);


            Banners[Location.Right].RenderTransform = group;


            DoubleAnimation scaleAnimation = new DoubleAnimation()
            {
                To = 1,
                From = 0.95,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)


            };

            DoubleAnimation moveAnimation = new DoubleAnimation()
            {

                From = rightlocation,
                To = centerlocation,
                EasingFunction = easeFunction,
                Duration = TimeSpan.FromSeconds(AnimationTime)

            };

            scaleAnimation.Completed += new EventHandler(RightAnimation_Completed);
            //  AnimationClock clock = scaleAnimation.CreateClock();  
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);

            //啟動平移動畫
            ts.BeginAnimation(TranslateTransform.XProperty, moveAnimation);









        }






        #endregion
        #region 動畫結束
        private void RightAnimation_Completed(object sender, EventArgs e)
        {
            Banners[Location.Left] = b_center;
            Banners[Location.Center] = b_right;
            Banners[Location.Right] = b_left;
            isplay = false;
            TimerAnimationStart();
        }
        #endregion
        #endregion

        #region 初始化設定控件位置
        //定義一個枚舉類用于辨別左中右三個banner(border),友善操作時擷取到。
        public enum Location
        {
            Left, Center, Right
        }
        //設定三個border的大小和位置
        public void SetLocation(Location l, Border g)
        {

            //banner的大小
            g.Width = 540;
            g.Height = 200;
            
            //給除中間banner外的border縮小一些
            ScaleTransform scaleTransform = new ScaleTransform();
            scaleTransform.ScaleX = 0.95;
            scaleTransform.ScaleY = 0.95;
            scaleTransform.CenterY = this.ActualHeight;
            //擷取設定遮蓋層的透明度
            Grid opacity_grid = GetOpacityGrid(g);
            opacity_grid.Opacity = bopacity;
            switch (l)
            {
                case Location.Left:

                    TranslateTransform tt_left = new TranslateTransform()
                    {
                        X = 0
                    };
                    TransformGroup group_left = new TransformGroup();
                    group_left.Children.Add(tt_left);
                    group_left.Children.Add(scaleTransform);
                    g.RenderTransform = group_left;

                    break;
                case Location.Center:
                    opacity_grid.Opacity = 0;

                    TransformGroup group_center = new TransformGroup();

                    //計算中心banner的x位置
                    centerlocation = (this.ActualWidth - g.ActualWidth) / 2;
                    TranslateTransform tt_center = new TranslateTransform()
                    {
                        X = centerlocation
                    };
                    group_center.Children.Add(tt_center);
                    g.RenderTransform = group_center;
                    Grid.SetZIndex(g, 3);
                    break;
                case Location.Right:
                    //Grid.SetZIndex(g, 3);

                    //計算右banner的X位置
                    rightlocation = (this.ActualWidth - Banners[Location.Left].ActualWidth * 0.95);

                    TranslateTransform tt_right = new TranslateTransform()
                    {
                        X = rightlocation
                    };
                    TransformGroup group_right = new TransformGroup();
                    //這裡要注意先後順序,否則位置會有偏差,必須先縮放再設定X坐标。
                    group_right.Children.Add(scaleTransform);
                    group_right.Children.Add(tt_right);
                    g.RenderTransform = group_right;


                    break;
            }

        }
        #endregion

        //擷取透明覆寫層
        //代碼來自:https://www.cnblogs.com/udoless/p/3381411.html
        #region 擷取透明覆寫層
        public Grid GetOpacityGrid(DependencyObject g)
        {
            Grid opacity_grid = GetChild<Grid>(g, typeof(Grid));
            opacity_grid = GetChild<Grid>(opacity_grid, typeof(Grid));
            return opacity_grid;
        }
        public T GetChild<T>(DependencyObject obj, Type typename) where T : FrameworkElement
        {
            DependencyObject child = null;
            List<T> childList = new List<T>();

            for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
            {
                child = VisualTreeHelper.GetChild(obj, i);

                if (child is T && (((T)child).GetType() == typename))
                {
                    return ((T)child);
                }

            }
            return null;
        }
        #endregion

        #region 定時喚醒動畫
        public void TimerAnimationStart()
        {
            if (timeranimation.IsEnabled == false)
            {
              
                timeranimation.Start();
            }
            timeranimation.Tick += (e, c) =>
            {
                
                timeranimation.Stop();
                if (isplay == false)
                {
                    RightAnimation();
                }
            };
        }
        #endregion
    }
}      

前台

<UserControl x:Class="網易雲音樂Banner動畫.Controls.CloudMusicBanner"
             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"
             mc:Ignorable="d" 
                         
            
             d:DesignHeight="200" d:DesignWidth="762" MouseEnter="UserControl_MouseEnter" MouseLeave="UserControl_MouseLeave"
             
             >
    <Grid>
        <!--兩個圖示按鈕,滑鼠進入時顯示-->
        <Button Name="toleftbtn" Opacity="0" Click="toleftbtn_Click" BorderThickness="0" HorizontalAlignment="Left" Background="Transparent" Panel.ZIndex="99" Width="50" Height="50" Cursor="Hand">
            <Image Source="/網易雲音樂Banner動畫;component/Res/左.png" Width="16" Height="16"></Image>
        </Button>
        <Button Name="torightbtn" Opacity="{Binding ElementName=toleftbtn,Path=Opacity}" Click="torightbtn_Click" BorderThickness="0" HorizontalAlignment="Right" Background="Transparent" Panel.ZIndex="99" Width="50" Height="50" Cursor="Hand">
            <Image Source="/網易雲音樂Banner動畫;component/Res/右.png" Width="16" Height="16"></Image>
        </Button>
        
        <Grid  HorizontalAlignment="Left">


           <!--左邊的banner-->
            <Border BorderBrush="#000000" BorderThickness="0" Width="540" Name="left" Background="Black">
                <Grid>
                    <!--透明遮蓋層-->
                    <Grid Background="Black" Panel.ZIndex="2"></Grid>
                    <!--banner圖檔-->
                    <Image Source="/網易雲音樂Banner動畫;component/Res/banner1.jpg" Stretch="Fill"></Image>
                </Grid>
            </Border>

            <!--中間的banner-->
            <Border BorderBrush="#96b0b3" BorderThickness="0" Width="540" Name="center" Background="Yellow" >
                <Grid>
                    <Grid Background="Black" Panel.ZIndex="2"></Grid>
                    <Image Source="/網易雲音樂Banner動畫;component/Res/banner2.jpg" Stretch="Fill"></Image>
                </Grid>
            </Border>
            
            <!--右邊的banner-->
            <Border BorderBrush="#ab1491" BorderThickness="1" Name="right" Background="Red">
                <Grid>
                    <Grid Background="Black" Panel.ZIndex="2"></Grid>
                    <Image Source="/網易雲音樂Banner動畫;component/Res/banner3.jpg" Stretch="Fill"></Image>
                </Grid>

            </Border>
            
        </Grid>
    </Grid>
</UserControl>      

被你發現了

項目下載下傳在這

點我下載下傳項目源碼

繼續閱讀