C# WPF 低仿网易云音乐(PC)Banner动画控件

原文: C# WPF 低仿网易云音乐(PC)Banner动画控件

由于技术有限没能做到一模一样的动画,只是粗略地做了一下。动画有点生硬,还有就是没做出网易云音乐的立体感。代码非常简单粗暴,而且我也写有很多注释,这里就不多啰嗦了,直接贴代码。

算了,啰嗦几句。原理是这样的,在自定义用户控件内添加3个border(左、中、右,以下分别简称为:b1、b2、b3),对border进行缩放和移动动画。往右切换时b1放大平移到b2的位置,b2缩小平移到b3的位置,b3平移到b1的位置,动画结束后重新记录3个border的左、中、右位置,然后如此循环。一次滚动有三个动画,分别写了3个方法来定义。

可加上透明动画、阴影,应该会更加好看些。

没有实现调用的方法,只是个纯动画项目,图片也是写死在前台代码中,需要在项目中使用时自行简单地修改即可。

 

低仿效果

网易云音乐原版

 

代码

后台

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
{
    /// 
    /// CloudMusicBanner.xaml 的交互逻辑
    /// 
    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 Banners = new Dictionary();
        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);

            //获取透明遮盖图层,设置透明度
            /*
             * 
             * 透明遮盖图层在设计代码中的每个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(g, typeof(Grid));
            opacity_grid = GetChild(opacity_grid, typeof(Grid));
            return opacity_grid;
        }
        public T GetChild(DependencyObject obj, Type typename) where T : FrameworkElement
        {
            DependencyObject child = null;
            List childList = new List();

            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">


           
            <Border BorderBrush="#000000" BorderThickness="0" Width="540" Name="left" Background="Black">
                <Grid>
                    
                    <Grid Background="Black" Panel.ZIndex="2">Grid>
                    
                    <Image Source="/网易云音乐Banner动画;component/Res/banner1.jpg" Stretch="Fill">Image>
                Grid>
            Border>

            
            <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>
            
            
            <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>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

被你发现了

项目下载在这

点我下载项目源码

你可能感兴趣的:(C# WPF 低仿网易云音乐(PC)Banner动画控件)