Flutter底部弹出菜单插件bottom_sheet_scaffold的使用

发布于 1周前 作者 vueper 来自 Flutter

Flutter底部弹出菜单插件 bottom_sheet_scaffold 的使用

bottom_sheet_scaffold 是一个非常简单且可高度定制的底部弹出菜单插件。它允许通过滑动 Scaffold 的主体来控制底部弹出菜单的高度,并提供了丰富的功能,如动画透明度、拖动手势等。

特性

  • 简单易用
  • 通过滑动 Scaffold 主体来确定底部弹出菜单的高度
  • 可拖动的底部弹出菜单主体
  • 动画透明度
  • 完全可定制
  • 使用 BottomSheetBuilder 监听底部弹出菜单的状态
  • 不需要设置任何头部即可滑动底部弹出菜单

示例效果

Scaffold Swipping Header Swipping Gradient Opacity Fixed height Custom

使用方法

将你的 Scaffold 替换为 BottomSheetScaffold

import 'package:bottom_sheet_scaffold/bottom_sheet_scaffold.dart';
import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return BottomSheetScaffold(
      draggableBody: true,
      dismissOnClick: true,
      barrierColor: Colors.black54,
      bottomSheet: DraggableBottomSheet(
        animationDuration: const Duration(milliseconds: 200),
        body: Container(
          width: double.infinity,
          height: 500,
          alignment: Alignment.center,
          child: const Text(
            "Bottom Sheet",
            style: TextStyle(fontSize: 36, color: Colors.black),
          ),
        ),
        header: Container(
          height: 60,
          color: Colors.blue,
          child: const Center(
            child: Text(
              "Drag me",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
      ),
      appBar: AppBar(
        title: const Text("My AppBar"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            const SizedBox(height: 100),
            BottomSheetBuilder(
              builder: (status, context) {
                return MaterialButton(
                  color: Colors.blue,
                  onPressed: () {
                    if (BottomSheetPanel.isExpanded) {
                      BottomSheetPanel.close();
                    } else {
                      BottomSheetPanel.open();
                    }
                  },
                  child: Icon(!status.isExpanded
                      ? Icons.open_in_browser
                      : Icons.close_fullscreen),
                );
              },
            ),
            const Text('Body of scaffold'),
          ],
        ),
      ),
    );
  }
}

自定义 onWillPop

你可以自定义 onWillPop 来处理返回按钮的行为:

BottomSheetScaffold(
  draggableBody: true,
  dismissOnClick: true,
  onWillPop: (() async {
    if (BottomSheetPanel.isOpen) {
      BottomSheetPanel.close();
      return false;
    } else {
      return true;
    }
  }),
  barrierColor: Colors.black54,
  bottomSheet: DraggableBottomSheet(
    animationDuration: const Duration(milliseconds: 200),
    body: Container(
      width: double.infinity,
      height: 500,
      alignment: Alignment.center,
      child: const Text(
        "Bottom Sheet",
        style: TextStyle(fontSize: 36, color: Colors.black),
      ),
    ),
    header: Container(
      height: 60,
      color: Colors.blue,
      child: const Center(
        child: Text(
          "Drag me",
          style: TextStyle(color: Colors.white),
        ),
      ),
    ),
  ),
  appBar: AppBar(
    title: const Text("My AppBar"),
  ),
  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.start,
      children: <Widget>[
        const SizedBox(height: 100),
        BottomSheetBuilder(
          builder: (status, context) {
            return MaterialButton(
              color: Colors.blue,
              onPressed: () {
                if (BottomSheetPanel.isExpanded) {
                  BottomSheetPanel.close();
                } else {
                  BottomSheetPanel.open();
                }
              },
              child: Icon(!status.isExpanded
                  ? Icons.open_in_browser
                  : Icons.close_fullscreen),
            );
          },
        ),
        const Text('Body of scaffold'),
      ],
    ),
  ),
);

处理 Scaffold 内部的屏障显示

如果你在 BottomSheetScaffold 内部使用 Scaffold,你应该将 Scaffold 的主体包裹在 BarrierViewer 中,以便在打开底部弹出菜单时显示你定义的屏障颜色:

return BottomSheetScaffold(
  bottomSheet: DraggableBottomSheet(
    animationDuration: const Duration(milliseconds: 200),
    body: Container(
      width: double.infinity,
      height: 500,
      alignment: Alignment.center,
      child: const Text(
        "Bottom Sheet",
        style: TextStyle(fontSize: 36, color: Colors.black),
      ),
    ),
    header: Container(
      height: 60,
      color: Colors.blue,
      child: const Center(
        child: Text(
          "Drag me",
          style: TextStyle(color: Colors.white),
        ),
      ),
    ),
  ),
  appBar: AppBar(
    title: const Text("My AppBar"),
  ),
  body: Scaffold(
    body: BarrierViewer(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            const SizedBox(height: 100),
            BottomSheetBuilder(
              builder: (status, context) {
                return MaterialButton(
                  color: Colors.blue,
                  onPressed: () {
                    if (BottomSheetPanel.isExpanded) {
                      BottomSheetPanel.close();
                    } else {
                      BottomSheetPanel.open();
                    }
                  },
                  child: Icon(!status.isExpanded
                      ? Icons.open_in_browser
                      : Icons.close_fullscreen),
                );
              },
            ),
            const Text('Body of scaffold'),
          ],
        ),
      ),
    ),
  ),
);

DraggableBottomSheet 参数

DraggableBottomSheet({
  super.key,
  this.maxHeight = 500,
  this.minHeight = 0,
  this.header,
  this.animationDuration = const Duration(milliseconds: 200),
  this.autoSwipped = true,
  this.draggableBody = true,
  this.gradientOpacity = true,
  this.headerVisibilityOnTap = true,
  this.backgroundColor = Colors.white60,
  this.onHide,
  this.radius = 30,
  this.onShow,
  required this.body,
})

BottomSheetPanel 方法和属性

  • 打开底部弹出菜单:
    BottomSheetPanel.open();
    
  • 关闭底部弹出菜单:
    BottomSheetPanel.close();
    
  • 更新底部弹出菜单的高度:
    BottomSheetPanel.updateHeight(double height);
    
  • 检查底部弹出菜单是否打开:
    BottomSheetPanel.isOpen;
    
  • 检查底部弹出菜单是否展开:
    BottomSheetPanel.isExpanded;
    
  • 检查底部弹出菜单是否折叠:
    BottomSheetPanel.isCollapsed;
    

DraggableArea 使用

如果在 DraggableBottomSheet 中将 draggableBody 设置为 false,你需要使用 DraggableArea 小部件来滚动底部弹出菜单:

DraggableBottomSheet(
  draggableBody: false,
  body: Column(
    children: [
      DraggableArea(
        child: Container(
          height: 80,
          width: double.infinity,
          color: Colors.blue,
          alignment: Alignment.center,
          child: const Text(
            "Drag Me",
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
      Container(
        height: 500,
        color: Colors.red,
        child: const Center(
          child: Text(
            "Bottom Sheet",
            style: TextStyle(fontSize: 36, color: Colors.white),
          ),
        ),
      )
    ],
  ),
)

BottomSheetBuilder 使用

如果你想监听底部弹出菜单的状态并根据状态更改页面上的某些内容,可以使用 BottomSheetBuilder

BottomSheetBuilder(
  builder: (status, context) {
    return FloatingActionButton(
      onPressed: () {
        if (BottomSheetPanel.isExpanded) {
          BottomSheetPanel.close();
        } else {
          BottomSheetPanel.open();
        }
      },
      child: Icon(!status.isExpanded
          ? Icons.open_in_browser
          : Icons.close_fullscreen),
    );
  },
)

完整示例代码

import 'package:bottom_sheet_scaffold/bottom_sheet_scaffold.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return BottomSheetScaffold(
      bottomSheet: DraggableBottomSheet(
        animationDuration: const Duration(milliseconds: 200),
        body: Container(
          width: double.infinity,
          height: 500,
          alignment: Alignment.center,
          child: const Text(
            "Bottom Sheet",
            style: TextStyle(fontSize: 36, color: Colors.black),
          ),
        ),
        header: Container(
          height: 60,
          color: Colors.blue,
          child: const Center(
            child: Text(
              "Drag me",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
      ),
      appBar: AppBar(
        title: const Text("My AppBar"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            const SizedBox(height: 100),
            BottomSheetBuilder(
              builder: (status, context) {
                return MaterialButton(
                  color: Colors.blue,
                  onPressed: () {
                    if (BottomSheetPanel.isExpanded) {
                      BottomSheetPanel.close();
                    } else {
                      BottomSheetPanel.open();
                    }
                  },
                  child: Icon(!status.isExpanded
                      ? Icons.open_in_browser
                      : Icons.close_fullscreen),
                );
              },
            ),
            const Text('Body of scaffold'),
          ],
        ),
      ),
    );
  }
}

希望这个详细的指南能帮助你更好地理解和使用 bottom_sheet_scaffold 插件!


更多关于Flutter底部弹出菜单插件bottom_sheet_scaffold的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter底部弹出菜单插件bottom_sheet_scaffold的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用bottom_sheet_scaffold插件来创建底部弹出菜单的示例代码。bottom_sheet_scaffold是一个非官方的Flutter插件,它提供了一个方便的方式来创建带有可滑动底部面板的页面结构。

首先,确保你已经在pubspec.yaml文件中添加了bottom_sheet_scaffold依赖:

dependencies:
  flutter:
    sdk: flutter
  bottom_sheet_scaffold: ^1.0.0  # 请检查最新版本号

然后,运行flutter pub get来安装依赖。

接下来是一个完整的示例代码,展示了如何使用BottomSheetScaffold来创建一个带有底部弹出菜单的页面:

import 'package:flutter/material.dart';
import 'package:bottom_sheet_scaffold/bottom_sheet_scaffold.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BottomSheetScaffold Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> menuItems = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];

  @override
  Widget build(BuildContext context) {
    return BottomSheetScaffold(
      sheet: Container(
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(16),
            topRight: Radius.circular(16),
          ),
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            ListView.builder(
              shrinkWrap: true,
              itemCount: menuItems.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(menuItems[index]),
                  onTap: () {
                    Navigator.of(context).pop(); // 关闭底部菜单
                    // 可以在这里添加点击菜单项后的处理逻辑
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Selected: ${menuItems[index]}')),
                    );
                  },
                );
              },
            ),
          ],
        ),
      ),
      appBar: AppBar(
        title: Text('BottomSheetScaffold Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // 打开底部菜单
            BottomSheetScaffold.of(context).showSheet();
          },
          child: Text('Show Bottom Sheet'),
        ),
      ),
    );
  }
}

在这个示例中:

  1. BottomSheetScaffold被用作根小部件,它提供了一个带有可滑动底部面板的页面结构。
  2. sheet属性定义了底部菜单的内容。这里我们用一个Container包裹了一个Column,其中包含了一个ListView.builder来动态生成菜单项。
  3. 每个菜单项是一个ListTile,点击时会关闭底部菜单并显示一个SnackBar。
  4. body中,我们放置了一个ElevatedButton,点击它会调用BottomSheetScaffold.of(context).showSheet()方法来显示底部菜单。

请注意,由于bottom_sheet_scaffold是一个第三方插件,其API可能会随着版本的更新而变化。因此,建议查看最新的官方文档和示例代码以确保兼容性。

回到顶部