'Flutter, Flow inside Align does not respond to the alignment rules

I am trying to use the Flow widget of Flutter, aligned to the top-right of the screen, and translating towards left. I tried using Stack + Positioned, I tried using Container + Align. Flow always sticks to the top-left. Here is the code I am struggling with;

/// Flutter code sample for Flow

// This example uses the [Flow] widget to create a menu that opens and closes
// as it is interacted with, shown above. The color of the button in the menu
// changes to indicate which one has been selected.

import 'package:flutter/material.dart';

void main() => runApp(FlowApp());

class FlowApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flow Example'),
        ),
        body: FlowMenu(),
      ),
    );
  }
}

class FlowMenu extends StatefulWidget {
  @override
  _FlowMenuState createState() => _FlowMenuState();
}

class _FlowMenuState extends State<FlowMenu>
    with SingleTickerProviderStateMixin {
  final double buttonDiameter = 40;
  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.of(context).size.width / menuItems.length;

    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 0.0),
      child: RawMaterialButton(
        fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue,
        splashColor: Colors.amber[100],
        shape: 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: buttonDiameter - 10,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: MediaQuery.of(context).size.width,
      decoration: BoxDecoration(color: Colors.green),
      child: Align(
        alignment: Alignment.topRight,
        child: Container(
          constraints: BoxConstraints.tight(
              Size((buttonDiameter) * menuItems.length, buttonDiameter+5)),
          decoration: BoxDecoration(color: Colors.red),
          child: Align( //why this align does not work?
            alignment: Alignment.topRight,
            child: Flow(
              delegate: FlowMenuDelegate(menuAnimation: menuAnimation),
              children: menuItems
                  .map<Widget>((IconData icon) => flowMenuItem(icon))
                  .toList(),
            ),
          ),
        ),
      ),
    );
  }
}

class FlowMenuDelegate extends FlowDelegate {
  FlowMenuDelegate({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,
        ),
      );
    }
  }
}


And the resulting screen is;

enter image description here

Can you help me with aligning flow to the top right? Thank you so much, for reading or responding.

ps. It says I am not allowed to create tags. So here is a list for the future: Flow Widget, Align Widget, Flutter

Edit

What I am trying to achieve:

  1. and 2. gifs are achieved. the last one shows how I failed to align it to the right.

Not this one,

Not this one,

Not working



Solution 1:[1]

It seems the problem is the Padding widget wrapping the RawMaterialButton widget. So I have replaced it with Align, and also tweaked a little your animation Working code as follows

/// Flutter code sample for Flow

// This example uses the [Flow] widget to create a menu that opens and closes
// as it is interacted with, shown above. The color of the button in the menu
// changes to indicate which one has been selected.

import 'package:flutter/material.dart';

void main() => runApp(FlowApp());

class FlowApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flow Example'),
        ),
        body: FlowMenu(),
      ),
    );
  }
}

class FlowMenu extends StatefulWidget {
  @override
  _FlowMenuState createState() => _FlowMenuState();
}

class _FlowMenuState extends State<FlowMenu>
    with SingleTickerProviderStateMixin {
  final double buttonDiameter = 40;
  AnimationController menuAnimation;
  IconData lastTapped = Icons.notifications;
  final List<IconData> menuItems = <IconData>[
    Icons.home,
    Icons.new_releases,
    Icons.notifications,
    Icons.settings,
    Icons.menu,
  ];
//  @override Size getSize(BoxConstraints constraints) => Size(100, 100);
//  @override Size getSize(BoxConstraints constraints) => constraints.biggest / 2;

  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.of(context).size.width / menuItems.length;

    return Container(
      decoration: BoxDecoration(
        color: Colors.white
      ),
      child: Align(
//      padding: const EdgeInsets.symmetric(vertical: 0.0),
        alignment: Alignment.topRight,
        child: RawMaterialButton(
          fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue,
          splashColor: Colors.amber[100],
          shape: 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: buttonDiameter - 10,
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: MediaQuery.of(context).size.width,
      decoration: BoxDecoration(color: Colors.green),
      child: Align(
        alignment: Alignment.topRight,
        child: Container(
          constraints: BoxConstraints.tight(
              Size(buttonDiameter * (menuItems.length+1), buttonDiameter+5)),
          decoration: BoxDecoration(color: Colors.red),
          child: Align(
            alignment: Alignment.topRight,
            child: Flow(
              delegate: FlowMenuDelegate(menuAnimation: menuAnimation),
              children: menuItems
                  .map<Widget>((IconData icon) => flowMenuItem(icon))
                  .toList(),
            ),
          ),
        ),
      ),
    );
  }
}

class FlowMenuDelegate extends FlowDelegate {
  FlowMenuDelegate({this.menuAnimation}) : super(repaint: menuAnimation);

  final Animation<double> menuAnimation;

  @override
  bool shouldRepaint(FlowMenuDelegate oldDelegate) {
    return menuAnimation != oldDelegate.menuAnimation;
  }
//  @override Size getSize(BoxConstraints constraints) => constraints.biggest / 2;


  @override
  void paintChildren(FlowPaintingContext context) {
    double dx = 0.0;
    for (int i = 0; i < context.childCount; ++i) {
      dx = 40.0 * i;
      context.paintChild(
        i,
        transform: Matrix4.translationValues(
          -dx * menuAnimation.value,
          0,
          0,
        ),
      );
    }
  }
}

solution gif

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Slim