Create an Animated Radial Menu in Flutter

In this tutorial, we will create an animated radial menu in Flutter using the provided code. The radial menu will consist of several options arranged in a circular pattern, and when the user taps on the menu button, the options will animate into view. 

Let's get started!

Animated Radial Menu


Folder Structure

To keep our project organized, let's create a folder structure as follows:

- lib
    - screens
        - radial_menu_screen.dart
    - controllers
        - radial_menu_controller.dart
    - main.dart

Implementation

First, let's create the `radial_menu_controller.dart` file inside the `controllers` folder. This controller class will handle the opening and closing of the radial menu.

import 'package:flutter/material.dart';

class RadialMenuController {
  late ValueChanged<bool> onStateChanged;
  bool _opened = false;

  bool get opened => _opened;

  void open() {
    _opened = true;
    onStateChanged(true);
  }

  void close() {
    _opened = false;
    onStateChanged(false);
  }
}

Finally, let's update the `main.dart` file to include the `RadialMenuScreen` as the home screen of our app.

import 'package:flutter/material.dart';
import '../controllers/radial_menu_controller.dart';

class RadialMenuScreen extends StatefulWidget {
  const RadialMenuScreen({Key? key}) : super(key: key);

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

class _RadialMenuScreenState extends State<RadialMenuScreen> {
  late RadialMenuController controller;

  @override
  void initState() {
    super.initState();
    controller = RadialMenuController();
    controller.onStateChanged = (bool opened) {
      setState(() {});
    };
  }

  Widget _buildOption(Icon icon, Color iconColor) {
    return AnimatedSwitcher(
      duration: const Duration(milliseconds: 500),
      transitionBuilder: (Widget child, Animation<double> animation) {
        return RotationTransition(turns: animation, child: child);
      },
      child: InkWell(
        key: UniqueKey(),
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Container(
            height: 50.0,
            width: 50.0,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(25.0),
              color: iconColor,
            ),
            child: Center(child: icon),
          ),
        ),
        onTap: () {},
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Scaffold(
        body: Stack(
          children: <Widget>[
            // App Bar
            Positioned(
              top: 0,
              left: 0,
              right: 0,
              child: AppBar(
                backgroundColor: Colors.orange,
                centerTitle: true,
                leading: InkWell(
                  onTap: () {
                    Navigator.pop(context);
                  },
                  child: const Icon(
                    Icons.chevron_left,
                    size: 22,
                  ),
                ),
                elevation: 0,
                title: const Text('Radial Menu'),
              ),
            ),
            // Menu Options
            AnimatedPositioned(
              duration: const Duration(milliseconds: 300),
              left: controller.opened
                  ? MediaQuery.of(context).size.width / 2 - 40.0
                  : MediaQuery.of(context).size.width / 2 - 150.0,
              top: (MediaQuery.of(context).size.height / 2) - 30,
              child: _buildOption(
                const Icon(Icons.mail_outline, color: Colors.white),
                Colors.purple,
              ),
            ),
            // Add more AnimatedPositioned widgets for other menu options

            // Menu Button
            Align(
              alignment: Alignment.center,
              child: AnimatedSwitcher(
                duration: const Duration(milliseconds: 200),
                transitionBuilder: (Widget child, Animation<double> animation) {
                  return ScaleTransition(scale: animation, child: child);
                },
                child: controller.opened
                    ? InkWell(
                        key: UniqueKey(),
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Container(
                            height: 80.0,
                            width: 80.0,
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(40.0),
                              color: Colors.orange,
                            ),
                            child: const Center(
                              child: Icon(Icons.share, color: Colors.white),
                            ),
                          ),
                        ),
                        onTap: () {
                          controller.close();
                        },
                      )
                    : InkWell(
                        key: UniqueKey(),
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Container(
                            height: 80.0,
                            width: 80.0,
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(40.0),
                              color: Colors.red,
                            ),
                            child: const Center(
                              child: Icon(Icons.close, color: Colors.white),
                            ),
                          ),
                        ),
                        onTap: () {
                          controller.open();
                        },
                      ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

That's it! You have successfully created an animated radial menu in Flutter. Run the app to see the menu in action.

Feel free to customize the menu options and the appearance to fit your needs. 

follow-me-linkedin

Happy coding!

Comments

Popular posts from this blog

Error Handling in Flutter - Gradle issue

How to Make a Dynamic and Trending ListView with Flutter Widgets?

Understanding API integration with Getx State management