如何在Flutter中的标签之间发送数据?

时间:2019-06-18 21:44:30

标签: flutter dart

我有一个Flutter应用,其中包含2个标签:一个标签用于管理和接收连续的数据流,另一个标签显示输入的数据。

如何将数据从第一个标签传递到第二个标签?我看到的大多数帖子都是关于在父子之间传递数据,而不是在子与子之间传递数据。

我会使用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(),
      ],
    ),
  );
}

3 个答案:

答案 0 :(得分:0)

在这种情况下,建议使用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)即可访问数据类。

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

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

答案 1 :(得分:0)

我相信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

答案 2 :(得分:0)

我发现使用状态良好的小部件很容易。 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);
}