Flutter 如何在Flatter中的选项卡之间发送数据?

Flutter 如何在Flatter中的选项卡之间发送数据?,flutter,dart,Flutter,Dart,我有一个Flatter应用程序,有两个选项卡:一个用于管理和接收连续的数据流,另一个选项卡在数据进入时显示数据 如何将数据从第一个选项卡传递到第二个选项卡?我看到的大部分帖子都是关于在父级和子级之间传递数据,而不是子级到子级 我会使用GlobalKey?有更好的选择吗 这是主要的构建功能: @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const

我有一个Flatter应用程序,有两个选项卡:一个用于管理和接收连续的数据流,另一个选项卡在数据进入时显示数据

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

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

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

这是非常全面的,包括一个

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

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将您的流提供给一个
MyInheritedWidget.of(context).stream


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

我相信该提供程序是管理颤振应用程序中状态的推荐方法,并在Google IO上展示,并且在

  • 谷歌I/O视频
作为我的提供商提供服务…

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();
  }
}
导入“dart:collection”;
进口“包装:颤振/材料.省道”;
类项目{
字符串名;
数量价格;
项目(此名称、此价格);
}
类CartModel扩展了ChangeNotifier{
///购物车的内部、私有状态。
最终清单_项=[];
///购物车中项目的不可修改视图。
UnmodifiableListView get items=>UnmodifiableListView(\u items);
///所有项目的当前总价(假设所有项目成本为42美元)。
///int get totalPrice=>\u items.length*42;
///将[项目]添加到购物车。这是从外部修改购物车的唯一方法。
无效添加(项目){
_项目。添加(项目);
//此调用告诉正在侦听此模型的小部件重建。
notifyListeners();
}
}
设置对状态的访问*

void main() => runApp(
      ChangeNotifierProvider<CartModel>(
        child: TabBarDemo(),
        builder: (BuildContext context) {
          return CartModel();
        },
      ),
    );
void main()=>runApp(
变更通知提供者(
子项:TabBarDemo(),
生成器:(BuildContext上下文){
返回CartModel();
},
),
);
从顶层访问状态以在选项卡标题中显示计数

class TabBarDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var count = Provider.of<CartModel>(context).items.length;
类TabBarDemo扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
var count=Provider.of(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();
      })
RaisedButton(
子项:文本(“添加项”),
onPressed:()异步{
最终形式=_formKey.currentState;
form.save();
if(form.validate()){
提供者(上下文)
.add(新项目(_name,num.parse(_price));
}否则{
打印(“验证失败”);
}
_formKey.currentState.reset();
})

请参见此处的完整示例:,此代码基于

我发现使用好的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);
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(App());
类应用程序扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“Tabbar答案”,
主页:主页(),
);
}
}
类主页扩展了StatefulWidget{
@凌驾
_HomePageState createState()=>\u HomePageState();
}
类_HomePageState使用SingleTickerProviderStateMixin扩展状态{
TabController TabController;
列表数据=[];
@凌驾
void initState(){
super.initState();
tabController=tabController(长度:2,vsync:this);
}
@凌驾
小部件构建(构建上下文)=>Scaffold(
appBar:appBar(标题:文本(“制表符委托”),
主体:TabBarView(子项:[输入管理(数据:数据,委托:(newData)=>setState((){data=newData;})),InfiniteListView(数据:数据)],控制器:tabController),
底部导航栏:选项卡栏(控制器:选项卡控制器,选项卡:[图标(Icons.mail,颜色:Colors.black),图标(Icons.view\u议程,颜色:Colors.black,)]
);
}
类InputManagement扩展了无状态小部件{
列出数据;
无效功能(动态)委托;
InputManagement({this.data,this.delegate});
添加(动态数据项){
data.add(数据项);
代表(数据);
}
@凌驾
小部件构建(BuildContext上下文)=>Center(子级:FloatingActionButton(按下时:()=>add(data.isEmpty?0:data.last+1),子级:Icon(Icons.add));
}
类InfiniteListView扩展了无状态小部件{
列表数据=[];
InfiniteListView({this.data});
@凌驾
小部件构建(BuildContext context)=>ListView.builder(itemBuilder:(context,index)=>Container(高度:100,宽度:MediaQuery.of(context).size.width,对齐方式:alignment.center,child:Text(数据[index].toString(),样式:Theme.of(context).textTheme.title.copyWith(颜色:Colors.black)),itemCount:data.length);
}