4
votes

In this widget the tabs navigate between types if it is question it goes a specified screen. If it is forum it goes to another one. The problem is I need to pass the type of the current tap to the on pressed function in the floating action button. However Floating action button is outside the body of the scaffold . Is there is way to pass a value to the floating action button ?


class TabScreen extends StatelessWidget {

  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState();
  @override
  Widget build(BuildContext context) {
    final bool showfab = MediaQuery.of(context).viewInsets.bottom == 0.0;
    final AuthService authService = Provider.of<AuthService>(context);
 return StreamBuilder<List<String>>(
              stream: forumServices.forumsTypes$,
              builder: (context, snapshot) {
                if (!snapshot.hasData) {
                  return CircularProgressIndicator();
                }
                List<String> types = snapshot.data;
                num tabLen = types.length;

                return DefaultTabController(
                    length: tabLen,
                    child: Scaffold(
                      key: _scaffoldKey,

                      body: CustomScrollView(slivers: <Widget>[
                        SliverAppBar(
                          title: Text("kdkdkkd"),
                          bottom: TabBar(
                              tabs: types.map((String f) {
                            return Text(f);
                          }).toList()),
                        ),
                        SliverFillRemaining(
                          child: StreamBuilder<List<Forums>>(
                              stream: forumServices.forums$,
                              builder: (context, snap) {
                                if (!snap.hasData) {
                                  return CircularProgressIndicator();
                                }
                                final forum = snap.data;
                                return TabBarView(
                                  children: types.map((String type) {
                                    List<Forums> listofthistype =
                                        forum.where((Forums fo) {
                                      return fo.type == type;
                                    }).toList();

                                    final cards = listofthistype
                                        .map((thistype) => ForumCard(
                                              choosentype: thistype,
                                              forumServices: forumServices,
                                            ))
                                        .toList();

                                    return ListView(
                                      children: cards,
                                    );
                                  }).toList(),
                                );
                              }),
                        ),
                      ]),
                      floatingActionButton:
                        FloatingActionButton(
                              onPressed: () => _showBottom(),
                              tooltip: 'Increment',
                              child: Icon(Icons.add),
                            )

                    ));
              });
3
I have the same problem. I want to pass the snapshot to the floating button onPressed function.markhorrocks
I used a model from where I get all my data and then recall it in the button using the providerAya Elsisy

3 Answers

2
votes

Remove the DefaultTabController widget and create your own TabController instead - this allows you to add a listener to the TabController which will be triggered every time the user navigates to a different tab. You can use this mechanism to get data associated to the index of the current tab, such as the type.

Here is the code you provided, with the modifications I mentioned above. The type is stored in the currentType variable, which you can use when tapping on the Fab.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class TabScreen extends StatefulWidget {
  @override
  _TabScreenState createState() => _TabScreenState();
}

class _TabScreenState extends State<TabScreen> with SingleTickerProviderStateMixin {
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  TabController tabController;
  String currentType;

  @override
  Widget build(BuildContext context) {
    final bool showfab = MediaQuery.of(context).viewInsets.bottom == 0.0;
    final AuthService authService = Provider.of<AuthService>(context);

    return StreamBuilder<List<String>>(
      stream: forumServices.forumsTypes$,
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return const CircularProgressIndicator();
        }
        List<String> types = snapshot.data;

        if (tabController == null) {
          currentType = types.first;

          tabController = TabController(length: types.length, vsync: this);
          tabController.addListener(() {
            currentType = types.elementAt(tabController.index);
          });
        }

        return Scaffold(
          key: _scaffoldKey,
          body: CustomScrollView(
            slivers: <Widget>[
              SliverAppBar(
                title: const Text("kdkdkkd"),
                bottom: TabBar(
                controller: tabController,
                tabs: types.map((String f) =>  Text(f)).toList()),
              ),
              SliverFillRemaining(
                child: StreamBuilder<List<Forums>>(
                  stream: forumServices.forums$,
                  builder: (context, snap) {
                    if (!snap.hasData) {
                      return const CircularProgressIndicator();
                    }
                    final forum = snap.data;

                    return TabBarView(
                      controller: tabController,
                      children: types.map((String type) {
                        List<Forums> listOfThisType = forum.where((Forums fo) => fo.type == type).toList();

                        return ListView(
                          children: listOfThisType.map((thisType) => ForumCard(
                            choosentype: thisType,
                            forumServices: forumServices,
                          )).toList(),
                        );
                      }).toList(),
                    );
                  },
                ),
              ),
            ],
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () => _showBottom(),
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ),
        );
      },
    );
  }
}
1
votes
class Screen extends StatelessWidget {
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  final GlobalKey<TabsWidgetState> _tabKey = GlobalKey<TabsWidgetState>();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<String>>(
        future: Future.delayed(
            const Duration(seconds: 1), () => ["Forum", "Question"]),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return CircularProgressIndicator();
          }
          List<String> types = snapshot.data;
          num tabLen = types.length;

          return Scaffold(
              key: _scaffoldKey,
              body: TabsWidget(key: _tabKey, tabLen: tabLen, types: types),
              floatingActionButton: FloatingActionButton(
                onPressed: () => print(_tabKey.currentState.currentQuestion),
                tooltip: 'Increment',
                child: Icon(Icons.add),
              ));
        });
  }
}

class TabsWidget extends StatefulWidget {
  const TabsWidget({
    Key key,
    @required this.tabLen,
    @required this.types,
  }) : super(key: key);

  final num tabLen;
  final List<String> types;

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

class TabsWidgetState extends State<TabsWidget> with SingleTickerProviderStateMixin{

   TabController _tabController;
   String currentQuestion;

  @override
  void initState() {
    _tabController = TabController(length: widget.tabLen, vsync: this)
    ..addListener(() {
      currentQuestion = widget.types[_tabController.index];
    });

  }

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(slivers: <Widget>[
      SliverAppBar(
        title: Text("kdkdkkd"),
        bottom: TabBar(
            controller: _tabController,
            tabs: widget.types.map((String f) {
              return Text(f);
            }).toList()),
      ),
      SliverFillRemaining(
        child: FutureBuilder(
            future: Future.delayed(const Duration(seconds: 1),
                    () => ["Forum", "Question"]),
            builder: (context, snap) {
              if (!snap.hasData) {
                return CircularProgressIndicator();
              }
              final forum = snap.data;
              return TabBarView(
                controller: _tabController,
                children: widget.types.map((String type) {
                  List<String> listofthistype =
                  forum.where((String fo) {
                    return fo == type;
                  }).toList();

                  final cards = listofthistype
                      .map((thistype) => Text(thistype))
                      .toList();

                  return ListView(
                    children: cards,
                  );
                }).toList(),
              );
            }),
      ),
    ]);
  }
}

For simplicity used futureBuilder If your length of tabs aren't loaded from snapshot you can avoid using global key and just create tab controller at the very beginning.

Don't forget to do null checking. Fab will be shown before data is loaded.

0
votes

You could store the data you need to pass in a variable and use that variable in onPressed of FloatingActionButton.