Drawer Builder组件实现flutter侧边抽屉效果示例分析

前言

平时开发中难免会碰到抽屉效果,如果自己写肯定要费一番工夫,用别人的也要付出代码量,Scaffold实际上已经默认提供了 Drawer 抽屉效果供我们使用,下面我们就看看怎么使用的吧

先上一张效果图

Drawer Builder组件实现flutter侧边抽屉效果示例分析_第1张图片

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 [
          //侧边栏顶部效果,可以根据情况使用,可有可无
          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 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 {
  @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 [
            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

以上就是Drawer Builder组件实现flutter侧边抽屉效果示例分析的详细内容,更多关于Drawer Builder flutter侧边抽屉的资料请关注脚本之家其它相关文章!

你可能感兴趣的:(Drawer Builder组件实现flutter侧边抽屉效果示例分析)