Drawer Builder组件实现flutter侧边抽屉效果示例分析
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>前言</li><li>Drawer 与 UserAccountsDrawerHeader</li><li>定制唤出按钮并引出 Builder 组件</li><li>整体代码</li><li>最后</li></ul></div><p class="maodian"></p><h2>前言</h2><p>平时开发中难免会碰到抽屉效果,如果自己写肯定要费一番工夫,用别人的也要付出代码量,<code>Scaffold</code>实际上已经默认提供了 <code>Drawer</code> 抽屉效果供我们使用,下面我们就看看怎么使用的吧</p>
<p>先上一张效果图</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202210/20221020085252014.png" /></p>
<p>demo案例</p>
<p class="maodian"></p><h2>Drawer 与 UserAccountsDrawerHeader</h2>
<p><code>Drawer</code>就是我们的抽屉效果,而 <code>UserAccountsDrawerHeader</code>就是我们侧边栏上面的那片用户信息页面,可有可无,为了方便可以使用,当然也可以自己定制</p>
<p>下面直接上一个属性表格,方便理解, <code>UserAccountsDrawerHeader</code>从属性就可以看到功能比较固定,可以看情况使用</p>
<table><tbody><tr><th>Drawer属性</th><th>说明</th></tr><tr><td>elevation</td><td>背景高度</td></tr><tr><td>child</td><td>子组件</td></tr><tr><td>semanticLabel</td><td>标签</td></tr><tr><td>width</td><td>侧边栏宽度</td></tr></tbody></table>
<table><tbody><tr><th>UserAccountsDrawerHeader属性</th><th>说明</th></tr><tr><td>decoration</td><td>头部装饰</td></tr><tr><td>margin</td><td>外边距 默认8.0</td></tr><tr><td>currentAccountPicture</td><td>主图像</td></tr><tr><td>otherAccountsPictures</td><td>副图像</td></tr><tr><td>accountName</td><td>标题</td></tr><tr><td>accountEmail</td><td>副标题</td></tr><tr><td>onDetailsPressed</td><td>点击监听</td></tr></tbody></table>
<p>话不多说,直接上代码</p>
<div class="jb51code"><pre class="brush:js;">Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("首页"),
),
body: const Center(
child: Text("我是首页内容"),
),
//endDrawer: Container(), //是右边侧边栏不多说了
//我们就在这里面直接写了,使用默认的 Drawer 就是抽屉效果了
drawer: Drawer(
child: ListView(
padding: const EdgeInsets.all(0),
children: const <Widget>[
//侧边栏顶部效果,可以根据情况使用,可有可无
UserAccountsDrawerHeader(
accountName: Text("标题"),
accountEmail: Text("副标题"),
//头像
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
),
//背景
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(title: Text("item0..."),),
ListTile(title: Text("item1..."),),
ListTile(title: Text("item2..."),),
],
),
),
);
}
</pre></div>
<p>侧边栏这样就介绍完毕了。</p>
<p><strong>读者</strong>:这就完了?根本不够用,感觉侧边栏按钮跟自己的不太一样,想换一个首页唤出侧边栏的按钮?</p>
<p>尝试案例后,就会知道,其实上面的案例图就是换过的侧边栏按钮,变粗了一点,没错,这也和我们后面介绍的 <code>Builder</code> 关联上了</p>
<p class="maodian"></p><h2>定制唤出按钮并引出 Builder 组件</h2>
<p>实际上我们定制侧边栏的时候,只需要更换 <code>AppBar</code> 的 <code>leading</code> 即可,<code>Scaffold</code> 默认提供了 <code>openDrawer</code> 方法<code>打开或者关闭</code>侧边栏,下面就距离打开侧边栏</p>
<div class="jb51code"><pre class="brush:js;">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(); //关闭侧边栏
// Scaffold.of(context).openEndDrawer();//打开右侧侧边栏
},
icon: const Icon(Icons.table_rows_rounded),
iconSize: 20,
);
),
),
body: const Center(
child: Text("我是首页内容"),
),
//我们就在这里面直接写了
drawer: Drawer(
...
),
);
}
</pre></div>
<p><code>问题</code></p>
<p>看了上面的说法和案例,那么可能会碰到一个 <code>Bug</code>,就是找不到 <code>Scaffold</code>,或者无法开关 <code>Drawer</code>,问题在于 <code>Scaffold.of</code></p>
<div class="jb51code"><pre class="brush:js;">Scaffold.of(context)
</pre></div>
<p>其会像向父类查找该组件,此时我们传递的,<code>context</code>,从哪里来的,看上面的代码就知道,是从当前<code>Build</code>中传递过来的 context,其祖先是谁,是我们的 <code>MaterialApp</code>,因此会出现找不到 <code>Scaffold</code> 或者无法打开侧边栏的问题</p>
<div class="jb51code"><pre class="brush:js;">//根据context到 父类祖先中查找状态
final ScaffoldState? result = context.findAncestorStateOfType&lt;ScaffoldState&gt;();
if (result != null) {
return result;
}
</pre></div>
<p><code>解决方案</code></p>
<p>外面嵌套一个 <code>Builder</code>即可, <code>Builder</code>实际上是一个 <code>StatelessWidget</code>小组件,其就是参数 <code>builder</code>就是利用回调<code>带回了自己的 context</code>从而解决的 <code>context</code> 父类查找问题</p>
<p>因此,我们将 <code>Leading</code> 的按钮换成一个 <code>StatelessWidget</code>,也可以作为其中一个解决方案,不过,我相信很多人更愿意选择 <code>Builder + IconButton</code>,毕竟其就只有一个按钮,这也是一些系统或者三方组件经常使用 <code>Builder</code>的原因了吧</p>
<div class="jb51code"><pre class="brush:js;">Builder(
builder: (context) {
return IconButton(
onPressed: () {
//会从context的父类开始找组件context.findAncestorStateOfType
//当前组件的context父组件是 MyApp 是没有 Scaffold,且没有drawer,因此无法打开
//Builder是一个StatelessWidget基础组件,只不过返回了自己的context,因此没问题
Scaffold.of(context).openDrawer();
//Scaffold.of(context).closeDrawer(); //关闭侧边栏
// Scaffold.of(context).openEndDrawer();//打开右侧侧边栏
},
icon: const Icon(Icons.table_rows_rounded),
iconSize: 20,
);
},
),
</pre></div>
<p class="maodian"></p><h2>整体代码</h2>
<div class="jb51code"><pre class="brush:js;">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: () {
//会从context的父类开始找组件context.findAncestorStateOfType
//当前组件的context父组件是 MyApp 是没有 Scaffold,且没有drawer,因此无法打开
//Builder是一个StatelessWidget基础组件,只不过返回了自己的context,因此没问题
Scaffold.of(context).openDrawer();
//Scaffold.of(context).closeDrawer(); //关闭侧边栏
// Scaffold.of(context).openEndDrawer();//打开右侧侧边栏
},
icon: const Icon(Icons.table_rows_rounded),
iconSize: 20,
);
},
),
),
body: const Center(
child: Text("我是首页内容"),
),
//endDrawer: Container(), //是右边侧边栏不多说了
//我们就在这里面直接写了
drawer: Drawer(
child: ListView(
padding: const EdgeInsets.all(0),
children: const <Widget>[
UserAccountsDrawerHeader(
accountEmail: Text("副标题"),
accountName: Text("标题"),
//头像
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
),
//背景
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(title: Text("item0..."),),
ListTile(title: Text("item1..."),),
ListTile(title: Text("item2..."),),
],
),
),
);
}
}
</pre></div>
<p class="maodian"></p><h2>最后</h2>
<p>快来尝试一下吧,相信,马上就能用个明明白白,我也是在使用其的过程中,发现了 <code>Scaffold.of</code>查找的逻辑问题,进而进出 <code>Builder</code>来解决问题,相信里面还有不少用到 <code>Builder</code>的组件有类似的情况,那时候就不一定是 <code>scaffold.of</code> 了😂</p>
<p>以上就是Drawer Builder组件实现flutter侧边抽屉效果示例分析的详细内容,更多关于Drawer Builder flutter侧边抽屉的资料请关注琼殿技术社区其它相关文章!</p>
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li>Flutter Widget移动UI框架使用Material和密匙Key实战</li><li>Flutter最小刷新范围探索ValueListenableBuilder使用详解</li><li>Flutter Widget之FutureBuilder使用示例详解</li><li>Flutter Widget 之StatefulBuilder构建方法详解</li><li>详解Flutter如何用思源宋体炫出你的UI</li></ul>
</div>
</div>
<!--endmain-->
頁:
[1]