Menu Button In Flutter

Menu Button In Flutter :

Menu Button In Flutter : In this flutter tutorial we learn about how to create menu button in flutter.

First import the material.dart file. Then extend your main class to stateful widget.

It display the menu in the form of dropdown. the list of widget that we are use to create menu button in flutter. Button with decoration and menu divider are used in this tutorial.

simply this menu buttons are commonly used to select city,state,region,subject etc.in short it is used in any form design to select above mentioned categories.

you can also set the animation when the menu button is clicked and toggled also the box decoration is important part to create the menu button in flutter.

yo can also set which action should be performed after the menu item is selected.

the final output and the coding pf the menu button in flutter is given below. for more information study the below tutorial.

Screenshot :

Menu Button In Flutter

menu_button.dart

library menu_button;

import 'package:flutter/material.dart';

class MenuButton<T> extends StatefulWidget {
  final Widget child;
  final Widget toggledChild;
  final MenuItemBuilder<T> itemBuilder;
  final Widget divider;
  final bool topDivider;
  final List<T> items;
  final MenuItemSelected<T> onItemSelected;
  final BoxDecoration decoration;

  const MenuButton({
    @required final this.child,
    @required final this.items,
    @required final this.itemBuilder,
    final this.toggledChild,
    final this.divider,
    final this.topDivider = true,
    final this.onItemSelected,
    final this.decoration,
  })  : assert(child != null),
        assert(items != null),
        assert(itemBuilder != null);

  @override
  State<StatefulWidget> createState() => _MenuButtonState<T>();
}

class _MenuButtonState<T> extends State<MenuButton<T>> {
  @override
  Widget build(BuildContext context) => InkWell(
        child: Container(decoration: widget.decoration, child: widget.child),
        onTap: togglePopup,
      );

  void togglePopup() {
    final List<Widget> items = widget.items
        .map((value) => _MenuItem(
              value: value,
              child: widget.itemBuilder(value),
            ))
        .toList();
    final RenderBox button = context.findRenderObject();
    final RenderBox overlay = Overlay.of(context).context.findRenderObject();
    final RelativeRect position = RelativeRect.fromRect(
      Rect.fromPoints(
        button.localToGlobal(const Offset(0, 0), ancestor: overlay),
        button.localToGlobal(button.size.bottomRight(Offset.zero),
            ancestor: overlay),
      ),
      Offset.zero & overlay.size,
    );

    if (items.isNotEmpty) {
      _togglePopup(
        context: context,
        position: position,
        items: items,
        toggledChild: widget.toggledChild,
        divider: widget.divider,
        topDivider: widget.topDivider,
        decoration: widget.decoration,
      ).then<void>((T newValue) {
        if (mounted && newValue != null && widget.onItemSelected != null) {
          widget.onItemSelected(newValue);
        }
      });
    }
  }

  Future<T> _togglePopup(
          {@required BuildContext context,
          @required RelativeRect position,
          @required List<Widget> items,
          Widget toggledChild,
          Widget divider,
          bool topDivider,
          BoxDecoration decoration}) =>
      Navigator.push(
          context,
          _MenuRoute<T>(
            position: position,
            items: items,
            toggledChild: toggledChild,
            divider: divider,
            topDivider: topDivider,
            decoration: decoration,
          ));
}

class _MenuRoute<T> extends PopupRoute<T> {
  final RelativeRect position;
  final List<Widget> items;
  final Widget toggledChild;
  final Widget divider;
  final bool topDivider;
  final BoxDecoration decoration;

  _MenuRoute({
    final this.position,
    final this.items,
    final this.toggledChild,
    final this.divider,
    final this.topDivider,
    final this.decoration,
  });

  @override
  Color get barrierColor => null;

  @override
  bool get barrierDismissible => true;

  @override
  String get barrierLabel => null;

  @override
  Duration get transitionDuration => const Duration(milliseconds: 300);

  @override
  Animation<double> createAnimation() => CurvedAnimation(
        parent: super.createAnimation(),
        curve: Curves.easeOutCubic,
        reverseCurve: Curves.easeInCubic,
      );

  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
          Animation<double> secondaryAnimation) =>
      MediaQuery.removePadding(
        context: context,
        removeTop: true,
        removeBottom: true,
        removeLeft: true,
        removeRight: true,
        child: Builder(
          builder: (BuildContext context) {
            return CustomSingleChildLayout(
              delegate: _MenuRouteLayout(
                position,
              ),
              child: _Menu<T>(route: this),
            );
          },
        ),
      );
}

// Positioning of the menu on the screen.
class _MenuRouteLayout extends SingleChildLayoutDelegate {
  _MenuRouteLayout(this.position);

  // Rectangle of underlying button, relative to the overlay's dimensions.
  final RelativeRect position;

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    // The menu can be at most the size of the overlay minus 8.0 pixels in each
    // direction.
    return BoxConstraints.loose(constraints.biggest);
  }

  @override
  Offset getPositionForChild(Size size, Size childSize) =>
      Offset(position.left, position.top);

  @override
  bool shouldRelayout(_MenuRouteLayout oldDelegate) =>
      position != oldDelegate.position;
}

class _Menu<T> extends StatelessWidget {
  const _Menu({
    Key key,
    this.route,
  }) : super(key: key);

  final _MenuRoute<T> route;

  @override
  Widget build(BuildContext context) {
    final List<Widget> children = <Widget>[];

    if (route.topDivider) {
      children.add(route.divider);
    }

    for (int i = 0; i < route.items.length; i += 1) {
      children.add(route.items[i]);

      if (i < route.items.length - 1) {
        children.add(route.divider);
      }
    }

    final CurveTween opacity =
        CurveTween(curve: const Interval(0.0, 1.0 / 8.0));
    final CurveTween height = CurveTween(curve: const Interval(0.0, .9));
    final CurveTween shadow = CurveTween(curve: const Interval(0.0, 1.0 / 4.0));

    return Material(
      color: Colors.transparent,
      child: AnimatedBuilder(
        animation: route.animation,
        builder: (BuildContext context, Widget child) => Opacity(
          opacity: opacity.evaluate(route.animation),
          child: Container(
            decoration: BoxDecoration(
              border: route.decoration.border,
              borderRadius: route.decoration.borderRadius,
              boxShadow: [
                BoxShadow(
                    color: Color.fromARGB(
                        (20 * shadow.evaluate(route.animation)).toInt(),
                        0,
                        0,
                        0),
                    offset: Offset(0.0, 3.0 * shadow.evaluate(route.animation)),
                    blurRadius: 5.0 * shadow.evaluate(route.animation))
              ],
            ),
            child: ClipRRect(
              borderRadius: route.decoration.borderRadius,
              child: IntrinsicWidth(
                child: SingleChildScrollView(
                  physics: const NeverScrollableScrollPhysics(),
                  child: ListBody(children: [
                    _MenuButtonToggledChild(child: route.toggledChild),
                    Container(
                      color: route.decoration.color,
                      child: Align(
                        alignment: AlignmentDirectional.topStart,
                        widthFactor: 1.0,
                        heightFactor: height.evaluate(route.animation),
                        child: SingleChildScrollView(
                          child: ListBody(
                            children: children,
                          ),
                        ),
                      ),
                    ),
                  ]),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _MenuButtonToggledChild extends StatelessWidget {
  final Widget child;

  const _MenuButtonToggledChild({@required final this.child});

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () => Navigator.of(context).pop(),
      child: child,
    );
  }
}

class _MenuItem<T> extends StatelessWidget {
  final T value;
  final Widget child;

  const _MenuItem({this.value, @required final this.child});

  @override
  Widget build(BuildContext context) {
    return InkWell(
        onTap: () => Navigator.of(context).pop<T>(value), child: child);
  }
}

typedef MenuItemBuilder<T> = Widget Function(T value);

typedef MenuItemSelected<T> = void Function(T value);

main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Menu Button Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Menu Button Example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String selectedKey;

  List<String> keys = [
    'Low',
    'Medium',
    'High',
  ];

  @override
  void initState() {
    selectedKey = keys[0];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final Widget button = SizedBox(
      width: 93,
      height: 40,
      child: Padding(
        padding: const EdgeInsets.only(left: 16, right: 11),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Flexible(
              child: Text(
                selectedKey,
                overflow: TextOverflow.ellipsis,
              ),
            ),
            SizedBox(
                width: 12,
                height: 17,
                child: FittedBox(
                    fit: BoxFit.fill,
                    child: Icon(
                      Icons.arrow_drop_down,
                      color: Colors.grey,
                    ))),
          ],
        ),
      ),
    );

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            MenuButton(
              child: button,
              items: keys,
              topDivider: true,
              itemBuilder: (value) => Container(
                  height: 40,
                  alignment: Alignment.centerLeft,
                  padding: const EdgeInsets.symmetric(vertical: 0.0, horizontal: 16),
                  child: Text(
                      value
                  )),
              toggledChild: Container(
                color: Colors.white,
                child: button,
              ),
              divider: Container(
                height: 1,
                color: Colors.grey,
              ),
              onItemSelected: (value) {
                setState(() {
                  selectedKey = value;
                });
              },
              decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey[300]),
                  borderRadius: const BorderRadius.all(Radius.circular(3.0)),
                  color: Colors.white
              ),
            ),
          ],
        ),
      ),
    );
  }
}

The flutter tutorial  is a website that bring you the latest and amazing resources of code. All the languages codes are included in this website. The languages like flutter, android, java,kotlin etc.with the help of this languages any user can develop the beautiful application

For more information about Flutter. visit www.fluttertutorial.in