滑动表格

一个可以通过单个手势进行拖动和滚动并吸附到一系列范围的窗口小部件。

Sliding-Sheet

点击此处查看完整示例。

安装

将其添加到您的pubspec.yaml文件中

dependencies:
  sliding_sheet: ^0.3.7

从命令行安装软件包

flutter packages get

如果您喜欢此软件包,请考虑在GitHub上为其点赞,并在pub.dev上为其点赞 :heart

用法

您可以通过两种方式使用 SlidingSheet:将其作为永久(或持久)Widget 放置在您的
小部件树中,或作为 BottomSheetDialog 使用。

作为小部件

此方法可用于将 SlidingSheet 永久显示(通常在您的其他小部件之上),如示例所示。

@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.grey.shade200,
    appBar: AppBar(
      title: Text('Simple Example'),
    ),
    body: SlidingSheet(
      elevation: 8,
      cornerRadius: 16,
      snapSpec: const SnapSpec(
        // Enable snapping. This is true by default.
        snap: true,
        // Set custom snapping points.
        snappings: [0.4, 0.7, 1.0],
        // Define to what the snappings relate to. In this case, 
        // the total available space that the sheet can expand to.
        positioning: SnapPositioning.relativeToAvailableSpace,
      ),
      // The body widget will be displayed under the SlidingSheet
      // and a parallax effect can be applied to it.
      body: Center(
        child: Text('This widget is below the SlidingSheet'),
      ),
      builder: (context, state) {
        // This is the content of the sheet that will get
        // scrolled, if the content is bigger than the available
        // height of the sheet.
        return Container(
          height: 500,
          child: Center(
            child: Text('This is the content of the sheet'),
          ),
        );
      },
    ),
  );
}

结果

Example

作为BottomSheetDialog

此方法可通过调用 showSlidingBottomSheet 函数并返回 SlidingSheetDialog 的实例来将 SlidingSheet 显示为 BottomSheetDialog

void showAsBottomSheet() async {
  final result = await showSlidingBottomSheet(
    context,
    builder: (context) {
      return SlidingSheetDialog(
        elevation: 8,
        cornerRadius: 16,
        snapSpec: const SnapSpec(
          snap: true,
          snappings: [0.4, 0.7, 1.0],
          positioning: SnapPositioning.relativeToAvailableSpace,
        ),
        builder: (context, state) {
          return Container(
            height: 400,
            child: Center(
              child: Material(
                child: InkWell(
                  onTap: () => Navigator.pop(context, 'This is the result.'),
                  child: Padding(
                    padding: const EdgeInsets.all(16),
                    child: Text(
                      'This is the content of the sheet',
                      style: Theme.of(context).textTheme.body1,
                    ),
                  ),
                ),
              ),
            ),
          );
        },
      );
    }
  );

  print(result); // This is the result.
}

结果

Example

吸附

SlidingSheet 可以吸附到多个高度,或者根本不吸附。您可以通过
SnapSpec 的实例传递给 SlidingSheet 来自定义吸附行为。

参数 描述
snap 如果为 true,SlidingSheet 将吸附到提供的 snappings。如果为 false,SlidingSheet 将从 minExtent 滑动到 maxExtent,然后开始滚动(如果内容大于可用高度)。
snappings 当用户结束拖动交互时,SlidingSheet 将吸附到的高度。最小和最大值将代表 SlidingSheet 可以扩展的边界,直到达到最大值,然后开始滚动。
positioning 可以设置为以下三个值之一:SnapPositioning.relativeToAvailableSpace - 将吸附位置相对于 SlidingSheet 可扩展的总可用高度。所有值必须在 0 到 1 之间。例如,在没有 AppBarScaffold 中,吸附到 0.5 意味着吸附位置将是屏幕高度的 40%,而与 SlidingSheet 的高度无关。 SnapPositioning.relativeToSheetHeight - 将吸附位置相对于表单的总高度。所有值必须在 0 到 1 之间。例如,吸附到 0.5 且总表单大小为 300 像素意味着吸附位置将距离底部 150 像素。 SnapPositioning.pixelOffset - 将吸附位置设置为固定的像素偏移量。 double.infinity 可用于引用可用总空间,而无需自行计算。
onSnap SlidingSheet 吸附到某个高度时调用的回调函数。

SnapPositioning.relativeToAvailableSpace with a snap of 0.5 SnapPositioning.relativeToSheetHeight with a snap of 0.5 SnapPositioning.pixelOffset with a snap of 100

还有一些预制的吸附方式,您可以使用它们来吸附,例如标题或页脚,如示例所示。

Snap 描述
SnapSpec.headerFooterSnap 该吸附高度使标题和页脚完全可见,而不考虑 SlidingSheet 上的垂直填充。
SnapSpec.headerSnap 该吸附高度使标题完全可见,而不考虑 SlidingSheet 上的顶部填充。
SnapSpec.footerSnap 该吸附高度使页脚完全可见,而不考虑 SlidingSheet 上的底部填充。
SnapSpec.expanded SlidingSheet 扩展到最大高度的吸附。

SheetController

SheetController 可用于手动更改 SlidingSheet 的状态,只需将 SheetController 的实例传递给 SlidingSheet 即可。请注意,这些方法只能在 SlidingSheet 渲染后使用,但提前调用它们不会抛出异常。

请注意,您还可以使用静态 SheetController.of(context) 方法来获取最近的 SlidingSheetSheetController 实例。即使您没有在 SlidingSheet 上显式分配 SheetController,此方法也有效。

方法 描述
expand() SlidingSheet 扩展到最大高度。
collapse() SlidingSheet 折叠到最小高度。
snapToExtent() SlidingSheet 吸附到任意高度。该高度将被限制在最小和最大高度之间。如果滚动偏移量大于 0,SlidingSheet 将首先滚动到顶部,然后滑动到指定高度。
scrollTo() SlidingSheet 滚动到给定偏移量。如果 SlidingSheet 尚未达到其最大高度,它将首先吸附到最大高度,然后滚动到给定偏移量。
rebuild() 调用 SlidingSheet 的所有构建器来重建它们的子项。此方法可用于反映 SlidingSheet 子项的变化,而无需在父小部件上调用 setState(() {});,从而提高性能。
show() 如果 SlidingSheet 之前被隐藏,则将其显示出来。请注意,此方法对 SlidingSheetDialogs 无效。
hide() 隐藏 SlidingSheet,直到您再次调用 show()。请注意,此方法对 SlidingSheetDialogs 无效。

标题和页脚

标题和页脚是 SlidingSheet 的 UI 元素,它们将分别显示在 SlidingSheet 的顶部或底部,并且不会滚动。然后,可滚动内容将位于标题和页脚之间(如果指定)。触摸事件委托给 SlidingSheet 已为您完成。示例

@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.grey.shade200,
    appBar: AppBar(
      title: Text('Simple Example'),
    ),
    body: Stack(
      children: <Widget>[
        SlidingSheet(
          elevation: 8,
          cornerRadius: 16,
          snapSpec: const SnapSpec(
            snap: true,
            snappings: [112, 400, double.infinity],
            positioning: SnapPositioning.pixelOffset,
          ),
          builder: (context, state) {
            return Container(
              height: 500,
              child: Center(
                child: Text(
                  'This is the content of the sheet',
                  style: Theme.of(context).textTheme.body1,
                ),
              ),
            );
          },
          headerBuilder: (context, state) {
            return Container(
              height: 56,
              width: double.infinity,
              color: Colors.green,
              alignment: Alignment.center,
              child: Text(
                'This is the header',
                style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),
              ),
            );
          },
          footerBuilder: (context, state) {
            return Container(
              height: 56,
              width: double.infinity,
              color: Colors.yellow,
              alignment: Alignment.center,
              child: Text(
                'This is the footer',
                style: Theme.of(context).textTheme.body1.copyWith(color: Colors.black),
              ),
            );
          },
        ),
      ],
    ),
  );
}

结果

Simple header/footer example

ListViews 和 Columns

不允许 SlidingSheet 的子项具有无限(无边界)高度。因此,在使用 ListView 时,请确保将 shrinkWrap 设置为 true,并将 physics 设置为 NeverScrollableScrollPhysics。类似地,当使用 Column 作为 SlidingSheet 的子项时,请确保将 mainAxisSize 设置为 MainAxisSize.min

反映变化

为了提高性能,SlidingSheet 的子项在滑动或滚动时不会重建。但是,您可以将回调函数传递给 SlidingSheetlistener 参数,该函数会在 SlidingSheet 滑动或滚动时使用当前的 SheetState 调用。然后,您可以通过调用 setState(() {})(SheetController的实例).rebuild() 或通过其他状态管理解决方案来重建 UI 以重建表单。当使用 SlidingSheet 作为 bottomSheetDialog 时,您还可以使用 (SheetController的实例).rebuild() 来重建表单。

例如,当 SlidingSheet 向顶部拖动时,它会减小其圆角半径,并通过状态栏高度增加标题的顶部填充。由于这在 Material Bottom Sheets 中是很常见的行为,SlidingSheet 支持开箱即用,可以通过将 addTopViewPaddingOnFullscreen 参数设置为 true 并将 cornerRadiusOnFullscreen 设置为 0 来实现。

Example on how to reflect changes in the SlidingSheet

GitHub

https://github.com/bnxm/sliding_sheet