Flutter Floating Action Menu Inside Listview

Last updated Jul 28, 2021

In this Flutter example we will learn how to create floating action menu in flutter. To create floating action menu we are going to use Flow widget with custom menus. We are applying animation while floating the menu items. Here we are adding floating action menu inside listview with multiple items

 

 

Flow widget constructor

Flow({
  Key? key,
  required this.delegate,
  List<Widget> children = const <Widget>[],
  this.clipBehavior = Clip.hardEdge,
})

 

The delegate property that controls the transformation matrices of the children.

final FlowDelegate delegate

 

Let's get started

Step 1: Create Flutter application

 

Step 2: Create Flow Menu items

final List<IconData> menuItems = <IconData>[
  Icons.home,
  Icons.new_releases,
  Icons.notifications,
  Icons.settings,
  Icons.menu,
];

 

Step 3: Set Menu item widget dimensions and its click events

Widget flowMenuItem(IconData icon,BuildContext context) {
  final double buttonDiameter = MediaQuery.of(context).size.width / menuItems.length;
  return Padding(
    padding: const EdgeInsets.symmetric(vertical: 4.0,horizontal: 4),
    child: Container(
      height: 28,
      width: 28,
      child: RawMaterialButton(

        fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue,
        splashColor: Colors.amber[100],
        shape: CircleBorder(),
        constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)),
        onPressed: () {
          _updateMenu(icon);
          menuAnimation.status == AnimationStatus.completed
              ? menuAnimation.reverse()
              : menuAnimation.forward();
        },
        child: Container(
          child: Icon(
            icon,
            color: Colors.white,
            size: 14.0,
          ),
        ),
      ),
    ),
  );
}

 

Step 4: Create Animation Controller to handle the Animation of the widget expand and collapse

menuAnimation = AnimationController(
  duration: const Duration(milliseconds: 250),
  vsync: this,
);

 

Step 5: Now add Child items to Listview

 ListView.builder(
  itemCount: 5,
    itemBuilder: (ctx,index){

  return ItemList();
})

 

Step 6: Run Application

 

Floating action Menu inside listview flutter

 

Complete code

list_item.dart

import 'dart:math';

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

class ItemList extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {

    return ItemListState();
  }

}
class ItemListState extends State<ItemList> with SingleTickerProviderStateMixin{
  late AnimationController menuAnimation;
  IconData lastTapped = Icons.notifications;
  final List<IconData> menuItems = <IconData>[
    Icons.home,
    Icons.new_releases,
    Icons.notifications,
    Icons.settings,
    Icons.menu,
  ];
  List<Color>colors=<Color>[
    Colors.green,Colors.blue,Colors.pink,Colors.brown,Colors.red
  ];
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Container(
          height: 90,

          margin: EdgeInsets.only(top: 24,left: 16,right: 8),
          decoration: new BoxDecoration(
            borderRadius: BorderRadius.circular(16),
            border: Border.all(width: 2.0, color: Colors.grey),
          ),
          child: Center(
            child: ListTile(
              leading: CircleAvatar(
                radius : 28 ,
                backgroundColor:  Colors.white ,
                child: CircleAvatar(
                  radius:  26,
                  backgroundImage:  NetworkImage(
                      "https://i.pinimg.com/originals/71/83/70/7183704aac01413c86805c19c1586e2b.jpg"),
                ),
              ),
              title: Text(
                "Freedom Fighter",
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700,color: Colors.deepPurple),
              ),
              subtitle: Text(
                'Freedom Fighter',
                style: TextStyle(
                    fontWeight: FontWeight.w600,
                    fontSize: 16,
                    color: Colors.white),
              ),
              trailing: Card(
                elevation: 1,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(15.0),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(5.0),
                  child: Container(
                    width: 50,
                    child: Row(
                      mainAxisSize: MainAxisSize.min,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text('5',
                            style: TextStyle(
                                fontSize: 20, color: Colors.grey)),
                        SizedBox(
                          width: 1,
                        ),
                        Icon(
                          Icons.access_alarms_outlined,
                          textDirection: TextDirection.rtl,
                          size: 20,
                          color: Colors.grey,
                        )
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
        Container(

          height: 80,
          margin: EdgeInsets.only(left: 16),
          child: Flow(
            clipBehavior: Clip.antiAliasWithSaveLayer,
            delegate: FlowMenuDelegate(menuAnimation: menuAnimation),
            children: menuItems.map<Widget>((IconData icon) => flowMenuItem(icon,context)).toList(),
          ),
        )
      ],

    );
  }
  Widget flowMenuItem(IconData icon,BuildContext context) {
    final double buttonDiameter = MediaQuery.of(context).size.width / menuItems.length;
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4.0,horizontal: 4),
      child: Container(
        height: 32,
        width: 32,
        child: RawMaterialButton(


          fillColor: lastTapped == icon ? Colors.amber[700] : colors[Random().nextInt(5)],
          splashColor: Colors.amber[100],
          shape: CircleBorder(),
          constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)),
          onPressed: () {
            _updateMenu(icon);
            menuAnimation.status == AnimationStatus.completed
                ? menuAnimation.reverse()
                : menuAnimation.forward();
          },
          child: Container(
            child: Icon(
              icon,
              color: Colors.white,
              size: 14.0,
            ),
          ),
        ),
      ),
    );
  }
  void _updateMenu(IconData icon) {
    if (icon != Icons.menu)
      setState(() => lastTapped = icon);
  }

  @override
  void initState() {
    super.initState();
    menuAnimation = AnimationController(
      duration: const Duration(milliseconds: 250),
      vsync: this,
    );
  }
}

class FlowMenuDelegate extends FlowDelegate {
  FlowMenuDelegate({required this.menuAnimation}) : super(repaint: menuAnimation);

  final Animation<double> menuAnimation;

  @override
  bool shouldRepaint(FlowMenuDelegate oldDelegate) {
    return menuAnimation != oldDelegate.menuAnimation;
  }

  @override
  void paintChildren(FlowPaintingContext context) {
    double dx = 0.0;
    for (int i = 0; i < context.childCount; ++i) {
      dx = context.getChildSize(i)!.width * i;
      context.paintChild(
        i,
        transform: Matrix4.translationValues(
          dx * menuAnimation.value,
          0,
          0,
        ),
      );
    }
  }
}

 

Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

662 Views