When introducing Row and Column, an overflow error is reported if the child component is out of screen range, such as:
Row(
children: <Widget>[
Text("xxx"* 100)],);Copy the code
The running effect is as follows:
As you can see, the overflow section on the right is an error. This is because the Row is only one line by default and does not fold if it goes beyond the screen. We call the layout that folds automatically when it goes beyond the screen a streaming layout. Flutter supports streaming layout with Wrap and Flow. If Row is replaced with Wrap in the previous example, the overflow part will fold automatically.
Wrap
Here is the definition of Wrap:
Wrap({ ... Horizontal = Axis. Horizontal, this.alignment = WrapAlignment. Start, this.spacing = 0.0, This. RunAlignment = WrapAlignment. Start, enclosing runSpacing = 0.0, enclosing crossAxisAlignment = WrapCrossAlignment. Start, this.textDirection, this.verticalDirection = VerticalDirection.down, List<Widget> children = const <Widget>[], })Copy the code
We can see that many Wrap attributes have the same meaning in Row, Column, and Flex, such as direction, crossAxisAlignment, textDirection, verticalDirection, and children. Note, however, that the crossAxisAlignment attribute in Wrap is slightly different from the crossAxisAlignment attribute in Row, Column, and Flex:
-
Different value modes; Wrap the crossAxisAlignment values for WrapCrossAlignment. Start, and the Row and Column, as well as in the Flex crossAxisAlignment values as crossAxisAlignment. The center, WrapCrossAlignment is used for the former, while CrossAxisAlignment is used for the latter.
-
When the main axis is vertical, the alignment of sub-components is slightly different. As in Wrap crossAxisAlignment value of WrapCrossAlignment. Center, and the direction for the Axis, vertical and width of the screen width at the same time, this all child components in the Wrap are centered on the width of the largest component alignment, CrossAxisAlignment values in the Column for crossAxisAlignment center, and width for the screen width, then all subcomponents of them will be in the middle of the screen width center alignment and to maximize the component.
Example code for Wrap:
ConstrainedBox( constraints: BoxConstraints(minWidth: double.infinity), child: Container( color: Colors.blue, child: Wrap( direction: Axis.vertical, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[ Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("A"),), label: Text("Hamilton"), ), Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("B"),), label: Text("LafayetteLafayette"), ), Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("C"),), label: Text("Mulligan"), ), Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("D"),), label: Text("Laurens"(), [(), [(), [(Copy the code
Operation effect:
Sample code for Column:
ConstrainedBox( constraints: BoxConstraints(minWidth: double.infinity), child: Container( color: Colors.blue, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("A"),), label: Text("Hamilton"), ), Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("B"),), label: Text("LafayetteLafayette"), ), Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("C"),), label: Text("Mulligan"), ), Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("D"),), label: Text("Laurens"(), [(), [(), [(Copy the code
Operation effect:
Other attributes are the same, and I won’t go over them all here. You can refer to Row and Colum’s articles. Let’s take a look at a few properties that are unique to Wrap:
spacing
: Spacing of sub-components in the spindle directionrunSpacing
: Spacing of child components along the vertical axisalignment
: Alignment of subcomponents in the spindle directionrunAlignment
: Alignment of child components along the vertical axis
The sample
Container(color: color. blue, child: Wrap(spacing: 20.0, runSpacing: 10.0, alignment: WrapAlignment. Center, children: <Widget>[ Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("A"),),
label: Text("Hamilton"),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("B"),),
label: Text("Lafayette"),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("C"),),
label: Text("Mulligan"),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("D"),),
label: Text("Laurens"),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("D"),),
label: Text("Zane"(), [(), [(),Copy the code
The running effect is as follows:
We can see that the width and height of the Wrap are adaptive, depending on the subcomponents it contains. If we want to set the width and height of the Wrap, we can force changes to the width and height limits by ConstrainedBox and SizedBox, as in:
ConstrainedBox(constraints: BoxConstraints(minWidth: double. Infinity, minHeight: 600.0), child: Container(color: Colors.blue, child: Wrap( alignment: WrapAlignment.center, runAlignment: WrapAlignment.center, children: <Widget>[ Chip( avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("A"),),
label: Text("Hamilton"),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("B"),),
label: Text("LafayetteLafayette"),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("C"),),
label: Text("Mulligan"),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue, child: Text("D"),),
label: Text("Laurens"(), [(), [(), [(Copy the code
Flow
Flow is rarely used because it is too complex and requires the implementation of the position conversion of the child components, so in many scenarios the first consideration is whether Wrap meets the requirements. Flow is mainly used in scenarios where a custom layout strategy is required or where performance is required (such as in animation).
Flow
The advantages of
- Good performance:
Flow
Is a very efficient control to adjust the size and position of child components,Flow
Use the transformation matrix to optimize when adjusting the position of the child components: inFlow
After positioning, if the size or position of the child component changes, inFlowDelegate
In thepaintChildren()
Method callcontext.paintChild
I’m going to redraw, andcontext.paintChild
The transformation matrix was used in the redraw without actually adjusting the component positions. - Flexibility: Because we need to implement it ourselves
FlowDelegate
In thepaintChildren()
Method, so you need to calculate the position of each component, so you can customize the layout strategy.
Flow
The disadvantages of the
- Use complexity (code implementation is still a bit of a foundation).
- Child component sizing cannot be customized and must be done by specifying the parent container size or
TestFlowDelegate
thegetSize
Return fixed size.
The sample
Custom streaming layout:
Flow(delegate: TestFlowDelegate(margin: edgeinset.all (10.0)), children: <Widget>[new Container(width: Color: color.red,), new Container(width: 80.0, height:80.0, color: color.red,) Color.green,), new Container(width: 80.0, height:80.0, color: color.blue,), new Container(width: 80.0, height:80.0, color: color.blue,), new Container(width: Color: color.yellow,), new Container(width: 80.0, height:80.0, color: color.yellow,) Colors. Brown,), new Container(width: 80.0, height:80.0, color: color.purple,),],)Copy the code
Implement TestFlowDelegate:
class TestFlowDelegate extends FlowDelegate { EdgeInsets margin = EdgeInsets.zero; TestFlowDelegate({this.margin}); @override void paintChildren(FlowPaintingContext context) { var x = margin.left; var y = margin.top; // Calculates the position of each child widgetfor (int i = 0; i < context.childCount; i++) {
var w = context.getChildSize(i).width + x + margin.right;
if{< context. The size. The width (w). The context paintChild (I, transform: new Matrix4 translationValues (x, y, 0.0)); x = w + margin.left; }else{ x = margin.left; y += context.getChildSize(i).height + margin.top + margin.bottom; / / draw the child widgets (optimization) context. PaintChild (I, transform: new Matrix4 translationValues (x, y, 0.0)); x += context.getChildSize(i).width + margin.left + margin.right; }} @override getSize(BoxConstraints constraints){// Specify the size of the FlowreturnThe Size (double. Infinity, 200.0); } @override bool shouldRepaint(FlowDelegate oldDelegate) {return oldDelegate != this;
}
}
Copy the code
Operation effect:
As you can see, our main task is to implement the paintChildren() method, whose main purpose is to determine the location of each child component. Since Flow does not adapt to the size of its child components, we specify the size of Flow by returning a fixed size in the getSize() return.