之前做了一个模仿网易云歌词的控件,实现了加载网易云歌词并能随音乐播放进度定位歌词。今天呢将在这个控件的基础上增加逐字定位描色功能,如下图效果(QQ音乐PC)所示:
我所使用的实现方法很简单粗暴,把每句歌词每个字切开,单独显示在一个描色的控件中,然后拼成一行完整的歌词,随音乐播放进度去找相应的字进行描色。
而最重要的描色功能是怎么实现的呢?
答案是:使用ClipToBounds属性
当控件ClipToBounds属性为TRUE时,超出控件范围的内容将会被裁剪掉不显示。现在你应该能明白描色功能怎么实现了吧?
在一个自定义控件中有两个Label,设置一个为置顶(ZINDEX最大)显示并加上颜色,给顶部的这个Label设置ClipToBounds属性为TRUE,然后默认顶部的Label宽度为0,描色的过程就把顶部的Label宽度慢慢增加。
最终完成的效果如下图,为了更直观地看到效果我给两个Label都加上了不同的背景颜色:
当然描色时间我没调好。当进度到达某个字时就调用那个字的控件执行一个宽度动画,动画目标就是置顶的Label,动画时间就是唱这个字所花费的时间。
这里就不把项目所有代码贴出来了,因为都是些简单的调用和判断而已,只贴描色的部分代码。
歌词负责描色的控件如下,每个字都单独显示在这个控件中
<Grid Background="Yellow"> <!--描色层--> <Canvas Background="Black" HorizontalAlignment="Left" ClipToBounds="True" Name="ColorLayer" Panel.ZIndex="1"> <Label Name="ColorWordLabel" Foreground="Red">测</Label> </Canvas> <Label Name="WordLabel" >测</Label> </Grid>
double tovalue = WordLabel.ActualWidth; widthAnimation.From = 0; widthAnimation.To = tovalue; widthAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Time)); ColorLayer.BeginAnimation(WidthProperty, widthAnimation);
后台代码的描色其实就是播放一个动画,动画操作了带有颜色的字体控件宽度,也就是ColorLayer控件,宽度从From 0开始到 To WordLabel的实际宽度,播放所需时间Duration是Time(毫秒单位),就这几句代码完成了描色的过程。
完整项目下载:
要知道普通的LRC格式歌词是没有记录每个字的吟唱时间的,而QQ音乐、酷狗音乐的歌词文件都经过不同算法的加密保护,没法直接读取,所以在这个项目中我将自己创建一个歌词格式。
那么歌词文件必须要包含以下信息:
1,完整歌词;
2,每句歌词的开始时间;
3,每句歌词每个字的吟唱耗时;
为了方便读写将使用JSON的数据格式来保存。
计划:
- 制作一个简单的描色歌词制作工具(参考酷狗音乐的歌词制作工具),在读取普通的LRC歌词后能可视化地去编辑每个字的吟唱时间,生成项目专用的歌词文件; [√]
- 单独分离成一个控件; [√]
- 性能优化; [×]
------------------------------------------------------------------------------------------------------
经过不断地缝缝补补和复制粘贴,已经完成了计划中的1、2。(2018年4月28日
首先说第1项,歌词制作工具,在播放音乐的同时调整描色的进度,将吟唱时间记录到歌词数据中,导出控件专用的NRC歌词数据格式方便调用。制作描色的时候决定了歌词描色的准确与否,而且还必须得比较熟悉歌曲才能制作出完美的描色歌词,这点有待改进。
所有歌词都调整描色完毕之后点击导出NRC文件即可完成制作,如果在没有将所有字描色完成之前导出会导致歌词显示控件无法正常描色定位。操作方式跟酷狗的歌词制作工具差不多,按键盘上键切到上一个字,下键切到下一个字。酷狗歌词制作工具制作的描色歌词好像会进行后期计算调整,更加准确,以后会想办法实现。
歌词制作工具的调用步骤是:
1,载入歌词(可以是网易云的或者是NRC的)
2,设置音乐的路径
然后启动工具点击play就可以开始制作了(最好是一遍过,反复调整的话很麻烦)
最后是我用制作工具制作的NRC歌词播放效果演示:
歌词显示已经单独分离成一个控件了,调用方法如下:
1,加载歌词:
控件.LoadNRC(歌词字符串);//歌词字符串可以是网易云的也可以是NRC的
2,在播放音乐开始时实时调用此方法更新歌词:
控件.UpdatePositionTime(播放进度总毫秒);
3,调整音乐进度后要调用此方法重新定位歌词:
控件.ResetPositionTime(播放进度总毫秒);
4,暂停音乐时调用此方法(同时不要再UpdatePositionTime):
控件.Pause();
控件源码、调用示例源码、歌词制作工具源码请通过Github获取: