本系列可能會伴隨你們很長時間,這裏我會從0開始搭建一個「網易雲音樂」的APP出來。git
下面是該APP 功能的思惟導圖:github
前期回顧:微信
本篇爲第八篇,在這裏咱們會搭建「個人」頁面。ide
個人 | 新建歌單 | 歌單操做 |
---|---|---|
仍是老套路,先確認一下需求。動畫
「個人」頁面,我這裏作的比較簡單,上面的UI(本地音樂等)目前只是用來展現用,真正的功能有以下幾點:ui
下面就開始吧。spa
首先咱們先想一下,整個 APP 中對於歌單操做的位置實際上是很是多的(搜索後添加歌單、推薦歌單裏添加歌單、給歌單添加歌曲等等),那麼對於這種需求,我所考慮的就是把歌單的邏輯放入頂層 Provider
中,這樣方便操做。插件
理清楚邏輯後,來看頁面如何展現:3d
一共分爲兩塊:「建立的歌單」、「收藏的歌單」。code
兩個模塊的 UI 實際上是同樣的,只不過度在了不一樣的列表中。
那麼先來看一下返回的數據是什麼樣的:
emmm,只返回了一個 playlist,那就說明要讓咱們本身來找這兩個的區別了。
通過我一番查找後發現,不一樣類型的 Creator
值是不同的,「我建立的歌單」裏的數據 Creator.userId
是等於我登陸後我的 id 的, 因此區分的代碼以下:
_selfCreatePlayList =
_allPlayList.where((p) => p.creator.userId == user.account.id).toList();
_collectPlayList =
_allPlayList.where((p) => p.creator.userId != user.account.id).toList();
複製代碼
ok,數據有了,畫頁面就簡單多了,從圖上咱們也能夠看得出來,是能夠展開和收回的。
這個功能首先我想到的是 ExpansionPanelList
,可是他和咱們的需求不太搭,包括樣式和邏輯。
那咱們就自定義一個,怎麼來作到展開和收回?其實就是控制歌單列表的顯示和不顯示,因此咱們應該能想到一個組件:Offstage
。
並且在展開/收回的時候箭頭要來回的變化,我在前面也寫過一篇文章:Flutter | 求求大家了,切換 Widget 的時候加上動畫吧,這個時候就派上用場了。
頭部組件大體代碼以下:
Widget build(BuildContext context) {
return Container(
height: ScreenUtil().setWidth(80),
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
setState(() {
if (arrow == arrows[0])
arrow = arrows[1];
else
arrow = arrows[0];
widget.onSwitchTap();
});
},
child: Row(
children: <Widget>[
AnimatedSwitcher(
transitionBuilder: (child, anim) {
return ScaleTransition(child: child, scale: anim);
},
duration: Duration(milliseconds: 300),
child: Image.asset(
arrow,
key: ValueKey(arrow),
width: ScreenUtil().setWidth(30),
),
),
],
),
),
);
}
複製代碼
給整行套上 GestureDetector
,點擊的時候切換箭頭,而且調用 widget.onSwitchTap()
方法來觸發回調。
整個歌單的代碼大體以下:
Widget _realBuildPlayList() {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
PlaylistTitle("建立的歌單", _playListModel.selfCreatePlayList.length, () {
setState(() {
selfPlayListOffstage = !selfPlayListOffstage;
});
}, () {},xxx,
Offstage(
offstage: selfPlayListOffstage,
child: _buildPlayListItem(_playListModel.selfCreatePlayList),
),
PlaylistTitle(
"收藏的歌單",
_playListModel.collectPlayList.length,
() {
setState(() {
collectPlayListOffstage = !collectPlayListOffstage;
});
},
() {},
),
Offstage(
offstage: collectPlayListOffstage,
child: _buildPlayListItem(_playListModel.collectPlayList),
),
],
);
}
複製代碼
在每個頭部下面都是一個 Offstage
組件,來控制歌單列表的顯示與否,而且經過點擊回調來觸發 setState
。
還有一點是:「建立的歌單」中是能夠新建歌單的,因此要多處理一下,控制「+」的顯示與否。
這樣就完成了整個歌單列表的分拆與顯示。
新建歌單相對來講就簡單不少了。
就是一個彈出框,來看一下是怎麼寫的:
Widget build(BuildContext context) {
return AlertDialog(
title: Text(
'新建歌單',
style: bold16TextStyle,
),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(ScreenUtil().setWidth(20)))),
content: Theme(
data: ThemeData(primaryColor: Colors.red),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
xxx,
],
),
),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('取消'),
textColor: Colors.red,
),
FlatButton(
onPressed: submitCallback == null
? null
: () {
submitCallback(_editingController.text, isPrivatePlayList);
},
child: Text('提交'),
textColor: Colors.red,
),
],
);
}
複製代碼
直接調用 showDialog()
方法,返回一個 AlertDialog
,
AlertDialog
自己就有一個 shape
字段,能夠用來控制外觀,這裏咱們加上圓角就能夠了。
剩下的還有一點就是「提交」按鈕的顏色問題,當咱們沒有寫歌單標題的時候,「提交」按鈕要置灰,
這裏有一個小竅門就是 若是 FlatButton
的 onPressed
爲 null,那麼這個按鈕的顏色就是灰色的。
因此咱們使用 TextEditingController
來判斷就行了:
_editingController.addListener(() {
if (_editingController.text.isEmpty) {
setState(() {
submitCallback = null;
});
} else {
setState(() {
if (submitCallback == null) {
submitCallback = widget.submitCallback;
}
});
}
});
複製代碼
最後在調用接口成功以後,給歌單列表中插入一條數據就好了,可是這裏返回的時候是沒有 Creator
信息的,咱們本身添加上就ok了:
NetUtils.createPlaylist(context,
params: {'name': name, 'privacy': isPrivate ? '10' : null})
.catchError((e) {
Utils.showToast('建立失敗');
}).then((result) {
Utils.showToast('建立成功');
Navigator.of(context).pop();
_playListModel.addPlayList(result.playlist..creator = _playListModel.selfCreatePlayList[0].creator);
});
複製代碼
對於歌單的操做,如圖所示:
這裏也有區分,若是是「建立的歌單」,那麼會有「編輯歌單信息」這一欄,若是是收藏的話,則沒有。
這裏也是簡單的使用了 showModalBottomSheet
來顯示。
在點擊更改歌單信息的時候彈出:
這裏其實和上面新建歌單是同樣的,只不過就是改了一點樣式。
在點刪除的時候,調用 PlayListModel
裏的刪除方法而且通知刷新就行了。
這樣整個「個人」頁面大體就完成了。
其實這一篇沒什麼好總結的,把前面寫好的東西拿來用就行了,很是簡單。
畢竟知識就是一個積累的過程,慢慢學就完了。
該項目是我本人本身在工做之餘寫的,因此進度不會很快,可是會一直寫下去。
你們若是有好的建議的話,歡迎提 issue,我會在第一時間回覆。
該系列文章代碼已傳至 GitHub:github.com/wanglu1209/…
另我我的建立了一個「Flutter 交流羣」,能夠添加我我的微信 「17610912320」來入羣。