Passing a value to the floating action button to be used in the bottom sheet
Solution 1
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),
),
);
},
);
}
}
Solution 2
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.
Aya Elsisy
Updated on December 11, 2022Comments
-
Aya Elsisy over 1 year
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), ) )); });