Giter Club home page Giter Club logo

pluto_menu_bar's Introduction

PlutoMenuBar for flutter - v3.0.1

PlutoMenuBar is a horizontal menu bar for flutter.

Features

  • Multiple sub-menu : Add as many submenus as you like.
  • Checkbox, Radio menu items.
  • Change the default style : Change the background, font, and border.
  • Hover-open sub menus.

Demo

Demo Web

Installation

pub.dev

Documentation

Documentation

Screenshots

PlutoMenuBar Image

Usage

// ignore_for_file: avoid_print

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('PlutoMenuBar'),
        ),
        body: const PlutoMenuBarDemo(),
      ),
    );
  }
}

class PlutoMenuBarDemo extends StatefulWidget {
  const PlutoMenuBarDemo({
    super.key,
  });

  @override
  State<PlutoMenuBarDemo> createState() => _PlutoMenuBarDemoState();
}

class _PlutoMenuBarDemoState extends State<PlutoMenuBarDemo> {
  late final List<PlutoMenuItem> whiteHoverMenus;

  late final List<PlutoMenuItem> orangeHoverMenus;

  late final List<PlutoMenuItem> whiteTapMenus;

  late final List<PlutoMenuItem> orangeTapMenus;

  @override
  void initState() {
    super.initState();

    whiteHoverMenus = _makeMenus(context);
    orangeHoverMenus = _makeMenus(context);
    whiteTapMenus = _makeMenus(context);
    orangeTapMenus = _makeMenus(context);
  }

  void message(context, String text) {
    ScaffoldMessenger.of(context).hideCurrentSnackBar();

    final snackBar = SnackBar(
      content: Text(text),
    );

    ScaffoldMessenger.of(context).showSnackBar(snackBar);
  }

  List<PlutoMenuItem> _makeMenus(BuildContext context) {
    return [
      PlutoMenuItem(
        title: 'Menu 1',
        icon: Icons.home,
        children: [
          PlutoMenuItem(
            title: 'Menu 1-1',
            icon: Icons.group,
            onTap: () => message(context, 'Menu 1-1 tap'),
            children: [
              PlutoMenuItem(
                title: 'Menu 1-1-1',
                onTap: () => message(context, 'Menu 1-1-1 tap'),
                children: [
                  PlutoMenuItem(
                    title: 'Menu 1-1-1-1',
                    onTap: () => message(context, 'Menu 1-1-1-1 tap'),
                  ),
                  PlutoMenuItem(
                    title: 'Menu 1-1-1-2',
                    onTap: () => message(context, 'Menu 1-1-1-2 tap'),
                  ),
                ],
              ),
              PlutoMenuItem(
                title: 'Menu 1-1-2',
                onTap: () => message(context, 'Menu 1-1-2 tap'),
              ),
            ],
          ),
          PlutoMenuItem(
            title: 'Menu 1-2',
            onTap: () => message(context, 'Menu 1-2 tap'),
          ),
          PlutoMenuItem.divider(height: 10),
          PlutoMenuItem.checkbox(
            title: 'Menu 1-3',
            initialCheckValue: true,
            // onTap: () => message(context, 'Menu 1-3 tap'),
            onChanged: (flag) => print(flag),
          ),
          PlutoMenuItem.divider(height: 10),
          PlutoMenuItem.radio(
            title: 'Menu 1-3',
            initialRadioValue: _RadioItems.one,
            radioItems: _RadioItems.values,
            // onTap: () => message(context, 'Menu 1-3 tap'),
            onChanged: (item) => print(item),
            getTitle: (item) {
              switch (item as _RadioItems) {
                case _RadioItems.one:
                  return 'One';
                case _RadioItems.two:
                  return 'Two';
                case _RadioItems.three:
                  return 'Three';
              }
            },
          ),
          PlutoMenuItem(
            title: 'Menu 1-4',
            icon: Icons.group,
            onTap: () => message(context, 'Menu 1-4 tap'),
            children: [
              PlutoMenuItem(
                title: 'Menu 1-4-1',
                onTap: () => message(context, 'Menu 1-4-1 tap'),
                children: [
                  PlutoMenuItem(
                    title: 'Menu 1-4-1-1',
                    onTap: () => message(context, 'Menu 1-4-1-1 tap'),
                  ),
                  PlutoMenuItem(
                    title: 'Menu 1-4-1-2',
                    onTap: () => message(context, 'Menu 1-4-1-2 tap'),
                  ),
                ],
              ),
              PlutoMenuItem(
                title: 'Menu 1-4-2',
                onTap: () => message(context, 'Menu 1-4-2 tap'),
              ),
            ],
          ),
        ],
      ),
      PlutoMenuItem(
        title: 'Menu 2',
        icon: Icons.add_circle,
        children: [
          PlutoMenuItem(
            title: 'Menu 2-1',
            onTap: () => message(context, 'Menu 2-1 tap'),
          ),
        ],
      ),
      PlutoMenuItem(
        title: 'Menu 3',
        icon: Icons.apps_outlined,
        onTap: () => message(context, 'Menu 3 tap'),
      ),
      PlutoMenuItem(
        title: 'Menu 4',
        onTap: () => message(context, 'Menu 4 tap'),
      ),
      PlutoMenuItem(
        title: 'Menu 5',
        onTap: () => message(context, 'Menu 5 tap'),
      ),
      PlutoMenuItem(
        title: 'Menu 6',
        children: [
          PlutoMenuItem(
            title: 'Menu 6-1',
            onTap: () => message(context, 'Menu 6-1 tap'),
            children: [
              PlutoMenuItem(
                title: 'Menu 6-1-1',
                onTap: () => message(context, 'Menu 6-1-1 tap'),
                children: [
                  PlutoMenuItem(
                    title: 'Menu 6-1-1-1',
                    onTap: () => message(context, 'Menu 6-1-1-1 tap'),
                  ),
                  PlutoMenuItem(
                    title: 'Menu 6-1-1-2',
                    onTap: () => message(context, 'Menu 6-1-1-2 tap'),
                  ),
                ],
              ),
              PlutoMenuItem(
                title: 'Menu 6-1-2',
                onTap: () => message(context, 'Menu 6-1-2 tap'),
              ),
            ],
          ),
          PlutoMenuItem(
            title: 'Menu 6-2',
            onTap: () => message(context, 'Menu 6-2 tap'),
          ),
        ],
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: [
          const SizedBox(height: 30),
          const Text('Hover-open Menu', style: TextStyle(fontSize: 30)),
          const Text('Works normally in an environment with a mouse.'),
          const SizedBox(height: 30),
          PlutoMenuBar(
            mode: PlutoMenuBarMode.hover,
            menus: whiteHoverMenus,
          ),
          const SizedBox(height: 30),
          PlutoMenuBar(
            mode: PlutoMenuBarMode.hover,
            backgroundColor: Colors.deepOrange,
            itemStyle: const PlutoMenuItemStyle(
              activatedColor: Colors.white,
              indicatorColor: Colors.deepOrange,
              textStyle: TextStyle(color: Colors.white),
              iconColor: Colors.white,
              moreIconColor: Colors.white,
            ),
            menus: orangeHoverMenus,
          ),
          const SizedBox(height: 30),
          const Text('Tap-open Menu', style: TextStyle(fontSize: 30)),
          const SizedBox(height: 30),
          PlutoMenuBar(
            mode: PlutoMenuBarMode.tap,
            menus: whiteTapMenus,
          ),
          const SizedBox(height: 30),
          PlutoMenuBar(
            backgroundColor: Colors.deepOrange,
            itemStyle: const PlutoMenuItemStyle(
              activatedColor: Colors.white,
              indicatorColor: Colors.deepOrange,
              textStyle: TextStyle(color: Colors.white),
              iconColor: Colors.white,
              moreIconColor: Colors.white,
            ),
            menus: orangeTapMenus,
          ),
          const SizedBox(height: 30),
          const Text('Selected top menu', style: TextStyle(fontSize: 30)),
          const SizedBox(height: 30),
          PlutoMenuBar(
            mode: PlutoMenuBarMode.tap,
            itemStyle: const PlutoMenuItemStyle(
              enableSelectedTopMenu: true,
            ),
            menus: [
              PlutoMenuItem(
                title: 'Select1',
                id: 'Select1',
                onTap: () => message(context, 'Select1'),
              ),
              PlutoMenuItem(
                title: 'Select2',
                id: 'Select2',
                onTap: () => message(context, 'Select2'),
              ),
              PlutoMenuItem(
                title: 'Select3',
                id: 'Select3',
                onTap: () => message(context, 'Select3'),
              ),
              PlutoMenuItem(
                title: 'Select4',
                id: 'Select4',
                onTap: () => message(context, 'Select4'),
              ),
              PlutoMenuItem(
                title: 'Select5',
                id: 'Select5',
                onTap: () => message(context, 'Select5'),
              ),
            ],
          ),
          const SizedBox(height: 30),
          const Text('Toggled top menu', style: TextStyle(fontSize: 30)),
          const SizedBox(height: 30),
          PlutoMenuBar(
            mode: PlutoMenuBarMode.tap,
            itemStyle: PlutoMenuItemStyle(
              enableSelectedTopMenu: true,
              selectedTopMenuResolver: (menu, enabled) {
                final description = enabled == true ? 'disabled' : 'enabled';
                message(context, '${menu.title} $description');
                return enabled == true ? null : true;
              },
            ),
            menus: [
              PlutoMenuItem(
                title: 'Toggle1',
                id: 'Toggle1',
              ),
              PlutoMenuItem(
                title: 'Toggle2',
                id: 'Toggle2',
              ),
              PlutoMenuItem(
                title: 'Toggle3',
                id: 'Toggle3',
              ),
              PlutoMenuItem(
                title: 'Toggle4',
                id: 'Toggle4',
              ),
              PlutoMenuItem(
                title: 'Toggle5',
                id: 'Toggle5',
              ),
            ],
          ),
          const SizedBox(height: 50),
        ],
      ),
    );
  }
}

enum _RadioItems {
  one,
  two,
  three,
}

Pluto series

develop packages that make it easy to develop admin pages or CMS with Flutter.


Donate to this project

Buy me a coffee


Jetbrains provides a free license

IDE license support

pluto_menu_bar's People

Contributors

avmakesh avatar bosskmk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pluto_menu_bar's Issues

Widget title

Hello,

What can't we set the title ?I don't want to show "_divider" when I use PlutoMenuItemDivider... I want to show MY title...

PlutoMenuItemDivider({
this.height = 16.0,
this.color,
this.indent,
this.endIndent,
this.thickness,
}) : super(title: '_divider', enable: false);

Cannot disable menu item

I didn't notice any difference when "enable" true or false. In both cases, the appearance of the menu is the same and it works. I expected to see the disabled menu item when enable is false.

PlutoMenuItem(title: 'Help', children: [
        PlutoMenuItem(
          title:  'Tutorial',
          onTap: () => message(context, 'Tutorial'),
          **enable**: true,
        ),        
      ])

3.0.1 breaks flutter apps < 3.7

Changes made for the last version break the compatibility with apps built for flutter version prior to 3.7.

So if you're building with a flutter version which is not the latest, you need to add:

pluto_menu_bar: <3.0.1

I want to add to drawer

Hi thanks for this amazing package , ı want to add drawer this package. I couldn't find any information about vertical usage.

Custom Widgets in PlutoMenuItem

Is there a particular reason the API doesn't allow arbitrary widgets in PlutoMenuItems? Judging from a quick look through the source code, it doesn't look like it should be a problem, and it would increase the flexibility by a lot.

The reason for this ticket is that I need a text field and a slider in my menu.

Is there a way to show different menus based on flag variable?

So I want this menu to show on my pluto grid when enableEditingMode is true:

image

And this one when the variable is false:

image

The buttons on the images toggles my view state variable enableEditingMode between true/false and then rebuild the ui with this values, which should show different menus each time the button is clicked. The issue might be related that this are separate widgets. Has anyone done something similar?

Center Menu Item

Is it possible to center all the menu ?
i tried wrap PlutoMenuBar with Center or Align, but not work

How to close sub menu?

On Android mobile, I can click to open sub menu, but click again doesn't close the sub menu. How should they be closed?

allow changing PlutoMenuItem.childreen after PlutoMenuItem is inserted.

I'm making a routine to create items dynamically. In this situation, I need to go back into a PlutoMenuItem and change PlutoMenuItem.childreen.

ID - TITLE
00001 - MENU1
00002 - MENU 2
0000200001 - MENU 2-1
0000200002 - MENU 2.2
000020000200001 - MENU 2.2.1
0000200003 - MENU 2.3
00003

Thank you for your attention.

issues when click child menu

ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
#0 Element._debugCheckStateIsActiveForAncestorLookup.
package:flutter/…/widgets/framework.dart:4001
#1 Element._debugCheckStateIsActiveForAncestorLookup
package:flutter/…/widgets/framework.dart:4015
#2 Element.findAncestorStateOfType
package:flutter/…/widgets/framework.dart:4062

malfunction after hidekeyboard

We hide the keyboard by using:
FocusScope.of(context).requestFocus(FocusNode());

After that,
the child menu item could not be shown

Icon position

I would like to put the icon at right of the title, not only the left

Desktop style

Can you realize the desktop style, where a submenu is opened nearby the parent menu ?

Enhancement - TextStyles

I use pluto_menu_bar above pluto_grid and it has a very nice look. Would it be possible to add some properties so that we could change the fontsize and color of selected grid items. I'm using only the top level of the menu and whichever they select, I have pluto_grid refreshing to that choice. I would like to change the selected menu option to indicate that the grid is showing that option by changing the color, maybe size and weight also. Right now, I have a separate Text widget that is redundantly stating which menu option is selected.

It's more a space conservation issue, so using pluto_grid's ability for column grouping also uses valuable space. Plus, it would look cleaner with the menu changing state on selection.

Side effect when displaying menu, after creating menus dynamically.

Hello, congratulations on the package.

I'm making a routine to create menu items dynamically. Reading json from an api. In this situation, I need to create the children of each item with an empty list []. So that, according to the json, I return to item and add an item to the children's list.

Doing it this way, the menu is displayed, but after the 2nd sub-menu the initial position is lost, with the items overlapping the previous menu, instead appearing after the menu arrow.

Thank you for your attention.

Example of api data

ID - TITLE
00001 - MENU1
00002 - MENU 2
0000200001 - MENU 2-1
0000200002 - MENU 2.2
000020000200001 - MENU 2.2.1
00002000020000100001 - MENU 2.2.1.1
0000200003 - MENU 2.3
00003

my code

`List carregarMenu(List departamentos) {
var menu = [];
var menuDepartamento = [];
var lista = [];

var grau = -1;

for (var i = 0; i < departamentos.length; i++) {
  if (i == 0) {
    grau = departamentos[i].grau;
  }

  if (grau != departamentos[i].grau) {
    if (departamentos[i - 1].grau == 0) {
      menuDepartamento.addAll(lista);
    } else {
      var nivelPai = departamentos[i - 1]
          .nivel
          .substring(0, departamentos[i - 1].nivel.length - 5);
      if (departamentos[i - 1].grau == 0) {
        var retornoPai = menuDepartamento.indexWhere(
          (element) =>
              (element.id as MenuDepartamentoModel).nivel ==
              nivelPai.substring(0, 5),
        );

        menuDepartamento[retornoPai].children!.addAll(lista);
      } else if (departamentos[i - 1].grau == 1) {
        var retornoPai = menuDepartamento.indexWhere(
          (element) =>
              (element.id as MenuDepartamentoModel).nivel ==
              nivelPai.substring(0, 5),
        );

        menuDepartamento[retornoPai].children!.addAll(lista);
      } else if (departamentos[i - 1].grau == 2) {
        var retornoPai = menuDepartamento.indexWhere(
          (element) =>
              (element.id as MenuDepartamentoModel).nivel ==
              nivelPai.substring(0, 5),
        );

        var retorno1 = menuDepartamento[retornoPai].children!.indexWhere(
              (element) =>
                  (element.id as MenuDepartamentoModel).nivel ==
                  nivelPai.substring(0, 10),
            );

        menuDepartamento[retornoPai]
            .children![retorno1]
            .children!
            .addAll(lista);
      }
    }
    lista = [];
    grau = departamentos[i].grau;
  }
  lista.add(adicionarMenu(departamentos[i]));
}
menu.add(
  PlutoMenuItem(
    title: 'DEPARTAMENTOS',
    icon: Icons.home,
    children: menuDepartamento,
  ),
);


return menu;

}
`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.