首页 > 解决方案 > Flutter, Flow inside Align 不响应对齐规则

问题描述

我正在尝试使用 Flutter 的 Flow 小部件,与屏幕右上角对齐,并向左平移。我尝试使用 Stack + Positioned,我尝试使用 Container + Align。Flow 总是停留在左上角。这是我正在努力的代码;

/// 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,
        ),
      );
    }
  }
}


结果屏幕是;

在此处输入图像描述

你能帮我把流量调整到右上角吗?非常感谢您阅读或回复。

附言。它说我不允许创建标签。所以这里有一个未来的列表:Flow Widget、Align Widget、Flutter

编辑

我想要达到的目标:

  1. 和 2. GIFs 被实现。最后一个显示了我如何未能将其与右侧对齐。

不是这个,

不是这个,

不工作

标签: flutteralignmentflow

解决方案


似乎问题在于包装 RawMaterialButton 小部件的 Padding 小部件。所以我用Align替换了它,并且还稍微调整了你的动画工作代码如下

/// 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,
        ),
      );
    }
  }
}

解决方案 gif


推荐阅读