├── LICENSE
├── CHANGELOG.md
├── gif
├── menu_1.gif
└── menu_2.gif
├── .gitignore
├── lib
├── floating_menu_item.dart
├── floating_menu_callback.dart
└── flutter_expandable_menu.dart
├── .metadata
├── flutter_expandable_menu.iml
├── pubspec.yaml
├── pubspec.lock
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | TODO: Add your license here.
2 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [0.0.1] - TODO: Add release date.
2 |
3 | * TODO: Describe initial release.
4 |
--------------------------------------------------------------------------------
/gif/menu_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UttamPanchasara/FlutterExpandableMenu/HEAD/gif/menu_1.gif
--------------------------------------------------------------------------------
/gif/menu_2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UttamPanchasara/FlutterExpandableMenu/HEAD/gif/menu_2.gif
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 | ios/.generated/
9 | ios/Flutter/Generated.xcconfig
10 | ios/Runner/GeneratedPluginRegistrant.*
11 |
--------------------------------------------------------------------------------
/lib/floating_menu_item.dart:
--------------------------------------------------------------------------------
1 | class FloatingMenuItem {
2 | final icon;
3 | final id;
4 | final backgroundColor;
5 |
6 | FloatingMenuItem({this.id, this.icon, this.backgroundColor});
7 | }
8 |
--------------------------------------------------------------------------------
/lib/floating_menu_callback.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_expandable_menu/floating_menu_item.dart';
2 |
3 | class FloatingMenuCallback {
4 | void onMenuClick(FloatingMenuItem floatingMenuItem) {}
5 | }
6 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713
8 | channel: stable
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/flutter_expandable_menu.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_expandable_menu
2 | description: A new Flutter package.
3 | version: 0.0.1
4 | author: Uttam Panchasara
5 | homepage: https://github.com/UttamPanchasara/FlutterExpandableMenu
6 |
7 | environment:
8 | sdk: ">=2.1.0 <3.0.0"
9 |
10 | dependencies:
11 | flutter:
12 | sdk: flutter
13 |
14 | dev_dependencies:
15 | flutter_test:
16 | sdk: flutter
17 |
18 | # For information on the generic Dart part of this file, see the
19 | # following page: https://www.dartlang.org/tools/pub/pubspec
20 |
21 | # The following section is specific to Flutter.
22 | flutter:
23 |
24 | # To add assets to your package, add an assets section, like this:
25 | # assets:
26 | # - images/a_dot_burr.jpeg
27 | # - images/a_dot_ham.jpeg
28 | #
29 | # For details regarding assets in packages, see
30 | # https://flutter.io/assets-and-images/#from-packages
31 | #
32 | # An image asset can refer to one or more resolution-specific "variants", see
33 | # https://flutter.io/assets-and-images/#resolution-aware.
34 |
35 | # To add custom fonts to your package, add a fonts section here,
36 | # in this "flutter" section. Each entry in this list should have a
37 | # "family" key with the font family name, and a "fonts" key with a
38 | # list giving the asset and other descriptors for the font. For
39 | # example:
40 | # fonts:
41 | # - family: Schyler
42 | # fonts:
43 | # - asset: fonts/Schyler-Regular.ttf
44 | # - asset: fonts/Schyler-Italic.ttf
45 | # style: italic
46 | # - family: Trajan Pro
47 | # fonts:
48 | # - asset: fonts/TrajanPro.ttf
49 | # - asset: fonts/TrajanPro_Bold.ttf
50 | # weight: 700
51 | #
52 | # For details regarding fonts in packages, see
53 | # https://flutter.io/custom-fonts/#from-packages
54 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "2.0.8"
11 | boolean_selector:
12 | dependency: transitive
13 | description:
14 | name: boolean_selector
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "1.0.4"
18 | charcode:
19 | dependency: transitive
20 | description:
21 | name: charcode
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "1.1.2"
25 | collection:
26 | dependency: transitive
27 | description:
28 | name: collection
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.14.11"
32 | flutter:
33 | dependency: "direct main"
34 | description: flutter
35 | source: sdk
36 | version: "0.0.0"
37 | flutter_test:
38 | dependency: "direct dev"
39 | description: flutter
40 | source: sdk
41 | version: "0.0.0"
42 | matcher:
43 | dependency: transitive
44 | description:
45 | name: matcher
46 | url: "https://pub.dartlang.org"
47 | source: hosted
48 | version: "0.12.3+1"
49 | meta:
50 | dependency: transitive
51 | description:
52 | name: meta
53 | url: "https://pub.dartlang.org"
54 | source: hosted
55 | version: "1.1.6"
56 | path:
57 | dependency: transitive
58 | description:
59 | name: path
60 | url: "https://pub.dartlang.org"
61 | source: hosted
62 | version: "1.6.2"
63 | pedantic:
64 | dependency: transitive
65 | description:
66 | name: pedantic
67 | url: "https://pub.dartlang.org"
68 | source: hosted
69 | version: "1.4.0"
70 | quiver:
71 | dependency: transitive
72 | description:
73 | name: quiver
74 | url: "https://pub.dartlang.org"
75 | source: hosted
76 | version: "2.0.1"
77 | sky_engine:
78 | dependency: transitive
79 | description: flutter
80 | source: sdk
81 | version: "0.0.99"
82 | source_span:
83 | dependency: transitive
84 | description:
85 | name: source_span
86 | url: "https://pub.dartlang.org"
87 | source: hosted
88 | version: "1.5.4"
89 | stack_trace:
90 | dependency: transitive
91 | description:
92 | name: stack_trace
93 | url: "https://pub.dartlang.org"
94 | source: hosted
95 | version: "1.9.3"
96 | stream_channel:
97 | dependency: transitive
98 | description:
99 | name: stream_channel
100 | url: "https://pub.dartlang.org"
101 | source: hosted
102 | version: "1.6.8"
103 | string_scanner:
104 | dependency: transitive
105 | description:
106 | name: string_scanner
107 | url: "https://pub.dartlang.org"
108 | source: hosted
109 | version: "1.0.4"
110 | term_glyph:
111 | dependency: transitive
112 | description:
113 | name: term_glyph
114 | url: "https://pub.dartlang.org"
115 | source: hosted
116 | version: "1.1.0"
117 | test_api:
118 | dependency: transitive
119 | description:
120 | name: test_api
121 | url: "https://pub.dartlang.org"
122 | source: hosted
123 | version: "0.2.2"
124 | typed_data:
125 | dependency: transitive
126 | description:
127 | name: typed_data
128 | url: "https://pub.dartlang.org"
129 | source: hosted
130 | version: "1.1.6"
131 | vector_math:
132 | dependency: transitive
133 | description:
134 | name: vector_math
135 | url: "https://pub.dartlang.org"
136 | source: hosted
137 | version: "2.0.8"
138 | sdks:
139 | dart: ">=2.1.0 <3.0.0"
140 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # flutter_expandable_menu
2 | [](https://pub.dartlang.org/packages/flutter_expandable_menu)
3 |
4 | A new Flutter package which helps developers in creating Expandable Menu.
5 |
6 | ## Getting Started
7 | | With Dark Background | Transparent Background |
8 | |-----------------------------------------|------------------------------------------|
9 | |
|
|
10 |
11 | ## Usage
12 |
13 | [Example](https://github.com/UttamPanchasara/FlutterExamples)
14 |
15 | To use this package :
16 |
17 | * add the dependency to your [pubspec.yaml](https://github.com/UttamPanchasara/FlutterExpandableMenu/blob/master/pubspec.yaml) file.
18 |
19 | ```yaml
20 | dependencies:
21 | flutter:
22 | sdk: flutter
23 | flutter_expandable_menu: ^0.0.1
24 | ```
25 |
26 | ## Quick Start:
27 | In order to use Expandable Menu Widget in your Application you will have to **Put this widget inside the Stack Widget** as below.
28 |
29 | ```dart
30 |
31 | Stack(
32 | children: [
33 | Center(
34 | child: Text(
35 | centerText,
36 | style: TextStyle(color: Colors.black),
37 | ),
38 | ),
39 | FlutterExpandableMenu(
40 | menuList: floatMenuList,
41 | callback: this,
42 | backgroundColor: Colors.transparent,
43 | menuBackgroundColor: Colors.black,
44 | menuIcon: AnimatedIcons.menu_close,
45 | menuAlignment: Alignment.center,
46 | outerTransitionDuration: Duration(milliseconds: 300),
47 | menusTransitionDuration: Duration(milliseconds: 500),
48 | menusTransitionDelay: Duration(milliseconds: 200),
49 | ),
50 | ],
51 | )
52 |
53 | ```
54 |
55 | ## Example - How to use:
56 |
57 | ```dart
58 |
59 | class _RoundMenuState extends State
60 | with TickerProviderStateMixin
61 | implements FloatingMenuCallback {
62 | String centerText = "Home";
63 |
64 | final List floatMenuList = [
65 | FloatingMenuItem(
66 | id: 1, icon: Icons.favorite, backgroundColor: Colors.deepOrangeAccent),
67 | FloatingMenuItem(id: 2, icon: Icons.map, backgroundColor: Colors.brown),
68 | FloatingMenuItem(id: 3, icon: Icons.email, backgroundColor: Colors.indigo),
69 | FloatingMenuItem(id: 4, icon: Icons.event, backgroundColor: Colors.pink),
70 | FloatingMenuItem(id: 5, icon: Icons.print, backgroundColor: Colors.green),
71 | FloatingMenuItem(
72 | id: 6, icon: Icons.home, backgroundColor: Colors.deepPurple),
73 | FloatingMenuItem(
74 | id: 7, icon: Icons.location_on, backgroundColor: Colors.blueAccent),
75 | ];
76 |
77 | @override
78 | Widget build(BuildContext context) {
79 | return Scaffold(
80 | appBar: AppBar(
81 | title: Text('Round Menu'),
82 | leading: new IconButton(
83 | icon: new Icon(Icons.arrow_back, color: Colors.black),
84 | onPressed: () => Navigator.of(context).pop(),
85 | ),
86 | ),
87 | body: Stack(
88 | children: [
89 | Center(
90 | child: Text(
91 | centerText,
92 | style: TextStyle(color: Colors.black),
93 | ),
94 | ),
95 | FlutterExpandableMenu(
96 | menuList: floatMenuList,
97 | callback: this,
98 | backgroundColor: Colors.transparent,
99 | menuBackgroundColor: Colors.black,
100 | menuIcon: AnimatedIcons.menu_close,
101 | menuAlignment: Alignment.center,
102 | outerTransitionDuration: Duration(milliseconds: 300),
103 | menusTransitionDuration: Duration(milliseconds: 500),
104 | menusTransitionDelay: Duration(milliseconds: 200),
105 | ),
106 | ],
107 | ),
108 | );
109 | }
110 |
111 | @override
112 | void onMenuClick(FloatingMenuItem floatingMenuItem) {
113 | if (floatingMenuItem != null) {
114 | print("onMenuClicked : " + floatingMenuItem.id.toString());
115 | switch (floatingMenuItem.id) {
116 | case 1:
117 | {
118 | centerText = "Favorite";
119 | }
120 | break;
121 | case 2:
122 | {
123 | centerText = "Map";
124 | }
125 | break;
126 | case 3:
127 | {
128 | centerText = "Email";
129 | }
130 | break;
131 | case 4:
132 | {
133 | centerText = "Event";
134 | }
135 | break;
136 | case 5:
137 | {
138 | centerText = "Print";
139 | }
140 | break;
141 | case 6:
142 | {
143 | centerText = "Home";
144 | }
145 | break;
146 | case 7:
147 | {
148 | centerText = "Location";
149 | }
150 | break;
151 | }
152 |
153 | setState(() {});
154 | }
155 | }
156 | }
157 |
158 | ```
159 |
160 | ## Questions?
161 |
162 | **Ping-Me on :** [](https://twitter.com/UTM_Panchasara)
163 | [](https://www.facebook.com/UttamPanchasara94)
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | ## Donate
172 | > If you found this package helpful or you learned something from the source code and want to thank me, consider buying me a cup of :coffee:
173 | - Paypal **https://paypal.me/UttamPanchasara**
174 |
175 |
176 | ## License
177 |
178 | ```
179 | Copyright 2019 Uttam Panchasara
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
192 | ```
193 |
194 |
--------------------------------------------------------------------------------
/lib/flutter_expandable_menu.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_expandable_menu/floating_menu_callback.dart';
3 | import 'package:flutter_expandable_menu/floating_menu_item.dart';
4 |
5 | class FlutterExpandableMenu extends StatefulWidget {
6 | final List menuList;
7 | final AnimatedIconData menuIcon;
8 | final Color backgroundColor;
9 | final Color menuBackgroundColor;
10 | final Duration outerTransitionDuration;
11 | final Duration menusTransitionDuration;
12 | final Duration menusTransitionDelay;
13 | final FloatingMenuCallback callback;
14 | final Alignment menuAlignment;
15 |
16 | const FlutterExpandableMenu(
17 | {Key key,
18 | @required this.menuList,
19 | this.menuIcon,
20 | this.backgroundColor,
21 | this.menuBackgroundColor,
22 | this.outerTransitionDuration,
23 | this.menusTransitionDuration,
24 | this.menusTransitionDelay,
25 | this.menuAlignment,
26 | @required this.callback})
27 | : super(key: key);
28 |
29 | @override
30 | _FlutterExpandableMenuState createState() => _FlutterExpandableMenuState();
31 | }
32 |
33 | class _FlutterExpandableMenuState extends State
34 | with TickerProviderStateMixin {
35 | bool isMenuClicked = false;
36 | var maxItemCount = 7;
37 |
38 | FloatingMenuItem selectedMenuItem;
39 |
40 | var myHeight = 0.0;
41 | var myWidth = 0.0;
42 |
43 | AnimationController controller;
44 |
45 | Animation offsetTop;
46 | Animation offsetTopRight;
47 | Animation offsetBottomRight;
48 | Animation offsetBottom;
49 | Animation offsetBottomLeft;
50 | Animation offsetTopLeft;
51 | Animation _animateIcon;
52 | Animation _animateMenu;
53 |
54 | @override
55 | void initState() {
56 | super.initState();
57 | if (widget.menuList.length == maxItemCount) {
58 | controller = AnimationController(
59 | vsync: this,
60 | duration: widget.menusTransitionDuration != null
61 | ? widget.menusTransitionDuration
62 | : Duration(milliseconds: 150));
63 |
64 | _animateIcon = Tween(begin: 0.0, end: 1.0).animate(controller);
65 | _animateMenu = CurvedAnimation(parent: controller, curve: Curves.easeIn);
66 |
67 | initOffsetValues();
68 | }
69 | }
70 |
71 | void initOffsetValues() {
72 | var curve = Curves.linear;
73 | var top = FractionalOffset(
74 | FractionalOffset.topCenter.x, FractionalOffset.topCenter.y)
75 | .alongSize(Size.fromRadius(0.15));
76 |
77 | offsetTop = Tween(begin: Offset.zero, end: Offset(top.dx, top.dy))
78 | .animate(CurvedAnimation(parent: controller, curve: curve));
79 |
80 | var topRight = FractionalOffset(
81 | FractionalOffset.topRight.x, FractionalOffset.topRight.y)
82 | .alongSize(Size.fromRadius(0.14));
83 |
84 | offsetTopRight = Tween(
85 | begin: Offset.zero,
86 | end: Offset(topRight.dx + 0.05, topRight.dy + 0.15))
87 | .animate(CurvedAnimation(
88 | parent: controller, curve: Interval(0.16, 1.0, curve: curve)));
89 |
90 | var bottomRight = FractionalOffset(
91 | FractionalOffset.bottomRight.x, FractionalOffset.bottomRight.y)
92 | .alongSize(Size.fromRadius(0.14));
93 |
94 | offsetBottomRight = Tween(
95 | begin: Offset.zero,
96 | end: Offset(bottomRight.dx + 0.05, bottomRight.dy - 0.15))
97 | .animate(CurvedAnimation(
98 | parent: controller, curve: Interval(0.32, 1.0, curve: curve)));
99 |
100 | var bottom = FractionalOffset(
101 | FractionalOffset.bottomCenter.x, FractionalOffset.bottomCenter.y)
102 | .alongSize(Size.fromRadius(0.15));
103 |
104 | offsetBottom =
105 | Tween(begin: Offset.zero, end: Offset(bottom.dx, bottom.dy))
106 | .animate(CurvedAnimation(
107 | parent: controller, curve: Interval(0.48, 1.0, curve: curve)));
108 |
109 | var bottomLeft = FractionalOffset(
110 | FractionalOffset.bottomLeft.x, FractionalOffset.bottomLeft.y)
111 | .alongSize(Size.fromRadius(0.14));
112 |
113 | offsetBottomLeft = Tween(
114 | begin: Offset.zero,
115 | end: Offset(bottomLeft.dx - 0.05, bottomLeft.dy - 0.15))
116 | .animate(CurvedAnimation(
117 | parent: controller, curve: Interval(0.54, 1.0, curve: curve)));
118 |
119 | var topLeft =
120 | FractionalOffset(FractionalOffset.topLeft.x, FractionalOffset.topLeft.y)
121 | .alongSize(Size.fromRadius(0.14));
122 |
123 | offsetTopLeft = Tween(
124 | begin: Offset.zero,
125 | end: Offset(topLeft.dx - 0.05, topLeft.dy + 0.15))
126 | .animate(CurvedAnimation(
127 | parent: controller, curve: Interval(0.70, 1.0, curve: curve)));
128 | }
129 |
130 | @override
131 | Widget build(BuildContext context) {
132 | if (widget.menuList.length == maxItemCount) {
133 | return Stack(
134 | children: [
135 | _showMenu(),
136 | Align(
137 | alignment: Alignment.bottomRight,
138 | child: Container(
139 | margin: EdgeInsets.all(16),
140 | child: FloatingActionButton(
141 | onPressed: () {
142 | _changeMenuVisibility();
143 | },
144 | backgroundColor: widget.menuBackgroundColor != null
145 | ? widget.menuBackgroundColor
146 | : Theme.of(context).accentColor,
147 | child: AnimatedIcon(
148 | icon: widget.menuIcon != null
149 | ? widget.menuIcon
150 | : AnimatedIcons.menu_close,
151 | progress: _animateIcon),
152 | ),
153 | ),
154 | ),
155 | ],
156 | );
157 | } else {
158 | throw ("Menu List must have seven(7) items.");
159 | }
160 | }
161 |
162 | void _changeMenuVisibility() {
163 | isMenuClicked = !isMenuClicked;
164 | if (!isMenuClicked) {
165 | controller.addStatusListener((state) {
166 | if (state == AnimationStatus.dismissed) {
167 | setState(() {});
168 | if (selectedMenuItem != null) {
169 | widget.callback.onMenuClick(selectedMenuItem);
170 | }
171 | }
172 | });
173 | controller.reverse();
174 | } else {
175 | setState(() {});
176 | }
177 | }
178 |
179 | void _animate() {
180 | Duration delay = widget.menusTransitionDelay != null
181 | ? widget.menusTransitionDelay
182 | : Duration(milliseconds: 400);
183 |
184 | Future.delayed(delay, () {
185 | controller.forward();
186 | });
187 | }
188 |
189 | Widget _showMenu() {
190 | if (isMenuClicked) {
191 | myWidth = myHeight = MediaQuery.of(context).size.width;
192 | _animate();
193 | } else {
194 | myWidth = myHeight = 0.0;
195 | }
196 | return Align(
197 | alignment: widget.menuAlignment != null
198 | ? widget.menuAlignment
199 | : Alignment.center,
200 | child: AnimatedContainer(
201 | duration: widget.outerTransitionDuration != null
202 | ? widget.outerTransitionDuration
203 | : Duration(milliseconds: 300),
204 | decoration: ShapeDecoration(
205 | shape: RoundedRectangleBorder(
206 | borderRadius: BorderRadius.circular(0),
207 | ),
208 | color: widget.backgroundColor != null
209 | ? widget.backgroundColor
210 | : Colors.black,
211 | ),
212 | width: myWidth == 0 ? 0 : MediaQuery.of(context).size.width,
213 | height: myHeight == 0 ? 0 : MediaQuery.of(context).size.height,
214 | child: Align(
215 | alignment: Alignment.center,
216 | child: AnimatedContainer(
217 | width: myWidth,
218 | height: myHeight,
219 | margin: EdgeInsets.all(30),
220 | duration: Duration(milliseconds: 500),
221 | decoration: ShapeDecoration(
222 | shape: CircleBorder(),
223 | color: widget.backgroundColor != null
224 | ? widget.backgroundColor
225 | : Colors.black,
226 | ),
227 | child: isMenuClicked ? _menuItems() : Container(),
228 | ),
229 | ),
230 | ),
231 | );
232 | }
233 |
234 | Widget _menuItem(int index) {
235 | selectedMenuItem = null;
236 |
237 | var menuItem = widget.menuList[index];
238 | if (menuItem == null) {
239 | return Container();
240 | }
241 | Animation offset;
242 | switch (index) {
243 | case 0:
244 | {
245 | offset = offsetTop;
246 | }
247 | break;
248 | case 1:
249 | {
250 | offset = offsetTopRight;
251 | }
252 | break;
253 | case 2:
254 | {
255 | offset = offsetBottomRight;
256 | }
257 | break;
258 | case 3:
259 | {
260 | offset = offsetBottom;
261 | }
262 | break;
263 | case 4:
264 | {
265 | offset = offsetBottomLeft;
266 | }
267 | break;
268 | case 5:
269 | {
270 | offset = offsetTopLeft;
271 | }
272 | break;
273 | }
274 |
275 | if (index != (maxItemCount - 1)) {
276 | return SlideTransition(
277 | position: offset,
278 | child: Center(
279 | child: FloatingActionButton(
280 | onPressed: () {
281 | selectedMenuItem = menuItem;
282 | _changeMenuVisibility();
283 | },
284 | backgroundColor: menuItem.backgroundColor != null
285 | ? menuItem.backgroundColor
286 | : Theme.of(context).accentColor,
287 | child: Icon(menuItem.icon),
288 | ),
289 | ),
290 | );
291 | } else {
292 | return Center(
293 | child: FloatingActionButton(
294 | onPressed: () {
295 | selectedMenuItem = menuItem;
296 | _changeMenuVisibility();
297 | },
298 | backgroundColor: menuItem.backgroundColor != null
299 | ? menuItem.backgroundColor
300 | : Theme.of(context).accentColor,
301 | child: Icon(menuItem.icon),
302 | ),
303 | );
304 | }
305 | }
306 |
307 | Widget _menuItems() {
308 | return Stack(
309 | children: [
310 | Stack(
311 | children: [
312 | FadeTransition(opacity: _animateMenu, child: _menuItem(0)),
313 | FadeTransition(opacity: _animateMenu, child: _menuItem(1)),
314 | FadeTransition(opacity: _animateMenu, child: _menuItem(2)),
315 | FadeTransition(opacity: _animateMenu, child: _menuItem(3)),
316 | FadeTransition(opacity: _animateMenu, child: _menuItem(4)),
317 | FadeTransition(opacity: _animateMenu, child: _menuItem(5)),
318 | FadeTransition(opacity: _animateMenu, child: _menuItem(6)),
319 | ],
320 | ),
321 | ],
322 | );
323 | }
324 | }
325 |
--------------------------------------------------------------------------------