本系列可能會伴隨你們很長時間,這裏我會從0開始搭建一個「網易雲音樂」的APP出來。git
下面是該APP 功能的思惟導圖:github
前期回顧:微信
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(1、建立項目、添加插件、通用代碼)
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(2、Splash Page、登陸頁、發現頁)
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(3、每日推薦、推薦歌單)
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(4、排行榜、播放頁面)
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(5、播放功能邏輯)
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(6、歌詞(一))
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(7、歌詞(二))
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(8、個人頁面)
本篇爲第九篇,在這裏咱們會搭建「搜索頁面、底部播放控制欄」。ide
搜索頁 | 搜索結果頁 |
---|---|
![]() |
![]() |
上一週一直沒更新代碼與文章,是由於公司公費去廈門旅遊來着,因此好好放鬆了一週。佈局
這周開始恢復代碼與文章的更新,最近收到不少童鞋反饋說比較卡,字體
我建議加我我的微信「17610912320」,來探討一下是哪一個地方,具體在哪裏卡。ui
也歡迎 PR,讓咱們一塊兒爲這個項目添磚加瓦!this
話很少說,接着就來咱們的搜索頁,先看一下圖,而後梳理一下需求:spa
先來搞歷史記錄,歷史記錄確定是要存在咱們本地的,那就須要用到 shared_preferences
了。插件
這方面的就很少說了,看看文檔,都懂的。
而後是 UI,不知道有沒有童鞋記得我之前寫過一篇文章:Flutter Wrap & Chip。
在這裏徹底就能用得上,並且不須要那麼多花裏胡哨的,只有一個文字就好了。
來看一下如何定義:
Wrap(
spacing: ScreenUtil().setWidth(20),
children: historySearchList
.map((v) => GestureDetector(
onTap: () {
searchText = v;
_search();
},
child: Chip(
label: Text(
v,
style: common14TextStyle,
),
backgroundColor: Color(0xFFf2f2f2),
),
))
.toList(),
),
複製代碼
邏輯以下:
Wrap
包裹住 chip
chip
的間隔爲 20historySearchList
的數據來返回 chip
chip
的背景顏色便可可是,不要忘了咱們還有「清空歷史記錄」的功能,頁面以下:
在點擊 小垃圾桶的時候彈出,這個也很簡單:
IconButton(
icon: Icon(
Icons.delete_outline,
color: Colors.grey,
),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(
"肯定清空所有歷史記錄?",
style: common14GrayTextStyle,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('取消'),
textColor: Colors.red,
),
FlatButton(
onPressed: () {
setState(() {
historySearchList.clear();
Application.sp.remove("search_history");
});
Navigator.of(context).pop();
},
child: Text('清空'),
textColor: Colors.red,
),
],
);
});
},
)
複製代碼
在點擊這個 IconButton
的時候調用 showDialog
方法,而後根據點擊的按鈕作相應的操做便可。
熱搜榜這個就更簡單了,直接就是一個 ListView
。
剛開始看到這個佈局的時候想到的是 ListTile
,可是間距什麼的很差控制,因此只能本身寫了。
Text(
curData.searchWord,
style: index < 3
? w500_16TextStyle
: common16TextStyle,
),
複製代碼
最前面排名字體顏色的控制直接用 index
就ok,後面的也沒什麼好說的,直接擼就完了。
搜索結果頁實際上是和「搜索頁」在一塊兒的,由搜索狀態控制:
_isSearching ? _buildSearchingPage() : _buildUnSearchingPage();
複製代碼
搜索結果頁分 7 頁:
其中「綜合」頁面包含了剩下的每一頁的UI,因此咱們在寫「綜合」頁面的時候每個控件都封裝一下。
具體UI上面就不說了,有一個須要注意的地方就是:
在綜合頁面須要跳轉別的頁面,這裏我使用的是在建立「綜合」頁面的時候傳入點擊事件,而後在點擊的時候調用:
SearchMultipleResultPage(this.keywords,
{@required this.onTapMore, @required this.onTapSimText});
複製代碼
最後在主頁面用 controller
來控制就行了。
接到不少人反饋說找不到當前聽的是哪首歌😅,
當時以爲這個東西比較簡單,就沒有寫,昨天花了一點時間給寫完了。
我爲何說他簡單呢。。。不是我裝x,是真的簡單,聽我說!
咱們在編寫播放頁面的時候就已經把關於歌曲播放功能的 model:PlaySongsModel
給寫好了,全部的功能都在這裏,因此咱們想要寫一個「播放控制欄」真的是分分鐘搞定。
so,控制欄邏輯以下:
第一個保存,很簡單了,使用 shared_preferences
:
// 保存當前歌曲到本地
void saveCurSong(){
Application.sp.remove('playing_songs');
Application.sp.setStringList('playing_songs', _songs.map((s) => FluroConvertUtils.object2string(s)).toList());
Application.sp.setInt('playing_index', curIndex);
}
複製代碼
第二個取出數據:
// 判斷是否有保存的歌曲列表
if(Application.sp.containsKey('playing_songs')){
List<String> songs = Application.sp.getStringList('playing_songs');
playSongsModel.addSongs(songs.map((s) => Song.fromJson(FluroConvertUtils.string2map(s))).toList());
int index = Application.sp.getInt('playing_index');
playSongsModel.curIndex = index;
}
複製代碼
關於UI更新什麼的根本不須要考慮,Provider
直接搞定了,什麼邏輯都不用寫。
暫停播放之類的,點擊事件以下:
GestureDetector(
onTap: (){
if(model.curState == null){
model.play();
}else {
model.togglePlay();
}
}
)
複製代碼
當咱們從新打開APP的時候,這個時候 curState
是 null,這個時候咱們調用 恢復/暫停 方法是沒有效果的,因此咱們要先調用 play()
方法。
還有一個地方須要注意,在 iPhone 上有些是有「控制條」的,因此咱們要加上這個高度:
height: ScreenUtil().setWidth(110) + Application.bottomBarHeight
複製代碼
寫好之後在須要使用的頁面加上就好了。
感受大部分功能已經完成,可是看了一下思惟導圖。。。慢慢來吧!
你們若是有好的建議的話,歡迎提 issue,我會在第一時間回覆。
該系列文章代碼已傳至 GitHub:github.com/wanglu1209/…
另我我的建立了一個「Flutter 交流羣」,能夠添加我我的微信 「17610912320」來入羣。