WPF实现仿网易云唱片图标

enter description here

相信大家对于网易云音乐并不陌生,仔细发现,每当我们点击播放和暂停音乐的时候,歌词左侧的唱片控件都会发生一些小变化。在人们的视野中,动态的物体总是那么引人注意,下面我将来说下如何用WPF实现这一效果,与大家共同分享

前期思考

  • 实现该效果可分为两个步骤:
    • 实现唱片的旋转
    • 实现指针的旋转

刚开始分析的时候,我是用Button来控制唱片的转动暂停的,但是后来发现Button的点击事件只能控制一种状态(既只能控制转动或者暂停),后来经过网上查阅了之后发现可以使用ToggleButton替换Button

ToggleButton也称为状态按钮,可以用过一个按钮切换多种状态(比如灯的ON/OFF)

  • 该控件有一个IsChecked属性,IsChecked的值有三种,分别是True,False,NullToggleButton的事件如下:
    • Checked:当IsChecked为True时,触发此事件
    • UnChecked:当IsChecked为False时,触发此事件
    • Indeterminate:当IsChecked为Null时,触发此事件

先来看一下最终的效果吧(由于没弄成gif动态图,只能上个图片了)!!!
暂停时的效果
播放时的效果

唱片旋转

唱片旋转是通过Storyboard(故事板)实现XAML代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<Window x:Class="黑胶唱片旋转.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:黑胶唱片旋转"
Background="#CCC"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="800">
<Grid>
<Image x:Name="黑胶唱片" Width="200" Height="200" Source="Resources/Images/黑胶唱片外层.png" >
<Image.RenderTransform>
<RotateTransform x:Name="recordTs" Angle="0"></RotateTransform>
</Image.RenderTransform>
</Image>
<ToggleButton x:Name="playMusic" Content="播放" Margin="321,423,321,90" RenderTransformOrigin="0.575,1.538" Click="playMusic_Click">
<ToggleButton.Triggers>
<EventTrigger RoutedEvent="ToggleButton.Checked">
<BeginStoryboard x:Name="beginRecord">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="recordTs" Storyboard.TargetProperty="Angle" By="360" RepeatBehavior="Forever" Duration="0:0:10"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="ToggleButton.Unchecked">
<PauseStoryboard BeginStoryboardName="beginRecord"></PauseStoryboard>
</EventTrigger>
</ToggleButton.Triggers>
</ToggleButton>
</Grid>
</Window>

通过此代码可以通过一个ToggleButton按钮控制图片的旋转和暂停,但是你会发现有一个问题就是:图片默认是沿着左上角为中心点旋转的,而不是沿着图片的中心旋转的。

那么该如何解决这个问题呢?我有个思路:由于我们可以通过获取图片的左上角旋转点的位置,设左上角旋转点的坐标为(centerX,centerY),这样我们再获取图片的宽(width)高(height),通过(centerX + width/2)获得图片的中心点横坐标CenterX,通过(centerY + height/2)获得图片的中心点纵坐标CenterY(CenterX, CenterY)既为图片在平面上的中心点了。代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/// <summary>
/// 设置唱片的旋转中心点
/// </summary>
public void SetCenterPoint()
{
double width = 黑胶唱片.Width;
double height = 黑胶唱片.Height;
double centerX = recordTs.CenterX + (width / 2);
double centerY = recordTs.CenterY + (height / 2);
recordTs.CenterX = centerX;
recordTs.CenterY = centerY;
}


指针旋转

通过上面这个步骤,唱片旋转已经实现,现在还缺少一根指针。该指针会随着ToggleButton的不同状态处于不同的位置(当ToggleButton处于播放状态时,该指针会与唱片接触,当ToggleButton处于暂停状态时,该指针会与唱片分离),实现这个效果的思想还是和实现唱片旋转类似,下面附上XAML的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<Window x:Class="黑胶唱片旋转.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:黑胶唱片旋转"
Background="#CCC"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="800">
<Grid>
<Image x:Name="指针唱片" Source="Resources/Images/唱片指针.png" Width="200" Margin="296,116,296,333" >
<Image.RenderTransform>
<RotateTransform x:Name="pointerTs" Angle="0"/>
</Image.RenderTransform>
</Image>
<ToggleButton x:Name="playMusic" Content="播放" Margin="321,423,321,90" RenderTransformOrigin="0.575,1.538" Click="playMusic_Click">
<ToggleButton.Triggers>
<EventTrigger RoutedEvent="ToggleButton.Checked"> <BeginStoryboard x:Name="beginPointer">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="pointerTs" Storyboard.TargetProperty="Angle" To="10" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="ToggleButton.Unchecked">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="pointerTs" Storyboard.TargetProperty="Angle" To="0" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToggleButton.Triggers>
</ToggleButton>
</Grid>
</Window>


整合唱片和指针

上面的两个步骤已经实现通过按钮实现按钮和指针的旋转了,现在对两者进行整合,附上完整代码如下:

  • XAML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    <Window x:Class="黑胶唱片旋转.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:黑胶唱片旋转"
    Background="#CCC"
    mc:Ignorable="d"
    Title="MainWindow" Height="600" Width="800">
    <Grid>
    <Image x:Name="黑胶唱片" Width="200" Height="200" Source="Resources/Images/黑胶唱片外层.png" >
    <Image.RenderTransform>
    <RotateTransform x:Name="recordTs" Angle="0"></RotateTransform>
    </Image.RenderTransform>
    </Image>
    <Image x:Name="指针唱片" Source="Resources/Images/唱片指针.png" Width="200" Margin="296,116,296,333" >
    <Image.RenderTransform>
    <RotateTransform x:Name="pointerTs" Angle="0"/>
    </Image.RenderTransform>
    </Image>
    <ToggleButton x:Name="playMusic" Content="播放" Margin="321,423,321,90" RenderTransformOrigin="0.575,1.538" Click="playMusic_Click">
    <ToggleButton.Triggers>
    <EventTrigger RoutedEvent="ToggleButton.Checked">
    <BeginStoryboard x:Name="beginRecord">
    <Storyboard>
    <DoubleAnimation Storyboard.TargetName="recordTs" Storyboard.TargetProperty="Angle" By="360" RepeatBehavior="Forever" Duration="0:0:10"></DoubleAnimation>
    </Storyboard>
    </BeginStoryboard>
    <BeginStoryboard x:Name="beginPointer">
    <Storyboard>
    <DoubleAnimation Storyboard.TargetName="pointerTs" Storyboard.TargetProperty="Angle" To="10" Duration="0:0:1"/>
    </Storyboard>
    </BeginStoryboard>
    </EventTrigger>
    <EventTrigger RoutedEvent="ToggleButton.Unchecked">
    <PauseStoryboard BeginStoryboardName="beginRecord"></PauseStoryboard>
    <BeginStoryboard>
    <Storyboard>
    <DoubleAnimation Storyboard.TargetName="pointerTs" Storyboard.TargetProperty="Angle" To="0" Duration="0:0:1"/>
    </Storyboard>
    </BeginStoryboard>
    </EventTrigger>
    </ToggleButton.Triggers>
    </ToggleButton>
    </Grid>
    </Window>
  • cs代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    using System;
    using System.Windows;
    namespace 黑胶唱片旋转
    {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
    private static Boolean isPlay = false;
    public MainWindow()
    {
    InitializeComponent();
    SetCenterPoint();
    }
    /// <summary>
    /// 设置唱片的旋转中心点
    /// </summary>
    public void SetCenterPoint()
    {
    double width = 黑胶唱片.Width;
    double height = 黑胶唱片.Height;
    double centerX = recordTs.CenterX + (width / 2);
    double centerY = recordTs.CenterY + (height / 2);
    recordTs.CenterX = centerX;
    recordTs.CenterY = centerY;
    }
    /// <summary>
    /// 根据按钮状态的改变修改按钮的文字
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void playMusic_Click(object sender, RoutedEventArgs e)
    {
    isPlay = !isPlay;
    if (playMusic.IsChecked == true)
    {
    playMusic.Content = "暂停";
    }else if(playMusic.IsChecked == false)
    {
    playMusic.Content = "播放";
    }
    }
    }
    }

初识WPF,如果你有更好的想法,可以与我共同分享,

版权声明:本文为博主原创文章,转载请注明出处http://hunterblog.cn/ 和作者:Hunter,谢谢支持。