1. 程式人生 > >C# WPF 低仿網易雲音樂(PC)Banner動畫控制元件

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

被你發現了

專案下載在這

點我下載專案原始碼