原文: C# WPF 低仿網易雲音樂(PC)Banner動畫控件
由于技術有限沒能做到一模一樣的動畫,隻是粗略地做了一下。動畫有點生硬,還有就是沒做出網易雲音樂的立體感。代碼非常簡單粗暴,而且我也寫有很多注釋,這裡就不多啰嗦了,直接貼代碼。
算了,啰嗦幾句。原理是這樣的,在自定義使用者控件内添加3個border(左、中、右,以下分别簡稱為:b1、b2、b3),對border進行縮放和移動動畫。往右切換時b1放大平移到b2的位置,b2縮小平移到b3的位置,b3平移到b1的位置,動畫結束後重新記錄3個border的左、中、右位置,然後如此循環。一次滾動有三個動畫,分别寫了3個方法來定義。
可加上透明動畫、陰影,應該會更加好看些。
沒有實作調用的方法,隻是個純動畫項目,圖檔也是寫死在前台代碼中,需要在項目中使用時自行簡單地修改即可。
低仿效果
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuImYhFmZ1MTNyMjYidzYzEjY0YmY3YzN1kTY0kTM2cjMfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
代碼
背景
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>
被你發現了
項目下載下傳在這
點我下載下傳項目源碼