如何在Flutter中从模态框返回数据?

5
基本上,我正在使用 showModalBottomSheet 小部件来显示一个全屏容器,该容器具有一个 GestureDetector,该手势检测器在单击时运行以下操作:
onTap: () {
  final String testText = "Sup";
  Navigator.of(context).pop(testText);
}

当我调用showModalBottomSheet并等待结果时,这将明显返回文本,但是我还想设置enableDrag: true,以便我们可以滑动模态框使其消失。

我的问题是:

如何在滑动关闭时传递参数/结果?如果使用一个函数,我可以简单地使用Navigator.of(context).pop(...) 来实现,但是当我们滑动时,没有函数,因此我无法找到一种方法来在滑动关闭时传递参数。

谢谢!

3个回答

0
当你滑动时,pop()方法会被调用,没有任何方法可以覆盖它,但我找到了一种处理这种情况的方法:
您可以像这样在showModalBottomSheet()上使用then()方法:
showModalBottomSheet(context: context, builder: (context) => SecondPage()).then((value) {
        str = "done";
        print("data: $str");
      });

请记住,future返回的值是pop()方法返回的值,否则为null。


这只适用于要返回的数据是常量的情况吧?我想返回的数据是动态的,并且其值由模态窗口中的小部件确定。 - darkstar

0

使用此小部件并添加Navigator.pop。

->使用此WillPopScope

欲了解更多信息,请访问单击此处

或者

如果您想在pop中传递数据,请参阅示例:

import 'package:flutter/material.dart';

void main() {
  runApp(
    const MaterialApp(
      title: 'Returning Data',
      home: HomeScreen(),
    ),
  );
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Returning Data Demo'),
      ),
      body: const Center(
        child: SelectionButton(),
      ),
    );
  }
}

class SelectionButton extends StatelessWidget {
  const SelectionButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        _navigateAndDisplaySelection(context);
      },
      child: const Text('Pick an option, any option!'),
    );
  }

  // A method that launches the SelectionScreen and awaits the result from
  // Navigator.pop.
  void _navigateAndDisplaySelection(BuildContext context) async {
    // Navigator.push returns a Future that completes after calling
    // Navigator.pop on the Selection Screen.
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => const SelectionScreen()),
    );

    // After the Selection Screen returns a result, hide any previous snackbars
    // and show the new result.
    ScaffoldMessenger.of(context)
      ..removeCurrentSnackBar()
      ..showSnackBar(SnackBar(content: Text('$result')));
  }
}

class SelectionScreen extends StatelessWidget {
  const SelectionScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Pick an option'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: ElevatedButton(
                onPressed: () {
                  // Close the screen and return "Yep!" as the result.
                  Navigator.pop(context, 'Yep!');
                },
                child: const Text('Yep!'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: ElevatedButton(
                onPressed: () {
                  // Close the screen and return "Nope." as the result.
                  Navigator.pop(context, 'Nope.');
                },
                child: const Text('Nope.'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

选择屏幕:

Navigator.pop(context, 'Yep!');

按钮代码(导航器推送如下):

 final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => const SelectionScreen()),

了解更多信息


我已经检查过了,但它没有帮助,因为它只在你显式调用pop()并且按下应用栏返回按钮时才有用。 - Mohammad Hosein
请检查更新后的答案。 - Jeel Bhatti

0

看起来showModalBottomSheet没有指定关闭值的方法。所以在这种情况下它总是返回null。并且你不能做太多事情。但我看到的选项有:

  • 使用结果包装器通过引用返回值。像这样:
class MyResult {
    int myValue;
}

class MyBottomWidget ... {
    MyResult result;
    MyBottomWidget(this.result);

    // then you can initialize the value somewhere
    // result.myValue = 5;
}

final result = MyResult();
await showModalBottomSheet(context: context, builder: (_) => MyBottomWidget(result);
// and here you can use your value
print('Result value: ${result.myValue});

  • 另一种方法是在showModalBottomSheet的结果为null时返回一个值,这意味着模态框已关闭/解散。

final result = await showModalBottomSheet(...);
if (result == null) {
    // initialize the value with a value you need when modal is closed.
}

你可以创建一个函数包装器来简化这个过程:
Future<T> myShowModalBottomSheet<T>(BuildContext context, WidgetBuilder builder, T dismissValue) async {
  final value = await showModalBottomSheet<T>(context: context, builder: builder);
  return value ?? dismissValue;
}

或者像这样:

Future<T> myShowModalBottomSheet<T>(BuildContext context, WidgetBuilder builder, T Function() dismissedValueBuilder) async {
  final value = await showModalBottomSheet<T>(context: context, builder: builder);
  return value ?? dismissedValueBuilder();
}
  • 另一种方法是创建自己的shoModalBottomSheet函数,该函数将允许指定值。该函数的源代码可以使用,因此实现它并不那么困难。这将是最干净的解决方案,但仍然有一些缺点。首先,需要做的更多。另一件事是您的解决方案将与本机flutter函数不同步。也就是说,如果flutter更改了该函数或小部件的行为,您将需要更新代码。
  • pub.dev上搜索具有所需功能的程序包。

也许还有其他方法,但我不知道。


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