Flutter DraggableScrollableSheet - 如何通过编程方式展开/折叠

24
我在想是否有人知道或发现了一种方法可以通过编程方式使Flutter的DraggableScrollableSheet展开/折叠。我正在使用Flutter最新版构建,可以将其包装在中。
NotificationListener<DraggableScrollableNotification>

我可以听到表格扩张/折叠的程度。但是,我不清楚如何将已扩展的表格折叠起来或反之亦然。

看起来在小部件源文件中有一个

DraggableScrollableActuator

它暴露了一个静态的 .reset 但我不知道 / 想到让它工作的方法。

3个回答

21
建立在Pierre的答案上,我最终实现了一个解决方法,它允许我使用DraggableScrollableActuator来折叠和展开DraggableScrollableSheet
您可以使用setState方法更改initialChildSize的值,然后使用DraggableScrollableActuator.reset方法来展开或折叠表格。
void toggleDraggableScrollableSheet() {
  if (draggableSheetContext != null) {
    setState(() {
      initialExtent = isExpanded ? minExtent : maxExtent;
    });
    DraggableScrollableActuator.reset(draggableSheetContext);
  }
}

要使这个工作成立的重要事情是为小部件折叠和展开时提供不同的Key。这将导致两个 _DraggableScrollableSheetState 实例 - 一个可以重置为折叠状态,另一个可以重置为展开状态。

DraggableScrollableActuator(
  child: DraggableScrollableSheet(
    key: Key(initialExtent.toString()),
    minChildSize: minExtent,
    maxChildSize: maxExtent,
    initialChildSize: initialExtent,
    builder: draggableScrollableSheetBuilder,
  ),
)

编辑:

工作示例:

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  static const List<Color> colors = [
    Colors.red,
    Colors.green,
    Colors.blue,
  ];

  static const double minExtent = 0.2;
  static const double maxExtent = 0.6;

  bool isExpanded = false;
  double initialExtent = minExtent;
  BuildContext draggableSheetContext;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: _buildBody(),
      ),
    );
  }

  Widget _buildBody() {
    return InkWell(
      onTap: _toggleDraggableScrollableSheet,
      child: DraggableScrollableActuator(
        child: DraggableScrollableSheet(
          key: Key(initialExtent.toString()),
          minChildSize: minExtent,
          maxChildSize: maxExtent,
          initialChildSize: initialExtent,
          builder: _draggableScrollableSheetBuilder,
        ),
      ),
    );
  }

  void _toggleDraggableScrollableSheet() {
    if (draggableSheetContext != null) {
      setState(() {
        initialExtent = isExpanded ? minExtent : maxExtent;
        isExpanded = !isExpanded;
      });
      DraggableScrollableActuator.reset(draggableSheetContext);
    }
  }

  Widget _draggableScrollableSheetBuilder(
    BuildContext context,
    ScrollController scrollController,
  ) {
    draggableSheetContext = context;
    return SingleChildScrollView(
      controller: scrollController,
      child: Column(
        children: colors
            .map((color) => Container(
                  height: 200,
                  width: double.infinity,
                  color: color,
                ))
            .toList(),
      ),
    );
  }
}

你能否提供一个完整的可工作示例?@gtrochimiuk - MahmutTariq
1
非常感谢,我真的卡住了,差点要放弃了。 - Muneeb ur Rehman
1
@gtrochimiuk 我已经使用了你的解决方案。但问题是UI中的变化很突兀。有没有一种方法可以使它平滑过渡? - Yashwardhan Pauranik
2
据我所知,目前还没有解决方案。在 Github 仓库中有一个开放问题,请求添加 animateTo 方法到 DraggableScrollableActuator 中,这将解决该问题: https://github.com/flutter/flutter/issues/45009 - gtrochimiuk

11

现在有一种新的解决方案——可以在稳定通道中使用。

通过使用新的DraggableScrollableController,您现在可以通过编程方式显示或隐藏DraggableScrollableSheet,可以选择是否使用动画效果。

class TestWidget extends StatelessWidget {
  final controller = DraggableScrollableController();
  final minChildSize = 0.2;

  @override
  Widget build(BuildContext context) {
    return DraggableScrollableSheet(
      controller: controller,
      minChildSize: minChildSize,
      builder: _buildBody(),
    );
  }

  void animatedHide() {
    controller.animateTo(
      minChildSize,
      duration: const Duration(milliseconds: 100),
      curve: Curves.easeOutBack,
    );
  }
}

此处提供文档: https://api.flutter.dev/flutter/widgets/DraggableScrollableController-class.html


尽管这个已经在11月份合并了,但它仍然没有出现在稳定版本中(目前的Flutter版本为2.8.1.)。我认为它将会在下一个更新中推出,可能会在二月或三月发布。 - Aleksandar
1
它已经是稳定版本。 - Nikita Shadkov

5
您可以使用DraggableScrollableActuatorDraggableScrollableSheet 重置为其initialChildSize。因此,您需要拥有BuildContext,该参数由DraggableScrollableSheet builder提供。
例如,您可以在DraggableScrollableSheet中创建一个按钮,并调用DraggableScrollableActuator.reset(context);
DraggableScrollableSheet(
  builder: (BuildContext context, ScrollController scrollController) {

    return MaterialButton(
      onPressed: () {
        DraggableScrollableActuator.reset(context);
      },
    );

  },
)

如果您想要在构建函数之外重置DraggableScrollableSheet,则需要创建一个BuildContext属性,它可以用来保存DraggableScrollableSheet的上下文。

谢谢你的回答 - 这允许“重置”,但似乎我找不到以编程方式控制底部表单高度的方法(例如,展开/折叠到特定高度),或者至少将表单发送到其最大高度... - Andre
@Andre 是的,没错。我需要这个功能是因为我打开表格,加载文本,然后想要根据需要调整高度。最终我复制了DraggableScrollableSheet并将其调整到我需要的样子。 - Pierre Fischer
4
就此而言,我已经向Flutter的GitHub页面提交了一个功能请求,希望扩展DraggableScrollableSheet/Actuator API,具体请参见https://github.com/flutter/flutter/issues/45009。 - filiph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接