是否可以强制对齐 Wrap 小部件中的特定子小部件?

Jam*_*mes 7 flutter flutter-layout

我正在尝试在 flutter 中创建一个布局,由一行与两个子小部件组成,第一个与左侧对齐,第二个与右侧对齐,如果容器太窄,它也会包裹小部件。

这类似于这里提出的问题Flutter aligning two items on Extremes - 一个在左边,一个在右边,这可以Wrapalignment: WrapAlignment.spaceBetween. 但是,当小部件使用此方法包装时,包装到新运行的右侧小部件不再右对齐。(截图

我希望发生的是正确的小部件在包装时保持与右侧对齐。在带有 flexbox 的 css 中,这可以通过右侧小部件上的 flex-grow:1 或 margin-left:auto 实现,如本代码笔所示(调整页面宽度以查看我想要的布局)。

到目前为止,我已经尝试过颤振:

  • 将正确的小部件包装在小Flexible部件中以尝试使其在包装时占据剩余的宽度,因此我可以在其中正确对齐,但这会引发错误:
   Incorrect use of ParentDataWidget.
   Flexible widgets must be placed inside Flex widgets.
Run Code Online (Sandbox Code Playgroud)
  • 将正确的小部件包装在小部件内Align,但这始终会扩展到全宽并导致环绕,即使屏幕足够宽以让两个小部件位于同一行
  • 使用CustomMultiChildLayoutMultiChildLayoutDelegate,它可以创建正确的布局,(截图),然而它似乎并不能够设定根据孩子小部件高度widget的高度,迫使你使用任意的高度值。MultiChildLayoutDelegate文档

覆盖 getSize 以控制布局的整体大小。布局的大小不能依赖于子项的布局属性。

那么是否有可能创建一个布局,当它必须换行时,正确的小部件保持与右边缘对齐?

Jam*_*mes 4

感谢 R\xc3\xa9mi Rousselet\ 使用自定义的建议,RenderBox这里是解决布局问题的基本实现(基于Wrap小部件RenderBox实现1 2

\n\n
import \'package:flutter/widgets.dart\';\nimport \'package:flutter/rendering.dart\';\nimport \'dart:math\' as math;\n\nclass LeftRightAlign extends MultiChildRenderObjectWidget {\n  LeftRightAlign({\n    Key key,\n    @required Widget left,\n    @required Widget right,\n  }) : super(key: key, children: [left, right]);\n\n  @override\n  RenderLeftRightAlign createRenderObject(BuildContext context) {\n    return RenderLeftRightAlign();\n  }\n}\n\nclass LeftRightAlignParentData extends ContainerBoxParentData<RenderBox> {}\n\nclass RenderLeftRightAlign extends RenderBox\n    with\n        ContainerRenderObjectMixin<RenderBox, LeftRightAlignParentData>,\n        RenderBoxContainerDefaultsMixin<RenderBox, LeftRightAlignParentData> {\n\n  RenderLeftRightAlign({\n    List<RenderBox> children,\n  }) {\n    addAll(children);\n  }\n\n  @override\n  void setupParentData(RenderBox child) {\n    if (child.parentData is! LeftRightAlignParentData)\n      child.parentData = LeftRightAlignParentData();\n  }\n\n  @override\n  void performLayout() {\n    final BoxConstraints childConstraints = constraints.loosen();\n\n    final RenderBox leftChild = firstChild;\n    final RenderBox rightChild = lastChild;\n\n    leftChild.layout(childConstraints, parentUsesSize: true);\n    rightChild.layout(childConstraints, parentUsesSize: true);\n\n    final LeftRightAlignParentData leftParentData = leftChild.parentData;\n    final LeftRightAlignParentData rightParentData = rightChild.parentData;\n\n    final bool wrapped =\n        leftChild.size.width + rightChild.size.width > constraints.maxWidth;\n\n    leftParentData.offset = Offset.zero;\n    rightParentData.offset = Offset(\n        constraints.maxWidth - rightChild.size.width,\n        wrapped ? leftChild.size.height : 0);\n\n    size = Size(\n        constraints.maxWidth,\n        wrapped\n            ? leftChild.size.height + rightChild.size.height\n            : math.max(leftChild.size.height, rightChild.size.height));\n  }\n\n  @override\n  bool hitTestChildren(HitTestResult result, {Offset position}) {\n    return defaultHitTestChildren(result, position: position);\n  }\n\n  @override\n  void paint(PaintingContext context, Offset offset) {\n    defaultPaint(context, offset);\n  }\n}\n\n...\n\nclass HomePageState extends State<HomePage> {\n  @override\n  Widget build(BuildContext context) {\n    return CupertinoPageScaffold(\n      navigationBar: CupertinoNavigationBar(middle: Text(\'App\')),\n      child: ListView(children: <Widget>[\n        Container(\n          margin: EdgeInsets.symmetric(horizontal: 32, vertical: 16),\n          child: LeftRightAlign(\n            left: Text(\n              \'Left Widget\',\n              style: TextStyle(fontSize: 40),\n            ),\n            right: Text(\n              \'Right Widget\',\n              style: TextStyle(fontSize: 40),\n            ),\n          ),\n        ),\n        Text(\'Next Line\'),\n      ])\n    );\n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n