| // Copyright 2014 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'package:flutter/material.dart'; | |
| /// Flutter code sample for [Flow]. | |
| void main() => runApp(const FlowApp()); | |
| class FlowApp extends StatelessWidget { | |
| const FlowApp({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| home: Scaffold( | |
| appBar: AppBar(title: const Text('Flow Example')), | |
| body: const FlowMenu(), | |
| ), | |
| ); | |
| } | |
| } | |
| class FlowMenu extends StatefulWidget { | |
| const FlowMenu({super.key}); | |
| @override | |
| State<FlowMenu> createState() => _FlowMenuState(); | |
| } | |
| class _FlowMenuState extends State<FlowMenu> | |
| 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, | |
| ]; | |
| 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, | |
| ); | |
| } | |
| Widget flowMenuItem(IconData icon) { | |
| final double buttonDiameter = | |
| MediaQuery.widthOf(context) / menuItems.length; | |
| return Padding( | |
| padding: const .symmetric(vertical: 8.0), | |
| child: RawMaterialButton( | |
| fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue, | |
| splashColor: Colors.amber[100], | |
| shape: const CircleBorder(), | |
| constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)), | |
| onPressed: () { | |
| _updateMenu(icon); | |
| menuAnimation.status == AnimationStatus.completed | |
| ? menuAnimation.reverse() | |
| : menuAnimation.forward(); | |
| }, | |
| child: Icon(icon, color: Colors.white, size: 45.0), | |
| ), | |
| ); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Flow( | |
| delegate: FlowMenuDelegate(menuAnimation: menuAnimation), | |
| children: menuItems | |
| .map<Widget>((IconData icon) => flowMenuItem(icon)) | |
| .toList(), | |
| ); | |
| } | |
| } | |
| 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), | |
| ); | |
| } | |
| } | |
| } |