I’m working a floating action button with some twists: when you click on the FloatingActionButton(), some InkWell() widgets become visible from a Stack(), where you can click on multiple options. When I inserted it to my application, I experienced something weird:
If I add the unique MyFAB() widget as a "home" option within MaterialApp(), the animation works perfectly and you can click on the small InkWell() widgets without any problems:
import 'package:flutter/material.dart';
import 'dart:math';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyFAB(),
);
}
}
class MyFAB extends StatefulWidget {
const MyFAB({Key? key}) : super(key: key);
@override
State<MyFAB> createState() => _MyFABState();
}
class _MyFABState extends State<MyFAB> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 300),
);
_animation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _toggle() {
if (_animationController.isDismissed) {
_animationController.forward();
} else {
_animationController.reverse();
}
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
_buildOption(Icons.mood, -0.2),
_buildOption(Icons.sentiment_satisfied, 0.27),
_buildOption(Icons.sentiment_dissatisfied, 0.72),
_buildOption(Icons.mood_bad, 1.2),
FloatingActionButton(
heroTag: "MyFAB",
onPressed: _toggle,
shape: const CircleBorder(),
child: AnimatedIcon(
icon: AnimatedIcons.menu_close,
progress: _animation,
),
),
],
);
}
Widget _buildOption(IconData icon, double index) {
final double angle = (index - 1.5) * 0.5 * pi;
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
final double offsetX = _animation.value * 70 * cos(angle);
final double offsetY = _animation.value * 70 * sin(angle);
return Transform.translate(
offset: Offset(offsetX, offsetY),
child: Transform.scale(
scale: _animation.value,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
print('Option tapped');
_toggle();
},
borderRadius: BorderRadius.circular(20),
splashColor: Colors.grey.withOpacity(0.5),
child: CircleAvatar(
radius: 20,
child: Icon(icon),
),
),
),
),
);
},
);
}
}
But if I add MyFAB() into a Scaffold() as a "floatingActionButton", the small icons become useless, you cannot click on them anymore.
import 'package:flutter/material.dart';
import 'dart:math';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
floatingActionButton: MyFAB(),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
),
);
}
}
class MyFAB extends StatefulWidget {
const MyFAB({Key? key}) : super(key: key);
@override
State<MyFAB> createState() => _MyFABState();
}
class _MyFABState extends State<MyFAB> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 300),
);
_animation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _toggle() {
if (_animationController.isDismissed) {
_animationController.forward();
} else {
_animationController.reverse();
}
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
_buildOption(Icons.mood, -0.2),
_buildOption(Icons.sentiment_satisfied, 0.27),
_buildOption(Icons.sentiment_dissatisfied, 0.72),
_buildOption(Icons.mood_bad, 1.2),
FloatingActionButton(
heroTag: "MyFAB",
onPressed: _toggle,
shape: const CircleBorder(),
child: AnimatedIcon(
icon: AnimatedIcons.menu_close,
progress: _animation,
),
),
],
);
}
Widget _buildOption(IconData icon, double index) {
final double angle = (index - 1.5) * 0.5 * pi;
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
final double offsetX = _animation.value * 70 * cos(angle);
final double offsetY = _animation.value * 70 * sin(angle);
return Transform.translate(
offset: Offset(offsetX, offsetY),
child: Transform.scale(
scale: _animation.value,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
print('Option tapped');
_toggle();
},
borderRadius: BorderRadius.circular(20),
splashColor: Colors.grey.withOpacity(0.5),
child: CircleAvatar(
radius: 20,
child: Icon(icon),
),
),
),
),
);
},
);
}
}
I’m a self-taught Flutter developer, still pretty new to it, so I got stuck at this point. What causing this behavior? How can I use MyFAB() within the Scaffold() without any problems?
You can try out my codes in https://dartpad.dev/
Thanks in advance!
I recoded the entire MyFAB() not to use Stack() widget, removed the "floatingActionButtonLocation"
option from the Scaffold(), nothing helped.
2
Answers
The issue you’re experiencing with the InkWell widgets not being clickable when MyFAB() is used as a floatingActionButton within a Scaffold is likely due to the positioning and hit testing of the widgets in the Stack. When using the floatingActionButton within a Scaffold, the floating action button’s stack might not cover the entire screen or the widgets in the stack might not be properly positioned within the tappable area.
To resolve this issue, you can ensure the Stack containing the InkWell widgets covers the entire screen and is positioned correctly. One approach is to use a Positioned widget to place the floating action button and the options correctly within the Stack.
Hey Can u just check this out !!!
the Stack inside the Scaffold ensures that the InkWell widgets and the FloatingActionButton are correctly positioned and cover the entire screen, making them clickable. The clipBehavior: Clip.none property of the Stack allows the InkWell widgets to be drawn outside the bounds of the Stack, if necessary. The Positioned widget ensures the floating action button is correctly placed at the bottom center of the screen. Adjust the bottom property of the Positioned widget as needed to get the desired position.
Its because tappable area in
floatingActionButton
is bounded to child widget and not with the 4 extra button, this is illustration iffloatingActionButton
child widget is wrapped with container to enlarge the layout area, marked with yellow color:Result:
My suggested answer step is below:
Container
orSizedBox
to resize the tap areaMyFAB
widget to align the button to bottom inside containerAnd below is the final code, changes marked with comments:
And this is the result, you can remove the color:
Hopefully it can solve your problem 😉