2 ways to create floating action button bubble without package
January 12, 2023•281 words
Double Scaffold
Child Scaffold is for actual floatingActionButton and BottomNavBar. child scaffold store FAB bubbles. ValueNotifier is just demonstration only. use your state management for better result.
class MainScaffold extends StatefulWidget {
const MainScaffold({
super.key,
required this.child,
});
final Widget child;
@override
State<MainScaffold> createState() => _MainScaffoldState();
}
class _MainScaffoldState extends State<MainScaffold>
with SingleTickerProviderStateMixin {
late ValueNotifier<bool> showBubbles;
@override
void initState() {
showBubbles.value = !showBubbles.value;
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
onPressed: () {
showBubbles.value = !showBubbles.value;
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
child: const Icon(Icons.add),
),
],
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: const AppBottomNavBar(),
body: Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton:
FloatingActionButtonBubbles(showBubbles: showBubbles),
body: widget.child,
),
);
}
}
showDialog
a simple replacement using dialog.
class MainScaffold extends StatelessWidget {
final Widget child;
const MainScaffold({super.key, required this.child});
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
onPressed: () {
_showFloatingActionButtonBubbles(context);
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
child: const Icon(Icons.add),
),
],
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: const AppBottomNavBar(),
body: child,
);
}
void _showFloatingActionButtonBubbles(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return Padding(
padding:
const EdgeInsets.only(bottom: kBottomNavigationBarHeight + 56),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
margin: const EdgeInsets.symmetric(vertical: 4),
child: FloatingActionButton.extended(
label: const Text('New Incident'),
icon: const Icon(Icons.electric_bolt_outlined),
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24)),
),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 4),
child: FloatingActionButton.extended(
label: const Text('New Inspection'),
icon: const Icon(Icons.search),
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24)),
),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 4),
child: FloatingActionButton.extended(
label: const Text('New Note'),
icon: const Icon(Icons.note_add),
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24)),
),
),
],
),
);
},
);
}
}