In Expandable Floating action button the gestures in the child widget is not detected in flutter

1,037

Look at this. https://api.flutter.dev/flutter/widgets/Transform-class.html

Unlike RotatedBox, which applies a rotation prior to layout, this object applies its transformation just prior to painting, which means the transformation is not taken into account when calculating how much space this widget's child (and thus this widget) consumes.

So, your fab1(),fab2(),fab3() have the same position. Although you animate them, it just move at painting, their real position wont change. Just give a color to your fabs, you will know what I mean.

        Container(
          color:Colors.green,
          child: Transform(
            transform:
                Matrix4.translationValues(-_translateAnimation!.value, 0, 0),
            child: fab2(),
          ),
        ),

Now you know why, and you need to know how. So I hope you can look at this. https://api.flutter.dev/flutter/animation/animation-library.html
You can use Stack&&Positioned,and with Tween, caculate each button's position, or other way. I will leave you to explore.

Here's some code of CustomFab.dart


  @override
  Widget build(BuildContext context) {
    return Container(
      // color: Colors.green, // Give this area a background color, then you know why.
      height: 150,// You need to give your "action area" a bigger size.
      width: 150,// make these bigger have a problem, your bar will have a bigger circle.
                // if you need this effect, you need to change all your fabs "Stack on the appbar"
                // or just remove `shape: CircularNotchedRectangle(),` in myhome.dart
      child: Stack(
        clipBehavior: Clip.none,
        children: [
          Positioned(// These numbers just for example, you can make your own size or position.
            left: 150 / 2 - 30,
            bottom: _translateAnimation.value + 40,
            child: fab1(),
          ),
          Positioned(
            left: 150 / 2 - 30 -_translateAnimation.value,
            bottom: 40,
            child: fab2(),
          ),
          Positioned(
            left: 150 / 2 - 30,
            bottom: 40,
            child: fab3(),
          ),
        ],
      ),
    );
  }
Share:
1,037
Lalit Thakare
Author by

Lalit Thakare

Updated on December 31, 2022

Comments

  • Lalit Thakare
    Lalit Thakare over 1 year

    Trying to implement a floating action button that extends in two dimension and then show some more option of floating action button. Somehow able to animated the child widget of the floating action button to their correct position, using the Transform Widget, but when I try to press on the child widget, i.e. the widgets that come out on pressing the floating action button, they do not respond to the onPressed handler. Tried many different thing like IgnorePointer, stacked rows and Columns, AnimatedBuilder,etc. but was unable to find the correct solution. It was like sometimes used to get the UI correct then the gesture was not detected and if the gesture were detected the UI got distorted. And I am somewhat new to flutter. Any help in sorting out this issue would be appreciated.

    Here is my Code:

    main.dart

    import "package:flutter/material.dart";
    import 'myhome.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(
            primaryColor: Colors.blue,
          ),
          title: "Custom Expandable FAB",
          home: MyHome(),
        );
      }
    }
    

    myhome.dart

    import 'package:flutter/material.dart';
    import 'package:tester_project/customFAB.dart';
    
    class MyHome extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          extendBody: true,
          backgroundColor: Colors.white,
          floatingActionButton: CustomFab(),
          floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
          bottomNavigationBar: BottomAppBar(
            color: Colors.blue,
            shape: CircularNotchedRectangle(),
            child: Container(
              height: 55,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  IconButton(
                    icon: Icon(Icons.search),
                    onPressed: () {},
                  ),
                  IconButton(
                    icon: Icon(Icons.menu),
                    onPressed: () {},
                  ),
                ],
              ),
            ),
          ),
          appBar: AppBar(
            title: Text("Custom FAB"),
          ),
          body: Container(
            alignment: Alignment.center,
            child: Text("Click on Fab to expand"),
            color: Colors.white,
          ),
        );
      }
    }
    

    CustomFab.dart

    import 'package:flutter/material.dart';
    import 'package:permission_handler/permission_handler.dart';
    
    class CustomFab extends StatefulWidget {
      @override
      _CustomFabState createState() => _CustomFabState();
    }
    
    class _CustomFabState extends State<CustomFab>
        with SingleTickerProviderStateMixin {
      AnimationController _animationController;
      Animation<double> _translateAnimation;
      Animation<double> _rotationAnimation;
    
      Animation<double> _iconRotation;
    
      bool _isExpanded = false;
    
      void animate() {
        if (!_isExpanded) {
          _animationController.forward();
        } else {
          _animationController.reverse();
        }
    
        _isExpanded = !_isExpanded;
      }
    
      Widget fab1() {
        return Container(
          height: 60,
          width: 60,
          child: FittedBox(
            child: FloatingActionButton(
              heroTag: "btn3",
              backgroundColor: Color(0xffFFC852),
              elevation: 0,
              onPressed: () {
                print("pressed");
              },
            ),
          ),
        );
      }
    
      Widget fab2() {
        return Container(
          height: 60,
          width: 60,
          child: FittedBox(
            child: FloatingActionButton(
              heroTag: "btn4",
              child: Transform.rotate(
                angle: _iconRotation.value,
                child: Icon(Icons.home),
              ),
              elevation: _isExpanded ? 5 : 0,
              backgroundColor: Color(0xffE5E4F4),
              onPressed: () {
                print("Pressed");
              },
            ),
          ),
        );
      }
    
      Widget fab3() {
        return Container(
          height: 60,
          width: 60,
          child: FittedBox(
            child: FloatingActionButton(
              heroTag: "btn5",
              child: Transform.rotate(
                angle: _rotationAnimation.value,
                child: Icon(Icons.add),
              ),
              backgroundColor: Color(0xffFFC852),
              onPressed: () async {
                await Permission.contacts.request();
                if (await Permission.contacts.status.isGranted) {
                  animate();
                }
              },
            ),
          ),
        );
      }
    
      @override
      void initState() {
        _animationController =
            AnimationController(vsync: this, duration: Duration(milliseconds: 400))
              ..addListener(() {
                setState(() {});
              });
        _translateAnimation = Tween<double>(begin: 0, end: 80)
            .chain(
              CurveTween(
                curve: _isExpanded ? Curves.fastOutSlowIn : Curves.bounceOut,
              ),
            )
            .animate(_animationController);
    
        _iconRotation = Tween<double>(begin: 3.14 / 2, end: 0)
            .chain(
              CurveTween(curve: Curves.bounceInOut),
            )
            .animate(_animationController);
        _rotationAnimation = Tween<double>(begin: 0, end: 3 * 3.14 / 4)
            .chain(
              CurveTween(
                curve: Curves.bounceInOut,
              ),
            )
            .animate(_animationController);
        super.initState();
      }
    
      @override
      void dispose() {
        _animationController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          clipBehavior: Clip.none,
          children: [
            Transform(
              transform:
                  Matrix4.translationValues(0, -_translateAnimation.value, 0),
              child: fab1(),
            ),
            Transform(
              transform:
                  Matrix4.translationValues(-_translateAnimation.value, 0, 0),
              child: fab2(),
            ),
            fab3(),
          ],
        );
      }
    }
    

    Floating action button before and after expansion

  • Lalit Thakare
    Lalit Thakare almost 3 years
    I have also tried to implement it using the stack and positioned widget but nothing changed everything remained the same...
  • Lalit Thakare
    Lalit Thakare almost 3 years
    Please help me with a different method if possible...
  • iwpz
    iwpz almost 3 years
    In your case, there's another problem is that, your stack's size is small, and you clipBehavior: Clip.none,, so buttons can be paint, but have no gesture area. I'll edit the answer.
  • iwpz
    iwpz almost 3 years
    About if you need this effect, you need to change all your fabs "Stack on the appbar", what I mean is, DO NOT make your floating buttons inside your CustomFab, you can make a Overlay, make buttons floating on screen, caculate their positions.