C# WPF 歌詞控制元件(支援逐字定位描色效果)
之前做了一個模仿網易雲歌詞的控制元件,實現了載入網易雲歌詞並能隨音樂播放進度定位歌詞。今天呢將在這個控制元件的基礎上增加逐字定位描色功能,如下圖效果(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獲取: