本系列可能會伴隨大家很長時間,這裡我會從0開始搭建一個「網易雲音樂」的APP出來。
下面是該APP 功能的思維導圖:
前期回顧:
本篇為第四篇,在這裡我們會搭建排行榜頁面、播放歌曲頁面。
排行榜頁面
先來看圖:
頁面很簡單,兩個列表:
- 官方榜 -> ListView
- 更多榜單 -> GridView
注意:這裡一定要使用這個介面,才會出現每個榜單中的1. 2. 3. 首歌。
話不多說,直接來看介面返回值:
返回值大致如此(刪除了一部分用不到的資料)。
可以看到我標了兩個紅框框,這就是該介面 list
引數中不一樣的地方:一個有歌,一個沒有歌。
這代表了什麼?這就是官方榜單和更多榜單的區別!
既然如此,區分的程式碼就如下了:
var officialTopListData =
data.list.where((l) => l.tracks.isNotEmpty).toList(); // 官方榜的資料
var moreTopListData =
data.list.where((l) => l.tracks.isEmpty).toList(); // 更多榜單的資料
複製程式碼
只需要判斷 tracks
的資料是否為空就好了。
然後就只需要根據各自的資料來建立列表就好了。
不過我這裡「官方榜」也是列表的一部分。所以在點選 index 的時候,不要忘記 -1。
接下來就是跳轉到「榜單詳情頁」。
因為開始在檢視介面文件的過程中,找到了這樣一段:
當時就想著在「榜單介面」中找到該id,但是我發現根本沒有!
然而就當我絕望的時候在 GitHub 的 issue 中找到這麼一段對話:
啊!!瞬間幸福感爆棚!頁面我都不用寫了,直接用原來的「歌單」頁面就好了!
so easy!
播放歌曲頁面
「播放歌曲頁面」可以說是整個APP的靈魂所在。
邏輯什麼的之後再說,這節就單單來說UI。
如圖所示:
播放 | 暫停 |
---|---|
從上到下,七個部分:
- 標題(主標題、副標題)
- 唱針
- 碟片
- 對該歌曲的操作(喜歡、下載等)
- 進度條
- 對播放的操作(暫停、下一首等)
- 最後還有一個背景
1. 標題
首先,這裡的標題是兩行的。
AppBar 的title 需要的是一個 Widget,那我們就可以隨意操作:
title: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
model.curSong.name,
style: commonWhiteTextStyle,
),
Text(
model.curSong.artists,
style: smallWhite70TextStyle,
),
],
)
複製程式碼
2. 唱針
裝在唱機唱頭上的針,一般由鋼或人造寶石製成。它跟隨聲盤紋道的調製,把所得機械運動傳送給唱頭的換能元件,使之轉換為相應的聲頻訊號。
這裡的唱針是一個圖片,他的作用就是移開,放上,也就是對應著 播放、暫停。
這裡有個問題是,唱針是個圖片,我們要對該圖片進行旋轉操作,
而旋轉的中心點左上角圖中1的位置:
那我們就要對整個圖片做一個瞭解,首先看看這個中心在原圖的哪裡:
用自帶的看圖工具大致看一下,在 45 * 45 的位置,然後檢視一下原圖的尺寸:
有了這兩個引數我們就好定義中心點:
RotationTransition(
turns: _stylusAnimation,
alignment: Alignment(
-1 +
(ScreenUtil().setWidth(45 * 2) /
(ScreenUtil().setWidth(293))),
-1 +
(ScreenUtil().setWidth(45 * 2) /
(ScreenUtil().setWidth(504)))),
child: Image.asset(
'images/bgm.png',
width: ScreenUtil().setWidth(146.5),
height: ScreenUtil().setWidth(252),
),
),
複製程式碼
首先我們設定該圖片的寬高比和原圖一致。
然後定義 Alignment,注意:
Alignment 左上角的值為:Alignment(-1.0, -1.0)
,
中心點的的值為:Alignment(0.0, 0.0)
,
右下角的值為:Alignment(1.0, 1.0)
;
從上面我們可以看得出來,Alignment 是從中心開始的座標系,左和上為負數、右和下為正數。
那我們控制唱針的中心是在左上角,所以肯定是負數,所以我們用 -1+。
而既然是從中心開始的,那麼計算的時候要用剛才看到的座標 * 2 / 寬(高)。
這樣得到的值才是準確的。
3. 碟片
我們所看到的碟片有兩種狀態:
- 正在轉
- 停止
也是正好對應上 播放和暫停。
旋轉的就不多說了,RotationTransition
瞭解一下。
監聽一下狀態,在完成的時候繼續就可以了。
4. 對該歌曲的操作(喜歡、下載等)
這個就比較簡單了,一個Row 裡面全是 Expanded
就可以了。
大致程式碼如下:
5. 進度條
進度條也很簡單,但是邏輯稍微複雜一點,我們後續再說。
進度條使用 Slider
就可以了。
關於 Slider
的樣式,程式碼如下:
SliderTheme(
data: SliderThemeData(
trackHeight: ScreenUtil().setWidth(2),
thumbShape: RoundSliderThumbShape(
enabledThumbRadius: ScreenUtil().setWidth(10),
),
),
child: Slider(
value: double.parse(curTime),
onChanged: (data) {},
onChangeStart: (data){
model.pausePlay();
},
onChangeEnd: (data){
model.seekPlay(data.toInt());
},
activeColor: Colors.white,
inactiveColor: Colors.white30,
min: 0,
max: double.parse(totalTime),
),
),
複製程式碼
在 Slider
上面套上 SliderTheme
就可以了。
6. 對播放的操作(暫停、下一首等)
這個也沒什麼好說的了,和上面對歌曲的操作一樣。封裝上一個元件,然後呼叫就好了。
7. 背景
背景還是使用的 BackdropFilter
,引數 sigma
設定成100。
這裡模擬器和真機是有區別的,在模擬器上最多設定成20,再大就花了。
所以我建議跑播放歌曲的時候,最好用真機,不然會卡的要命。。
總結
這一章節我們搭建了排行榜頁面、播放歌曲頁面。
其中「播放歌曲」頁面是該APP的一個難點和重點。
我這裡的邏輯也還沒有寫完,後續會慢慢捋出來發文的。
該系列文章程式碼已傳至 GitHub:github.com/wanglu1209/…
另我個人建立了一個「Flutter 交流群」,可以新增我個人微信 「17610912320」來入群。