How to place widgets around a circle using flutter?

1,114

If you're trying a circular menu you can follow this :

  1. Add vector_math: ^2.0.8 and font_awesome_flutter: 8.4.0 to pubspec.yaml

  2. Here is the full source of the example :

import 'package:flutter/material.dart';
import 'dart:math';
import 'package:vector_math/vector_math.dart' show radians, Vector3;
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'FlutterBase',
        home: Scaffold(
            body: SizedBox.expand(child: RadialMenu()) 
        )
    );
  }
}
class RadialMenu extends StatefulWidget {
  createState() => _RadialMenuState();
}
class _RadialMenuState extends State<RadialMenu> with SingleTickerProviderStateMixin {
  AnimationController controller;
  @override
  void initState() {
    super.initState();
    controller = AnimationController(duration: Duration(milliseconds: 900), vsync: this);
                  // ..addListener(() => setState(() {}));
  }
  @override
  Widget build(BuildContext context) {
    return RadialAnimation(controller: controller);
  }
  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}
class RadialAnimation extends StatelessWidget {
    RadialAnimation({ Key key, this.controller }) :
    translation = Tween<double>(
      begin: 0.0,
      end: 100.0,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Curves.elasticOut
      ),
    ),
    scale = Tween<double>(
      begin: 1.5,
      end: 0.0,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Curves.fastOutSlowIn
      ),
    ),
    rotation = Tween<double>(
      begin: 0.0,
      end: 360.0,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Interval(
          0.0, 0.7,
          curve: Curves.decelerate,
        ),
      ),
    ),
  super(key: key);
  final AnimationController controller;
  final Animation<double> rotation;
  final Animation<double> translation;
  final Animation<double> scale;
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: (context, widget) { 
        return Transform.rotate(
          angle: radians(rotation.value),
          child: Stack(
          alignment: Alignment.center,
          children: <Widget>[
            _buildButton(0, color: Colors.red, icon: FontAwesomeIcons.thumbtack),
            _buildButton(45, color: Colors.green, icon:FontAwesomeIcons.sprayCan),
            _buildButton(90, color: Colors.orange, icon: FontAwesomeIcons.fire),
            _buildButton(135, color: Colors.blue, icon:FontAwesomeIcons.kiwiBird),
            _buildButton(180, color: Colors.black, icon:FontAwesomeIcons.cat),
            _buildButton(225, color: Colors.indigo, icon:FontAwesomeIcons.paw),
            _buildButton(270, color: Colors.pink, icon: FontAwesomeIcons.bong),
            _buildButton(315, color: Colors.yellow, icon:FontAwesomeIcons.bolt),
            Transform.scale(
              scale: scale.value - 1,
              child: FloatingActionButton(child: Icon(FontAwesomeIcons.timesCircle), onPressed: _close, backgroundColor: Colors.red),
            ),
            Transform.scale(
              scale: scale.value,
              child: FloatingActionButton(child: Icon(FontAwesomeIcons.solidDotCircle), onPressed: _open),
            )
        ])
      );
    });
  }
  _open() {
    controller.forward();
  }
  _close() {
    controller.reverse();
  }
  _buildButton(double angle, { Color color, IconData icon }) {
    final double rad = radians(angle);
    return Transform(
      transform: Matrix4.identity()..translate(
        (translation.value) * cos(rad), 
        (translation.value) * sin(rad)
      ),
      child: FloatingActionButton(
        child: Icon(icon), backgroundColor: color, onPressed: _close, elevation: 0)
    );
  }
}
Share:
1,114
Author by

Francesco

Updated on December 13, 2022

Comments

  • Francesco 29 days

    I'm new in flutter, I need to create an interface like this

    I've created a circular button in this way:

     @override
      Widget build(BuildContext context) {
        return GestureDetector(
          onTap: () => _buttonCallBack(),
          child: ClipOval(
            child: FractionallySizedBox(
                heightFactor : 0.4,
                widthFactor : 0.6,
                child : Container(
                    color: Colors.lightGreen,
                    child : Center(
                        child: Text(
                            "Start",
                            style: new TextStyle(fontSize: 36.0),
                        )
                    )
                )
            ),
          ),
        );
    

    But now I don't how to show buttons around the circle. Anyone has any ideas ?

  • Zahra over 1 year
    This is a very nice answer.
  • Alejandro
    Alejandro over 1 year
    It would also be useful to isolate this to a circular layout widget and re-use it. Nice job!