【问题标题】:How to update content of a ModalBottomSheet from parent while active如何在活动时从父级更新 ModalBottomSheet 的内容
【发布时间】:2020-11-12 07:34:40
【问题描述】:

我有一个自定义按钮,其中包含项目列表。当它被按下时,它会打开一个模态底部表并将该列表传递给底部表。

但是,当按钮项目发生变化时,它不会更新底部工作表中的项目。

我怎样才能达到这个效果。

简单示例

ButtonsPage
     |
Button(items: initialItems)
     |
BottomSheet(items: initialItems)

** After a delay, setState is called in ButtonsPage with newItems, thereby sending newItems to the button

ButtonsPage
     |
Button(items: newItems)
     | ## Here, the bottom sheet is open. I want it to update initialItems to be newItems in the bottom sheet

BottomSheet(items: initialItems -- should be newItems)

代码示例

这是我的选择字段,如图所示,它接收一个列表items,当按下它时,它会打开一个底部工作表并将收到的项目发送到底部工作表。

class PaperSelect extends StatefulWidget {
  final List<dynamic> items;

  PaperSelect({
    this.items,
  }) : super(key: key);

  @override
  _PaperSelectState createState() => _PaperSelectState();
}

class _PaperSelectState extends State<PaperSelect> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    return GestureDetector(
      onTap: widget.disabled ? null : () => _showBottomSheet(context),
        child: Container(
            
        ),
    );
  }

  void _showBottomSheet(BuildContext context) {
    showModalBottomSheet(
      context: context,
      builder: (BuildContext context) => BottomSheet(
        items: widget.items,
       ),
      )
    );
  }
}

一段时间后(网络调用),itemsPaperSelect 的父 Widget 中更新。 PaperSelect 然后更新并接收新项目。

class BottomSheet extends StatefulWidget {
  final dynamic items;

  BottomSheet({
    this.items,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return _BottomSheetState();
  }
}

class _BottomSheetState extends State<BottomSheet> {
  dynamic items;

  @override
  void initState() {
    print(widget.items);
    items = widget.items;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    if(items==null) return Center(
      child: SizedBox(
          width: 140.0,
          height: 140.0,
          child: PaperLoader()
      ),
    );

    if(items==-1) return Text("Network Error");

    return Column(
      children: <Widget>
        Expanded(
          child: ListView.builder(
            shrinkWrap: true,
            itemCount: items.length,
            itemBuilder: (BuildContext context, int i) => ListTile(
              onTap: () => Navigator.pop(context),
              title: Text('')
            )
          ),
        ),
      ],
    );
  }

}

现在,我想将更新后的数据发送到底部表格。但是,它不起作用,因为 ModalBottomSheet 已经打开。

我怎样才能解决这个问题?

【问题讨论】:

  • 我不完全确定我理解这个问题。我假设您的问题与使用 showBottomSheet 中的构建器创建的带有一组项目的 BottomSheet 的内容有关,但是当这些项目更改时,底部工作表没有更新? (因为构建器不会重新运行)。它是否正确?也许你可以在 dartpad 上展示一些代码甚至是一个简单的复制案例:-)
  • 没错。正是
  • 嗨,你知道有什么解决办法吗? @赫伯特
  • 你能把你底页的代码显示出来吗?
  • 我更新了问题。 PTAL

标签: flutter flutter-layout flutter-dependencies


【解决方案1】:

我在这里假设 items 是 List&lt;String&gt;,因为您根本没有指定。 (在大多数情况下,您通常不应该使用dynamic,因为它根本不进行任何类型检查)。总之,

您可以做的一件事(除了无数其他人之外)是传递ValueNotifier&lt;List&lt;String&gt;&gt; 而不是List&lt;String&gt;,然后在底部工作表中使用ValueListenableBuilder。喜欢:

// in the caller
    final itemsNotifier = ValueNotifier(items);


// in your bottom sheet
    ValueListenableBuilder<List<String>>(
      valueListenable: itemsNotifier,
      builder: (context, snapshot, child) {
        final items = snapshot.data;
        // build your list
      },
    )

那么每次您更改 itemsNotifier.value = [...] 您的项目都会重建。

更新itemsNotifier.value时注意:一定不能在build/didUpdateWidget/etc里面做。因此,如果是这种情况,您可以使用 WidgetsBinding.instance.addPostFrameCallback(() =&gt; itemsNotifier.value = ... ) 将更新值推迟到当前构建阶段之后。

【讨论】:

  • in initState,否则您将不会保留对正确对象的引用。上面的代码也适用于 Map ...显然适用于任何类型的对象..
  • 对不起,但这不是解决方案的错。对您的问题进行简单的复制,我会尝试为您修复它。但我不能只是猜测你的整个代码。例如,使用代码笔 codepen.io/pen/editor/flutterdartpad.dartlang.org 通过 gist 分享。
  • 给你:codepen.io/hpoul/pen/mdVvzOK .. 还有一个问题。您在内部小部件中创建了 ValueNotifier 并在 build() 上对其进行了更新,但这不起作用,因为它会同步尝试重建底部工作表。这就是为什么需要额外的WidgetsBinding.instance.addPostFrameCallback。我认为将ValueNotifier 提高一个级别会更好,并在PaperSelect 中也使用ValueListenableBuilder,我猜这可能是无状态的。
  • 不客气。我已经更新了答案。也许你可以接受。
  • 只要不引入任何类型错误,它就可以工作。但说真的,永远不要使用动态.. 恕我直言,这只是导致错误的原因,因为您基本上失去了完整的静态类型检查,这是一个坏主意
猜你喜欢
  • 2021-12-13
  • 1970-01-01
  • 2018-08-06
  • 2019-12-19
  • 1970-01-01
  • 2013-02-25
  • 2014-09-02
  • 2019-02-24
  • 2020-10-17
相关资源
最近更新 更多