0

In flutter creating a tabbar and navigating through the various pages with a list passed as a reference, the pages no longer report the correct data

Each tab contains a title and a list of strings, this list is displayed in each TabView, but browsing through the pages does not display the correct list.

class _TabsFabDemoState extends State<TabsFabDemo>  with SingleTickerProviderStateMixin {

  @override
  Widget build(BuildContext context) {
  return MaterialApp(
    home: DefaultTabController(
      length: choices.length,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Tabbed AppBar'),
          bottom: TabBar(
            isScrollable: true,
            tabs: choices.map((Choice choice) {
              return Tab(
                text: choice.title,
                icon: Icon(choice.icon),
              );
            }).toList(),
          ),
        ),
        body: Column(
          children: <Widget>[
            GestureDetector(
              onTap: (){
                choices.add(Choice(title: 'CAR', icon: Icons.directions_car));
                setState(() {});
              },
              child: Container(
                height: 100.0,
                color: Colors.red,
              ),
            ),
            Expanded(
              child: TabBarView(
                children: choices.map((Choice choice) {
                  return Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Center(child: ListaLinkWidget(tab: choice)),
                  );
                }).toList(),
              ),
            ),
          ],
        ),
      ),
     ),
    );
  }
}

class Choice {
  Choice({this.title, this.icon});

  final String title;
  final IconData icon;
  List<String> liststring = new List();
}

List<Choice> choices = <Choice>[
  Choice(title: 'CAR', icon: Icons.directions_car),
  Choice(title: 'BICYCLE', icon: Icons.directions_bike),
  Choice(title: 'BOAT', icon: Icons.directions_boat),
  Choice(title: 'BUS', icon: Icons.directions_bus),
  Choice(title: 'TRAIN', icon: Icons.directions_railway),
  Choice(title: 'WALK', icon: Icons.directions_walk),
];



class ListaLinkWidget extends StatefulWidget{

  Choice tab;

  ListaLinkWidget({Key key, this.tab}) : super(key: key);

  @override
  ListaLinkWidgetState createState() => ListaLinkWidgetState();

}

class ListaLinkWidgetState extends State<ListaLinkWidget> {


  @override
  void initState() {
    super.initState();
    widget.tab.liststring.add("a");
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      child: Text(
        widget.tab.liststring.toString()
      ),
    );
  }
}

I expected every page to have its own list and not go to interfere with that of the other pages, what am I wrong?

The init block of the widget is called so many times, how do I get it to be called only once?

Thanks

John
  • 313
  • 4
  • 17
  • you are using : `widget.tab.liststring.add("a");` and inside `Choice` you have List liststring = new List(); , so it's empty, every tab will have the same "a" – diegoveloper Oct 22 '19 at 17:43
  • Of course, but by changing the page the init method is called several times and the whole thing does not remain with the single string "a" – John Oct 23 '19 at 06:59

1 Answers1

0

Step 1: change Choice class, add this.liststring, remove = new List()

class Choice {
  Choice({this.title, this.icon, this.liststring});

  final String title;
  final IconData icon;
  List<String> liststring; //= new List();
}    

Step 2: choices add liststring Strings you need

List<Choice> choices = <Choice>[
Choice(title: 'CAR', icon: Icons.directions_car, liststring: ["car"]),
Choice(title: 'BICYCLE', icon: Icons.directions_bike, liststring: ["bike"]),

Step 3: remove widget.tab.liststring.add("a");

Step 4: OnTap need to change choices.add with liststring

GestureDetector(
                onTap: () {
                  _counter = _counter + 1;
                  choices.add(Choice(
                      title: 'New ${_counter}',
                      icon: Icons.directions_car,
                      liststring: ['List ${_counter}']));
                  setState(() {});
                },

full code

    import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: tabDemo(),
    );
  }
}

class tabDemo extends StatefulWidget {
  @override
  _tabDemoState createState() => _tabDemoState();
}

class _tabDemoState extends State<tabDemo> with SingleTickerProviderStateMixin {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: choices.length,
        child: Scaffold(
          appBar: AppBar(
            title: const Text('Tabbed AppBar'),
            bottom: TabBar(
              isScrollable: true,
              tabs: choices.map((Choice choice) {
                return Tab(
                  text: choice.title,
                  icon: Icon(choice.icon),
                );
              }).toList(),
            ),
          ),
          body: Column(
            children: <Widget>[
              GestureDetector(
                onTap: () {
                  _counter = _counter + 1;
                  choices.add(Choice(
                      title: 'New ${_counter}',
                      icon: Icons.directions_car,
                      liststring: ['List ${_counter}']));
                  setState(() {});
                },
                child: Container(
                  height: 100.0,
                  color: Colors.red,
                ),
              ),
              Expanded(
                child: TabBarView(
                  children: choices.map((Choice choice) {
                    return Padding(
                      padding: const EdgeInsets.all(16.0),
                      child: Center(child: ListaLinkWidget(tab: choice)),
                    );
                  }).toList(),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class Choice {
  Choice({this.title, this.icon, this.liststring});

  final String title;
  final IconData icon;
  List<String> liststring; //= new List();
}

List<Choice> choices = <Choice>[
  Choice(title: 'CAR', icon: Icons.directions_car, liststring: ["car"]),
  Choice(title: 'BICYCLE', icon: Icons.directions_bike, liststring: ["bike"]),
  /* Choice(title: 'BOAT', icon: Icons.directions_boat),
  Choice(title: 'BUS', icon: Icons.directions_bus),
  Choice(title: 'TRAIN', icon: Icons.directions_railway),
  Choice(title: 'WALK', icon: Icons.directions_walk),*/
];

class ListaLinkWidget extends StatefulWidget {
  Choice tab;

  ListaLinkWidget({Key key, this.tab}) : super(key: key);

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

class ListaLinkWidgetState extends State<ListaLinkWidget>
    with AutomaticKeepAliveClientMixin<ListaLinkWidget> {
  @override
  void initState() {
    super.initState();
    //widget.tab.liststring.add("a");
    print("created");
  }

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      child: Text(widget.tab.liststring.toString()),
    );
  }
}

enter image description here

chunhunghan
  • 51,087
  • 5
  • 102
  • 120
  • Thanks, but what would be useful to me is to make sure that in the widget ListaLinkWidgetState is added to the init method the addition of an element to the list ( widget.tab.liststring.add("a"); ) – John Oct 23 '19 at 06:58
  • The init block of the widget is called so many times, how do I get it to be called only once? – John Oct 23 '19 at 07:01
  • I have update my answer. you can do it with AutomaticKeepAliveClientMixin. I have tested. work fine. every tab print created only one time. – chunhunghan Oct 23 '19 at 07:11
  • Try to remove //widget.tab.liststring.add("a"); sometimes the init block is called twice – John Oct 24 '19 at 16:56
  • I found called twice reason https://stackoverflow.com/questions/56145378/why-is-initstate-called-twice – chunhunghan Oct 25 '19 at 01:53
  • You can use global bool variable or global List to keep trace , set bool to true if it has init before. – chunhunghan Oct 25 '19 at 01:56