J'ai une application Flutter avec 2 onglets: l'un qui gère et reçoit un flux continu de données, l'autre affiche les données au fur et à mesure qu'elles entrent.

Comment passer les données du premier onglet au second? La plupart des articles que je vois concernent la transmission de données entre parent et enfant, et non d'enfant à enfant.

Est-ce que j'utiliserais GlobalKey? y a-t-il une meilleure option?

Voici la fonction de construction principale:

@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(),
      ],
    ),
  );
}
5
CrustyWang 19 juin 2019 à 00:44

3 réponses

Meilleure réponse

Dans ce cas, il est recommandé d'utiliser InheritedWidget.

La documentation pour InheritedWidget est très complète, y compris une vidéo de l'équipe Flutter.

Tout d'abord, vous souhaitez probablement créer une classe contenant les données que vous souhaitez partager.

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;
}

Je viens d'ajouter un tas de variables à cette classe. Vous pouvez le remplir avec ce que vous voulez.
Maintenant, vous voulez également avoir un InheritedWidget qui contient cette classe de données.

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;
}

Vous devez placer ce MyInheritedWidget en haut de votre arborescence de widgets ou au moins au-dessus du widget parent dont vous avez parlé. Ce qui suit est censé illustrer la hiérarchie nécessaire des widgets.

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

Désormais, vous pouvez simplement accéder à votre classe de données en utilisant MyInheritedWidget.of(context) dans l'un de vos widgets enfants.

Vous pouvez envisager d'utiliser des flux pour envoyer et écouter le «flux de données» en continu. Cependant, cela ferait simplement partie de la classe de données. Pour vous donner une idée, j'ai inclus la variable stream dans l'exemple de classe de données. Vous ajouteriez des données à l'aide de MyInheritedWidget.of(context).sink.add(..) et fourniriez votre flux à un {{ X1}} à l'aide de MyInheritedWidget.of(context).stream.

Ce ne sont que des exemples pour expliquer ce qui est nécessaire pour partager des données entre widgets. Vous pouvez lire la documentation pour plus d'informations et des cas d'utilisation plus avancés .

1
creativecreatorormaybenot 18 juin 2019 à 22:42

Je crois que le fournisseur est la méthode recommandée pour gérer l'état dans Flutter Application et a été présenté à Google IO et est au sommet de la pile pour la gestion de l'état dans le Documentation Flutter sur la gestion des états

service en tant que fournisseur ...

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();
  }
}

Configuration de l'accès à l'état *

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

Accès à l'état depuis le niveau supérieur pour afficher le nombre dans le titre de l'onglet

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

Accès à l'état depuis le premier onglet lors de l'ajout d'un article au panier

  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();
      })

Voir l'exemple complet ici: https://github.com/aaronksaunders/flutter_simple_tabs, ce code est basé sur l 'Exemple de documentation Flutter

1
Aaron Saunders 19 juin 2019 à 01:56

J'ai trouvé cela facile en utilisant un widget avec état bon. Il existe une fonction de première classe sur InputManagement qui prend les données et construit la page d'accueil. Il est important de noter que InputManagement doit appeler cette fonction de manière responsable, car elle reconstruit la page.

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);
}
0
jnblanchard 19 juin 2019 à 17:28