前言

平常开发中难免会碰到抽屉作用,如果自己写肯定要费一番时间,用他人的也要付出代码量,Scaffold实际上已经默许供给了 Drawer 抽屉作用供咱们运用,下面咱们就看看怎么运用的吧

先上一张作用图

flutter-侧边抽屉效果Drawer与Builder组件的思考

demo事例

Drawer 与 UserAccountsDrawerHeader

Drawer便是咱们的抽屉作用,而 UserAccountsDrawerHeader便是咱们侧边栏上面的那片用户信息页面,可有可无,为了便利能够运用,当然也能够自己定制

下面直接上一个特点表格,便利了解, UserAccountsDrawerHeader从特点就能够看到功用比较固定,能够看情况运用

Drawer特点 说明
elevation 布景高度
child 子组件
semanticLabel 标签
width 侧边栏宽度
UserAccountsDrawerHeader特点 说明
decoration 头部装饰
margin 外边距 默许8.0
currentAccountPicture 主图像
otherAccountsPictures 副图像
accountName 标题
accountEmail 副标题
onDetailsPressed 点击监听

话不多说,直接上代码

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..."),),
        ],
      ),
    ),
  );
}

侧边栏这样就介绍结束了。

读者:这就完了?底子不够用,感觉侧边栏按钮跟自己的不太相同,想换一个主页唤出侧边栏的按钮?

测验事例后,就会知道,其实上面的事例图便是换过的侧边栏按钮,变粗了一点,没错,这也和咱们后面介绍的 Builder 关联上了

定制唤出按钮并引出 Builder 组件

实际上咱们定制侧边栏的时候,只需要替换 AppBarleading 即可,Scaffold 默许供给了 openDrawer 办法翻开或许封闭侧边栏,下面就间隔翻开侧边栏

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(
       ...
    ),
  );
}

问题

看了上面的说法和事例,那么可能会碰到一个 Bug,便是找不到 Scaffold,或许无法开关 Drawer,问题在于 Scaffold.of

Scaffold.of(context)

其会像向父类查找该组件,此时咱们传递的,context,从哪里来的,看上面的代码就知道,是从当时Build中传递过来的 context,其祖先是谁,是咱们的 MaterialApp,因而会呈现找不到 Scaffold 或许无法翻开侧边栏的问题

//根据context到 父类祖先中查找状态
final ScaffoldState? result = context.findAncestorStateOfType<ScaffoldState>();
if (result != null) {
  return result;
}

处理方案

外面嵌套一个 Builder即可, Builder实际上是一个 StatelessWidget小组件,其便是参数 builder便是利用回调带回了自己的 context从而处理的 context 父类查找问题

因而,咱们将 Leading 的按钮换成一个 StatelessWidget,也能够作为其间一个处理方案,不过,我信任很多人更愿意挑选 Builder + IconButton,毕竟其就只有一个按钮,这也是一些系统或许三方组件经常运用 Builder的原因了吧

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,
    );
  },
),

全体代码

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..."),),
          ],
        ),
      ),
    );
  }
}

最终

快来测验一下吧,信任,立刻就能用个明明白白,我也是在运用其的过程中,发现了 Scaffold.of查找的逻辑问题,从而进出 Builder来处理问题,信任里边还有不少用到 Builder的组件有类似的情况,那时候就不一定是 scaffold.of