【问题标题】:How to send data between tabs in Flutter?如何在 Flutter 中的选项卡之间发送数据?
【发布时间】:2019-06-18 21:44:30
【问题描述】:

我有一个带有 2 个选项卡的 Flutter 应用程序:一个管理和接收连续的数据流,另一个选项卡显示传入的数据。

如何将数据从第一个选项卡传递到第二个选项卡?我看到的大部分帖子都是关于在父母和孩子之间传递数据,而不是在孩子之间传递数据。

我会使用GlobalKey 吗?有更好的选择吗?

这是主要的构建功能:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('some text'),
      bottom: TabBar(
        tabs: tabs,
        controller: _tabController,
      ),
    ),
    body: TabBarView(
      controller: _tabController,
      children: [
        InputManagment(),
        InfiniteListView(),
      ],
    ),
  );
}

【问题讨论】:

  • 您可以创建一个回调并将数据发送回父级,然后将其移动到第二个选项卡。

标签: flutter dart


【解决方案1】:

在这种情况下,建议使用InheritedWidget

documentation for InheritedWidget 很全面,包括一个video from the Flutter team

首先,您可能想要创建一个类来保存您要共享的数据。

import 'dart:async';

class MyInheritedWidgetData {
  var sharedData;
  int someCount;
  String someMessage;

  final StreamController _streamController = StreamController.broadcast();

  Stream get stream => _streamController.stream;

  Sink get sink => _streamController.sink;
}

我刚刚在这个类中添加了一堆变量。你可以用任何你想要的东西来填充它。
现在,您还希望拥有一个包含此数据类的InheritedWidget

class MyInheritedWidget extends InheritedWidget {
  final MyInheritedWidgetData data;

  MyInheritedWidget({
    Key key,
    @required Widget child,
  })  : assert(child != null),
        data = MyInheritedWidgetData(),
        super(key: key, child: child);

  static MyInheritedWidgetData of(BuildContext context) => (context.inheritFromWidgetOfExactType(MyInheritedWidget) as MyInheritedWidget).data;

  @override
  bool updateShouldNotify(MyInheritedWidget old) => false;
}

您需要将此MyInheritedWidget 放在小部件树的顶部或至少在您谈到的父小部件之上。下面应该说明必要的小部件层次结构。

MyInheritedWidget
 TabBarView
   InputManagment
   InfiniteListView
// in your build function this would be `body: MyInheritedWidget(child: TabBarView(...))`

现在,您可以在任何子小部件中使用 MyInheritedWidget.of(context) 轻松访问您的数据类。

您可能需要考虑使用流来连续发送和收听“数据流”。但是,这也只是数据类的一部分。为了给你一个想法,我在示例数据类中包含了流变量。您可以使用MyInheritedWidget.of(context).sink.add(..) 添加数据,并使用MyInheritedWidget.of(context).stream 将您的流提供给StreamBuilder

这些只是解释在小部件之间共享数据所需的示例。您可以阅读documentation 了解更多信息和更高级的用例。

【讨论】:

    【解决方案2】:

    我相信 Provider 是在 Flutter Application 中管理状态的推荐方法,并在 Google IO 上介绍过,并且在 Flutter Documentation on State Management 中处于状态管理堆栈的顶部

    作为我的提供者服务...

    import 'dart:collection';
    import 'package:flutter/material.dart';
    
    class Item {
      String name;
      num price;
    
      Item(this.name, this.price);
    }
    
    class CartModel extends ChangeNotifier {
      /// Internal, private state of the cart.
      final List<Item> _items = [];
    
      /// An unmodifiable view of the items in the cart.
      UnmodifiableListView<Item> get items => UnmodifiableListView(_items);
    
      /// The current total price of all items (assuming all items cost $42).
      /// int get totalPrice => _items.length * 42;
    
      /// Adds [item] to cart. This is the only way to modify the cart from outside.
      void add(Item item) {
        _items.add(item);
        // This call tells the widgets that are listening to this model to rebuild.
        notifyListeners();
      }
    }
    

    设置访问状态*

    void main() => runApp(
          ChangeNotifierProvider<CartModel>(
            child: TabBarDemo(),
            builder: (BuildContext context) {
              return CartModel();
            },
          ),
        );
    

    从顶层访问状态以在标签标题中显示计数

    class TabBarDemo extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        var count = Provider.of<CartModel>(context).items.length;
    

    将商品添加到购物车时从第一个选项卡访问状态

      RaisedButton(
          child: Text("Add Item"),
          onPressed: () async {
            final form = _formKey.currentState;
            form.save();
            if (form.validate()) {
              Provider.of<CartModel>(context)
                  .add(new Item(_name, num.parse(_price)));
            } else {
              print('validate failed');
            }
            _formKey.currentState.reset();
          })
    

    查看完整示例:https://github.com/aaronksaunders/flutter_simple_tabs,此代码基于Flutter Documentation Example

    【讨论】:

      【解决方案3】:

      我发现使用 good-ole 有状态小部件很容易。 InputManagement 上有一个一流的函数,它获取数据并构建主页。重要的是要注意 InputManagement 应该负责任地调用此函数,因为它会重建页面。

      import 'package:flutter/material.dart';
      
      void main() => runApp(App());
      
      class App extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            title: 'Tabbar Answer',
            home: HomePage(),
          );
        }
      }
      
      class HomePage extends StatefulWidget {
        @override
        _HomePageState createState() => _HomePageState();
      }
      
      class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
        TabController tabController;
        List<dynamic> data = [];
      
        @override
        void initState() {
          super.initState();
          tabController = TabController(length: 2, vsync: this);
        }
      
        @override
        Widget build(BuildContext context) => Scaffold(
            appBar: AppBar(title: Text("Tab Delegate")),
            body: TabBarView(children: [InputManagement(data: data, delegate: (newData) => setState(() { data = newData; })), InfiniteListView(data: data)], controller: tabController),
            bottomNavigationBar: TabBar(controller: tabController, tabs: [Icon(Icons.mail, color: Colors.black), Icon(Icons.view_agenda, color: Colors.black,)])
          );
      }
      
      class InputManagement extends StatelessWidget {
        List<dynamic> data;
        void Function(dynamic) delegate;
        InputManagement({this.data, this.delegate});
      
        add(dynamic dataItem) {
          data.add(dataItem);
          delegate(data);
        }
      
        @override
        Widget build(BuildContext context) => Center(child: FloatingActionButton(onPressed: () => add(data.isEmpty ? 0 : data.last + 1), child: Icon(Icons.add)));
      }
      
      class InfiniteListView extends StatelessWidget {
        List<dynamic> data = [];
        InfiniteListView({this.data});
        @override
        Widget build(BuildContext context) => ListView.builder(itemBuilder: (context, index) => Container(height: 100, width: MediaQuery.of(context).size.width, alignment: Alignment.center, child: Text(data[index].toString(), style: Theme.of(context).textTheme.title.copyWith(color: Colors.black),)), itemCount: data.length);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-31
        • 2014-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-31
        • 2022-11-28
        • 2021-07-10
        相关资源
        最近更新 更多