Flutter layout (3)-FittedBox, AspectRatio, ConstrainedBox detailed explanation

Flutter layout (3)-FittedBox, AspectRatio, ConstrainedBox detailed explanation

This article mainly introduces FittedBox, AspectRatio, ConstrainedBox in Flutter layout, introduces its deployment behavior and usage scenarios in detail, and analyzes the source code.

1. FittedBox

Scales and positions its child within itself according to fit.

1.1 Introduction

According to its official introduction, it mainly does two things, scaling (Scale) and position adjustment (Position).

FittedBox will scale within its own size range and adjust the position of the child so that the child fits its size. If you have done the mobile terminal, you may think of the ImageView control, which adjusts the zoom position of the picture within its range according to the rules. FittedBox is somewhat similar to ImageView. It can be guessed that it must have a property similar to ScaleType.

1.2 Layout behavior

The layout behavior of FittedBox is fairly simple, the official did not give an explanation, I will briefly talk about it here. Since FittedBox is a container and its child needs to be zoomed within its scope, its layout behavior is divided into two situations:

  • If there are external constraints, adjust its size according to the external constraints, then scale and adjust the child, and lay out according to the specified conditions;
  • If there are no external constraints, it is consistent with the child size, and the specified zoom and position attributes will not work.

1.3 Inheritance

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > FittedBox
 

It can be seen from the inheritance relationship that the FittedBox control is a basic control.

1.4 Sample code

new Container(
  color: Colors.amberAccent,
  width: 300.0,
  height: 300.0,
  child: new FittedBox(
    fit: BoxFit.contain,
    alignment: Alignment.topLeft,
    child: new Container(
      color: Colors.red,
      child: new Text("FittedBox"),
    ),
  ),
)
 

I wrote a very simple example. Container is added to display two areas with color. Readers can try to modify fit and alignment to see their different effects.

1.5 Source code analysis

const FittedBox({
Key key,
this.fit: BoxFit.contain,
this.alignment: Alignment.center,
Widget child,
})
 

1.5.1 Attribute resolution

fit : The way of zooming. The default attribute is BoxFit.containthat the child is as large as possible within the FittedBox, but does not exceed its size. Note here that contain is to fill as much as possible under the premise of maintaining the child's aspect ratio. Generally, when the width or height reaches the maximum value, the zoom will stop.

alignment : Alignment, the default attribute is to Alignment.centerdisplay the child in the center.

1.5.2 Source code

The constructor is as follows:

@override
RenderFittedBox createRenderObject(BuildContext context) {
return new RenderFittedBox(
  fit: fit,
  alignment: alignment,
  textDirection: Directionality.of(context),
);
}
 

The specific implementation of FittedBox is carried out by RenderFittedBox. I don t know if the readers have discovered that some of the current basic controls are inherited from RenderObjectWidget. The widget itself only stores some configuration information. The actual rendering is implemented by the RenderObject called by the internal createRenderObject.

The specific layout code of RenderFittedBox is as follows:

if (child != null) {
  child.layout(const BoxConstraints(), parentUsesSize: true);
 // child null child child 
  size = constraints.constrainSizeAndAttemptToPreserveAspectRatio(child.size);
  _clearPaintData();
} else {
 // child null 
  size = constraints.smallest;
}
 

1.6 Usage scenarios

FittedBox has not been used in the current project. For the processing that needs to be zoomed and adjusted, it is generally pictures. The author generally uses the decoration attribute in the Container to achieve the corresponding effect. For other controls that need to be zoomed and adjusted, there is no use scene yet. You only need to know that there is such a control that can achieve this function.

2. AspectRatio

A widget that attempts to size the child to a specific aspect ratio.

2.1 Introduction

The role of AspectRatio is to adjust the child to the set aspect ratio. This kind of control is generally not provided on other mobile platforms. I think the biggest reason why Flutter provides it is that it is particularly troublesome to customize.

2.2 Layout behavior

The layout behavior of AspectRatio is divided into two situations:

  • AspectRatio will first expand as much as possible within the range allowed by the layout constraints. The height of the widget is determined by the width and ratio. Similar to the contain in BoxFit, it will occupy the area as much as possible according to a fixed ratio.
  • If a feasible size cannot be found after all the constraints are met, AspectRatio will eventually adapt to the layout constraints first, ignoring the set ratio.

2.3 Inheritance

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > AspectRatio
 

From the perspective of inheritance, AspectRatio is the basic layout control.

2.4 Sample code

new Container(
  height: 200.0,
  child: new AspectRatio(
    aspectRatio: 1.5,
    child: new Container(
      color: Colors.red,
    ),
  ),
);
 

The sample code defines an area with a height of 200, the internal AspectRatio ratio is set to 1.5, and the final AspectRatio is an area with a width of 300 and a height of 200.

2.5 Source code analysis

The constructor is as follows:

const AspectRatio({
Key key,
@required this.aspectRatio,
Widget child
}) 
 

The constructor contains only one aspectRatio attribute, where aspectRatio cannot be null.

2.5.1 Attribute resolution

aspectRatio : aspectRatio is the aspect ratio, and the layout may not be based on this value in the end. It depends on the comprehensive factors. Whether the outer layer is allowed to be laid out at this ratio is just a reference value.

2.5.2 Source code

@override
  RenderAspectRatio createRenderObject(BuildContext context) => new RenderAspectRatio(aspectRatio: aspectRatio);
 

After analyzing some of the previous controls, I think everyone should not be unfamiliar with this structure anymore. The drawing is done by RenderObject, and here it is RenderAspectRatio to complete the specific drawing work.

The constructor of RenderAspectRatio will do some checks on aspectRatio (assert)

  • aspectRatio cannot be null;
  • aspectRatio must be greater than 0;
  • aspectRatio must be finite.

Next, let's take a look at the specific size calculation function of RenderAspectRatio:

  • If the restriction condition is isTight, the smallest size (constraints.smallest) is returned;
if (constraints.isTight)
  return constraints.smallest;
 
  • If the width is a finite value, set the height to width/_aspectRatio. If the width is infinite, set the height to the maximum height and the width to height * _aspectRatio;
if (width.isFinite) {
  height = width/_aspectRatio;
} else {
  height = constraints.maxHeight;
  width = height * _aspectRatio;
}
 
  • The next step is to adjust the width and height within the limit. The overall idea is to give priority to the width. If it is greater than the maximum value, it is set to the maximum value, and if it is less than the minimum value, it is set to the minimum value.

If the width is greater than the maximum width, set it to the maximum width and the height to width/_aspectRatio;

if (width > constraints.maxWidth) {
  width = constraints.maxWidth;
  height = width/_aspectRatio;
}
 

If the height is greater than the maximum height, set it to the maximum height, and set the width to height * _aspectRatio;

if (height > constraints.maxHeight) {
  height = constraints.maxHeight;
  width = height * _aspectRatio;
}
 

If the width is less than the minimum width, set it to the minimum width and the height to width/_aspectRatio;

if (width < constraints.minWidth) {
  width = constraints.minWidth;
  height = width/_aspectRatio;
}
 

If the height is less than the minimum height, it is set to the minimum height, and the width is set to height * _aspectRatio.

if (height < constraints.minHeight) {
  height = constraints.minHeight;
  width = height * _aspectRatio;
}
 

2.6 Usage scenarios

AspectRatio is suitable for scenarios where a fixed aspect ratio is required. The scene where the author recently used this control is a camera. The preview size of the camera is a fixed number of values. Therefore, you cannot set the display area of the camera at will. It must be displayed according to the ratio, otherwise it will be stretched. In addition, it is not used much.

3. ConstrainedBox

A widget that imposes additional constraints on its child.

3.1 Introduction

The function of this control is to add additional constraints to the child. It is simple in itself and can be replaced by some controls. Flutter's layout control system, after combing, found that it is indeed a bit messy, I feel that the overall idea is to make whatever is lacking, haha.

3.2 Layout behavior

The layout behavior of ConstrainedBox is very simple and depends on the set constraints. Regarding the priority of the constraints of the parent and child nodes, you can check the previous article, and I won't describe it in detail here.

3.3 Inheritance

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > ConstrainedBox
 

ConstrainedBox is also a basic layout control.

3.4 Sample code

new ConstrainedBox(
  constraints: const BoxConstraints(
    minWidth: 100.0,
    minHeight: 100.0,
    maxWidth: 150.0,
    maxHeight: 150.0,
  ),
  child: new Container(
    width: 200.0,
    height: 200.0,
    color: Colors.red,
  ),
);
 

The example is also quite simple. Add a ConstrainedBox that constrains the maximum and minimum width and height to a Container with a width and height of 200.0. In the actual display, it is an area with a width and height of 150.0.

3.5 Source code analysis

The constructor is as follows:

ConstrainedBox({
Key key,
@required this.constraints,
Widget child
})
 

Contains a constraints attribute, and cannot be null.

3.5.1 Attribute resolution

constraints : Additional constraints added to the child, its type isBoxConstraints. What is the purpose of BoxConstraints? In fact, it is very simple, that is, to limit the maximum and minimum width and height. Speaking of here, double.infinity is when the widget is laid out , that is to say, for example, if you want the largest expansion width, you can set the width value to double.infinity.

3.5.2 Source code

@override
RenderConstrainedBox createRenderObject(BuildContext context) {
return new RenderConstrainedBox(additionalConstraints: constraints);
}
 

RenderConstrainedBox realizes its drawing. The specific layout performance is divided into two situations:

  • If child is not null, the restriction conditions are added to child;
  • If child is null, the size will be reduced as much as possible.

The specific code is as follows:

@override
void performLayout() {
if (child != null) {
  child.layout(_additionalConstraints.enforce(constraints), parentUsesSize: true);
  size = child.size;
} else {
  size = _additionalConstraints.enforce(constraints).constrain(Size.zero);
}
}
 

3.6 Usage scenarios

You can use this control if you need to add additional constraints, such as setting the minimum width and height, occupying as much area as possible, and so on. The author does not use a lot in actual development. It is not that this control is not easy to use, but that many constraint factors are integrated. For example, additional settings of margin and padding properties are required. Therefore, it is very cumbersome to set this separately. Up.

3.7 About UnconstrainedBox

This control will not be introduced in detail. It is the opposite of ConstrainedBox. It does not add any constraints to the child, and lets the child render according to its original size.

It's amazing, I also think that its function is to give the child as much space as possible and let it be displayed without constraints. I have no idea of its usefulness for the time being. It can only be said that Flutter produces Widgets very casually.

4. Later

A Flutter learning-related project built by the author, Github address created by the author , contains some articles written by the author about Flutter learning, which will be updated regularly, and some learning demos will also be uploaded. Welcome everyone to pay attention.

5. Reference

  1. FittedBox class
  2. BoxFit enum
  3. AspectRatio class
  4. ConstrainedBox class
  5. BoxConstraints class
  6. UnconstrainedBox class