【问题标题】:Flutter DraggableScrollableSheet - how to expand/collapse programmaticallyFlutter DraggableScrollableSheet - 如何以编程方式展开/折叠
【发布时间】:2019-11-11 05:22:59
【问题描述】:

我想知道是否有人知道/找到了一种以编程方式使 Flutters 的 DraggableScrollableSheet 展开/折叠的方法。我正在使用他们 Dev 频道的 Flutters 最新版本,它允许我将它包装在一个

NotificationListener<DraggableScrollableNotification>

然后我可以听到床单展开/折叠的程度。但是,我不清楚如何折叠展开的工作表,反之亦然。

似乎在小部件 src 文件中有一个

DraggableScrollableActuator

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

【问题讨论】:

    标签: flutter flutter-layout


    【解决方案1】:

    有一个新的解决方案可用,虽然目前仅在 Flutter 的 beta 通道上。

    通过使用新的DraggableScrollableController,您现在可以以编程方式显示或隐藏DraggableScrollableSheet,带或不带动画。

    警告:目前动画始终使用线性曲线。检查此 PR 是否已修复:https://github.com/flutter/flutter/pull/92440

    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://master-api.flutter.dev/flutter/widgets/DraggableScrollableController-class.html

    【讨论】:

      【解决方案2】:

      基于 Pierre 的回答,我最终实施了一种解决方法,允许我使用 DraggableScrollableActuator 来折叠和展开 DraggableScrollableSheet

      您可以使用setState 方法更改initialChildSize 的值,然后使用DraggableScrollableActuator.reset 方法展开或折叠工作表。

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

      重要的是要在小部件折叠和展开时提供不同的Key。这将产生 2 个 _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
      • 非常感谢,我真的被卡住了,快要放弃了。
      • @gtrochimiuk 我已经使用了您的解决方案。但问题是 UI 中出现了变化。有什么办法可以顺利完成吗?
      • 我不知道。 github repo 中有一个未解决的问题,请求将animateTo 方法添加到DraggableScrollableActuator 以解决问题:github.com/flutter/flutter/issues/45009
      【解决方案3】:

      您可以使用DraggableScrollableActuatorDraggableScrollableSheet 的位置重置为其initialChildSize。 因此,您需要拥有由 DraggableScrollableSheet builder-parameter 提供的BuildContext

      例如,您可以在DraggableScrollableSheet内创建一个Button并调用DraggableScrollableActuator.reset(context);

      DraggableScrollableSheet(
        builder: (BuildContext context, ScrollController scrollController) {
      
          return MaterialButton(
            onPressed: () {
              DraggableScrollableActuator.reset(context);
            },
          );
      
        },
      )
      

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

      【讨论】:

      • 感谢您的回答 - 这允许“重置”,但我似乎无法弄清楚以编程方式控制底部工作表的高度(例如展开/折叠到某个高度)或至少将工作表“发送”到其 maxHeight...
      • @Andre 是的,没错。我自己需要这个,因为我打开工作表,加载文本,然后想根据需要的高度调整高度。我最终复制了 DraggableScrollableSheet 并根据需要对其进行了调整。
      • FWIW,我提出了扩展 DraggableScrollableSheet/Actuator API 的功能请求:github.com/flutter/flutter/issues/45009
      猜你喜欢
      • 2012-07-01
      • 2018-06-17
      • 2015-08-19
      • 2017-05-07
      • 2011-07-06
      • 2014-12-18
      • 1970-01-01
      • 1970-01-01
      • 2010-10-29
      相关资源
      最近更新 更多