I\'m trying to create a layout in flutter consisting of a row with two child widgets, the first aligned to the left and the second aligned to the right, that also will wrap
Thanks to Rémi Rousselet's advice to use a custom RenderBox
here is a basic implementation that solves the layout problem (based off the Wrap
widgets RenderBox
implementation 1 2)
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
import 'dart:math' as math;
class LeftRightAlign extends MultiChildRenderObjectWidget {
LeftRightAlign({
Key key,
@required Widget left,
@required Widget right,
}) : super(key: key, children: [left, right]);
@override
RenderLeftRightAlign createRenderObject(BuildContext context) {
return RenderLeftRightAlign();
}
}
class LeftRightAlignParentData extends ContainerBoxParentData {}
class RenderLeftRightAlign extends RenderBox
with
ContainerRenderObjectMixin,
RenderBoxContainerDefaultsMixin {
RenderLeftRightAlign({
List children,
}) {
addAll(children);
}
@override
void setupParentData(RenderBox child) {
if (child.parentData is! LeftRightAlignParentData)
child.parentData = LeftRightAlignParentData();
}
@override
void performLayout() {
final BoxConstraints childConstraints = constraints.loosen();
final RenderBox leftChild = firstChild;
final RenderBox rightChild = lastChild;
leftChild.layout(childConstraints, parentUsesSize: true);
rightChild.layout(childConstraints, parentUsesSize: true);
final LeftRightAlignParentData leftParentData = leftChild.parentData;
final LeftRightAlignParentData rightParentData = rightChild.parentData;
final bool wrapped =
leftChild.size.width + rightChild.size.width > constraints.maxWidth;
leftParentData.offset = Offset.zero;
rightParentData.offset = Offset(
constraints.maxWidth - rightChild.size.width,
wrapped ? leftChild.size.height : 0);
size = Size(
constraints.maxWidth,
wrapped
? leftChild.size.height + rightChild.size.height
: math.max(leftChild.size.height, rightChild.size.height));
}
@override
bool hitTestChildren(HitTestResult result, {Offset position}) {
return defaultHitTestChildren(result, position: position);
}
@override
void paint(PaintingContext context, Offset offset) {
defaultPaint(context, offset);
}
}
...
class HomePageState extends State {
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(middle: Text('App')),
child: ListView(children: [
Container(
margin: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
child: LeftRightAlign(
left: Text(
'Left Widget',
style: TextStyle(fontSize: 40),
),
right: Text(
'Right Widget',
style: TextStyle(fontSize: 40),
),
),
),
Text('Next Line'),
])
);
}
}