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
{
/// <summary>
/// CloudMusicBanner.xaml 的交互逻辑
/// </summary>
public partial class CloudMusicBanner : UserControl
{ //代码所用涉及时间单位均是:秒
#region 一些变量
//左、中、右三张banner的位置
double leftlocation = , centerlocation = , rightlocation = ;
//每张banner的动画执行时间
double AnimationTime = 0.4;
//非中间banner的遮盖层透明度
double bopacity = 0.65;
//没有交互时动画自动执行间隔时间
double timeranimation_time = ;
//动画播放状态(当前动画是否在执行)
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 = ;
} private void UserControl_MouseLeave(object sender, MouseEventArgs e)
{
//鼠标移出控件时隐藏两个“左/右”图标按钮 toleftbtn.Opacity = ;
} 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], ); //获取透明遮盖图层,设置透明度
/*
* <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 = ,
//到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], );
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], ); GetOpacityGrid(b_left).Opacity = ; 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 = ,
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], );
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], );
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 = ,
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], ); GetOpacityGrid(b_right).Opacity = ; 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 = ,
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 = ;
g.Height = ; //给除中间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 =
};
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 = ; TransformGroup group_center = new TransformGroup(); //计算中心banner的x位置
centerlocation = (this.ActualWidth - g.ActualWidth) / ;
TranslateTransform tt_center = new TranslateTransform()
{
X = centerlocation
};
group_center.Children.Add(tt_center);
g.RenderTransform = group_center;
Grid.SetZIndex(g, );
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 = ; i <= VisualTreeHelper.GetChildrenCount(obj) - ; 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>
被你发现了
项目下载在这
C# WPF 低仿网易云音乐(PC)Banner动画控件的更多相关文章
- C# WPF 低仿网易云音乐(PC)歌词控件
原文:C# WPF 低仿网易云音乐(PC)歌词控件 提醒:本篇博客记录了修改的过程,废话比较多,需要项目源码和看演示效果的直接拉到文章最底部~ 网易云音乐获取歌词的api地址 http://music ...
- 网易云音乐PC端刷曲快捷键
文章首发于szhshp的第三边境研究所(szhshp.org), 转载请注明 网易云音乐PC端刷曲快捷键 好吧我承认我特别懒 云音乐其实做的还不错,FM推荐的算法明显比虾米好. 虾米可以听的曲子都 ...
- 《云阅》一个仿网易云音乐UI,使用Gank.Io及豆瓣Api开发的开源项目
CloudReader 一款基于网易云音乐UI,使用GankIo及豆瓣api开发的符合Google Material Desgin阅读类的开源项目.项目采取的是Retrofit + RxJava + ...
- 网易云音乐PC客户端加密API逆向解析
1.前言 网上已经有大量的web端接口解析的方法了,但是对客户端的接口解析基本上找不到什么资料,本文主要分析网易云音乐PC客户端的API接口交互方式. 通过内部的代理设置,使用fiddler作为代理工 ...
- Flutter仿网易云音乐:播放界面
写在前头 本来是要做一个仿网易云音乐的flutter项目,但是因为最近事情比较多,项目周期跨度会比较长,因此分几个步骤来完成.这是仿网易云音乐项目系列文章的第一篇.没有完全照搬网易云音乐的UI,借鉴了 ...
- 新鲜出炉高仿网易云音乐 APP
我的引语 晚上好,我是吴小龙同学,我的公众号「一分钟GitHub」会推荐 GitHub 上好玩的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注我. 项目中成长是最快的,如何成长,就 ...
- C# WPF 仿网易云音乐(PC)Banner动画控件
在自定义用户控件内添加3个border(左.中.右,以下分别简称为:b1.b2.b3),对border进行缩放和移动动画.往右切换时b1放大平移到b2的位置,b2缩小平移到b3的位置,b3平移到b1的 ...
- WPF仿网易云音乐系列(一、左侧菜单栏:Expander+RadioButton)
1.简介 上一篇咱们说到,网易云音乐的左侧菜单栏可以通过Expander+RadioButton来实现,具体如何实现,咱们下面开始干: 首先来一张网易云音乐PC版原图(个人觉得PC版比UWP版左侧菜单 ...
- WPF仿网易云音乐系列(序)
1.简介 由于之前做了一个播放器,苦于不懂界面设计,只得去借鉴借鉴一些成功的作品,网易云音乐就甚合朕心,哈哈,最后做出来的效果如下: 本系列文章就来和大家讨论以下,如何用WPF去仿制一个网易云音乐来: ...
随机推荐
- 快速理解Java中的五种单例模式(转)
解法一:只适合单线程环境(不好) package test; /** * @author xiaoping * */ public class Singleton { private static S ...
- 分析Net 内存对象
.Net 内存对象分析 在生产环境中,通过运行日志我们会发现一些异常问题,此时,我们不能直接拿VS远程到服务器上调试,同时日志输出的信息无法百分百反映内存中对象的状态,比如说我们想查看进程中所有的 ...
- python画最最简单的折线图
# encoding=utf-8import matplotlib.pyplot as pltfrom pylab import * #支持中文mpl.rcParams['font.sans-seri ...
- 从Set里面取出有序的记录
Set里面的记录是无序的.假设想使用Set,然后又想里面的记录是有序的,就能够使用TreeSet.而不是HashSet.在使用TreeSet的时候,里面的元素必须是实现了Comparable接口的,T ...
- php 静态方法和非静态方法的调用说明
1. php类中,静态方法调用当前类的非静态方法必须用self关键字,不能用$this 2. php类中,公有方法调用私有方法使用$this关键字,只能实例化调用 3. php类中,公有方法调用私有方 ...
- 【42.38%】【BZOJ 3196】二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1363 Solved: 579 [Submit][Status][Discuss] Descripti ...
- 多校 hdu
欢迎參加--每周六晚的BestCoder(有米!) Solve this interesting problem Time Limit: 2000/1000 MS (Java/Others) M ...
- Android JAVA中的时间大小比较
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; imp ...
- 号外:小雷将开发一款Java版的简易CMS系统
我的个人官网: http://FansUnion.cn 已经改版,隆重上线了,欢迎关注~持续升级中... 出于个人兴趣.技术总结.工作相关,我终于想要做一个简单的CMS系统了. 原来想研究,D ...
- todo bitnami
https://bitnami.com/stack/dokuwiki https://bitnami.com/stack/jenkins/installer