Drawer?Builder組件實(shí)現(xiàn)flutter側(cè)邊抽屜效果示例分析
前言
平時(shí)開發(fā)中難免會(huì)碰到抽屜效果,如果自己寫肯定要費(fèi)一番工夫,用別人的也要付出代碼量,Scaffold實(shí)際上已經(jīng)默認(rèn)提供了 Drawer 抽屜效果供我們使用,下面我們就看看怎么使用的吧
先上一張效果圖

Drawer 與 UserAccountsDrawerHeader
Drawer就是我們的抽屜效果,而 UserAccountsDrawerHeader就是我們側(cè)邊欄上面的那片用戶信息頁面,可有可無,為了方便可以使用,當(dāng)然也可以自己定制
下面直接上一個(gè)屬性表格,方便理解, UserAccountsDrawerHeader從屬性就可以看到功能比較固定,可以看情況使用
| Drawer屬性 | 說明 |
|---|---|
| elevation | 背景高度 |
| child | 子組件 |
| semanticLabel | 標(biāo)簽 |
| width | 側(cè)邊欄寬度 |
| UserAccountsDrawerHeader屬性 | 說明 |
|---|---|
| decoration | 頭部裝飾 |
| margin | 外邊距 默認(rèn)8.0 |
| currentAccountPicture | 主圖像 |
| otherAccountsPictures | 副圖像 |
| accountName | 標(biāo)題 |
| accountEmail | 副標(biāo)題 |
| onDetailsPressed | 點(diǎn)擊監(jiān)聽 |
話不多說,直接上代碼
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("首頁"),
),
body: const Center(
child: Text("我是首頁內(nèi)容"),
),
//endDrawer: Container(), //是右邊側(cè)邊欄不多說了
//我們就在這里面直接寫了,使用默認(rèn)的 Drawer 就是抽屜效果了
drawer: Drawer(
child: ListView(
padding: const EdgeInsets.all(0),
children: const <Widget>[
//側(cè)邊欄頂部效果,可以根據(jù)情況使用,可有可無
UserAccountsDrawerHeader(
accountName: Text("標(biāo)題"),
accountEmail: Text("副標(biāo)題"),
//頭像
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
),
//背景
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(title: Text("item0..."),),
ListTile(title: Text("item1..."),),
ListTile(title: Text("item2..."),),
],
),
),
);
}
側(cè)邊欄這樣就介紹完畢了。
讀者:這就完了?根本不夠用,感覺側(cè)邊欄按鈕跟自己的不太一樣,想換一個(gè)首頁喚出側(cè)邊欄的按鈕?
嘗試案例后,就會(huì)知道,其實(shí)上面的案例圖就是換過的側(cè)邊欄按鈕,變粗了一點(diǎn),沒錯(cuò),這也和我們后面介紹的 Builder 關(guān)聯(lián)上了
定制喚出按鈕并引出 Builder 組件
實(shí)際上我們定制側(cè)邊欄的時(shí)候,只需要更換 AppBar 的 leading 即可,Scaffold 默認(rèn)提供了 openDrawer 方法打開或者關(guān)閉側(cè)邊欄,下面就距離打開側(cè)邊欄
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("首頁"),
// leading: const Leading(),//直接寫成小組件可以解決從context查找父類引起的bug
leading: IconButton(
onPressed: () {
Scaffold.of(context).openDrawer();
//Scaffold.of(context).closeDrawer(); //關(guān)閉側(cè)邊欄
// Scaffold.of(context).openEndDrawer();//打開右側(cè)側(cè)邊欄
},
icon: const Icon(Icons.table_rows_rounded),
iconSize: 20,
);
),
),
body: const Center(
child: Text("我是首頁內(nèi)容"),
),
//我們就在這里面直接寫了
drawer: Drawer(
...
),
);
}
問題
看了上面的說法和案例,那么可能會(huì)碰到一個(gè) Bug,就是找不到 Scaffold,或者無法開關(guān) Drawer,問題在于 Scaffold.of
Scaffold.of(context)
其會(huì)像向父類查找該組件,此時(shí)我們傳遞的,context,從哪里來的,看上面的代碼就知道,是從當(dāng)前Build中傳遞過來的 context,其祖先是誰,是我們的 MaterialApp,因此會(huì)出現(xiàn)找不到 Scaffold 或者無法打開側(cè)邊欄的問題
//根據(jù)context到 父類祖先中查找狀態(tài)
final ScaffoldState? result = context.findAncestorStateOfType<ScaffoldState>();
if (result != null) {
return result;
}
解決方案
外面嵌套一個(gè) Builder即可, Builder實(shí)際上是一個(gè) StatelessWidget小組件,其就是參數(shù) builder就是利用回調(diào)帶回了自己的 context從而解決的 context 父類查找問題
因此,我們將 Leading 的按鈕換成一個(gè) StatelessWidget,也可以作為其中一個(gè)解決方案,不過,我相信很多人更愿意選擇 Builder + IconButton,畢竟其就只有一個(gè)按鈕,這也是一些系統(tǒng)或者三方組件經(jīng)常使用 Builder的原因了吧
Builder(
builder: (context) {
return IconButton(
onPressed: () {
//會(huì)從context的父類開始找組件context.findAncestorStateOfType
//當(dāng)前組件的context父組件是 MyApp 是沒有 Scaffold,且沒有drawer,因此無法打開
//Builder是一個(gè)StatelessWidget基礎(chǔ)組件,只不過返回了自己的context,因此沒問題
Scaffold.of(context).openDrawer();
//Scaffold.of(context).closeDrawer(); //關(guān)閉側(cè)邊欄
// Scaffold.of(context).openEndDrawer();//打開右側(cè)側(cè)邊欄
},
icon: const Icon(Icons.table_rows_rounded),
iconSize: 20,
);
},
),
整體代碼
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
//小組件
class Leading extends StatelessWidget {
const Leading({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
Scaffold.of(context).openDrawer();
},
icon: const Icon(Icons.table_rows_rounded),
iconSize: 20,
);
}
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("首頁"),
// leading: const Leading(),//直接寫成小組件可以解決從context查找父類引起的bug
leading: Builder(
builder: (context) {
return IconButton(
onPressed: () {
//會(huì)從context的父類開始找組件context.findAncestorStateOfType
//當(dāng)前組件的context父組件是 MyApp 是沒有 Scaffold,且沒有drawer,因此無法打開
//Builder是一個(gè)StatelessWidget基礎(chǔ)組件,只不過返回了自己的context,因此沒問題
Scaffold.of(context).openDrawer();
//Scaffold.of(context).closeDrawer(); //關(guān)閉側(cè)邊欄
// Scaffold.of(context).openEndDrawer();//打開右側(cè)側(cè)邊欄
},
icon: const Icon(Icons.table_rows_rounded),
iconSize: 20,
);
},
),
),
body: const Center(
child: Text("我是首頁內(nèi)容"),
),
//endDrawer: Container(), //是右邊側(cè)邊欄不多說了
//我們就在這里面直接寫了
drawer: Drawer(
child: ListView(
padding: const EdgeInsets.all(0),
children: const <Widget>[
UserAccountsDrawerHeader(
accountEmail: Text("副標(biāo)題"),
accountName: Text("標(biāo)題"),
//頭像
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
),
//背景
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(title: Text("item0..."),),
ListTile(title: Text("item1..."),),
ListTile(title: Text("item2..."),),
],
),
),
);
}
}
最后
快來嘗試一下吧,相信,馬上就能用個(gè)明明白白,我也是在使用其的過程中,發(fā)現(xiàn)了 Scaffold.of查找的邏輯問題,進(jìn)而進(jìn)出 Builder來解決問題,相信里面還有不少用到 Builder的組件有類似的情況,那時(shí)候就不一定是 scaffold.of 了??
以上就是Drawer Builder組件實(shí)現(xiàn)flutter側(cè)邊抽屜效果示例分析的詳細(xì)內(nèi)容,更多關(guān)于Drawer Builder flutter側(cè)邊抽屜的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
iOS統(tǒng)計(jì)項(xiàng)目的代碼總行數(shù)
最近一個(gè)項(xiàng)目有段時(shí)間了,不知道怎樣可以統(tǒng)計(jì)出寫了多少行代碼,如何處理這個(gè)問題呢,下面我們來探討下。2015-06-06
iOS9 系統(tǒng)分享調(diào)用之UIActivityViewController
UIActivityViewController類是一個(gè)標(biāo)準(zhǔn)的view controller,通個(gè)使用這個(gè)controller,你的應(yīng)用程序就可以提供各種服務(wù)。本文給大家介紹iOS9 系統(tǒng)分享調(diào)用之UIActivityViewController,感興趣的朋友一起學(xué)習(xí)吧2015-11-11
iOS 二維碼掃描相關(guān)功能實(shí)現(xiàn)
這篇文章主要介紹了iOS 二維碼掃描相關(guān)功能實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09
Objective-C實(shí)現(xiàn)無限循環(huán)輪播器
這篇文章主要介紹了Objective-C實(shí)現(xiàn)無限循環(huán)輪播器的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05

