In the last section we saw that Stack and jam provide the exact offset of one or more child elements with respect to the edges of the parent, and can overlap. But if we simply want to adjust the position of a child element in the parent element, it’s easier to use the Align component.

Align

The Align component can adjust the position of its children and determine its own width and height based on the width and height of the children, as defined below:

Align({
  Key key,
  this.alignment = Alignment.center,
  this.widthFactor,
  this.heightFactor,
  Widget child,
})
Copy the code
  • alignment: Need oneAlignmentGeometryType that represents the starting position of the child component in the parent.AlignmentGeometryIs an abstract class that has two commonly used subclasses:AlignmentandFractionalOffset, which we will cover in detail in the following examples.
  • widthFactorandheightFactorIs used to determineAlignThe width and height property of the component itself; These are two scaling factors, multiplied by the width and height of the child element, and the final result isAlignWidth and height of the component. If the value isnull,AlignThe width and height of the components will take up as much space as possible.

The sample

Let’s start with a simple example:

Container(height: 120.0, width: 120.0, color: Colors. Blue [50], child: Align(alignment: Align. TopRight, child: FlutterLogo( size: 60, ), ), )Copy the code

The running effect is as follows:

The FlutterLogo is a component of the Flutter SDK that contains the Flutter logo. In the example above, we explicitly specify that the Container is 120 in width and 120 in height. If we do not explicitly specify the width and height, we can achieve the same effect by specifying both widthFactor and heightFactor to be 2, as follows:

Align(
  widthFactor: 2,
  heightFactor: 2,
  alignment: Alignment.topRight,
  child: FlutterLogo(
    size: 60,
  ),
),
Copy the code

Since the width and height of FlutterLogo is 60, the final width and height of Align are both 2*60=120.

In addition, we positioned the FlutterLogo in the upper right corner of the Container using Alignment. TopRight. What is Alignment. TopRight? By searching the SDK source code, we can see its definition as follows:

// Upper right static const Alignment topRight = Alignment(1.0, -1.0);Copy the code

As you can see, this is just one example of Alignment, which we will introduce next.

Aligment

Alignment inherits AlignmentGeometry, which represents a point in the rectangle. It has two attributes X and Y, which represent the deviation in horizontal and vertical directions respectively. Alignment is defined as follows:

Alignment(this.x, this.y)
Copy the code

The Alignment component takes the center point of the rectangle as the coordinate origin, namely Alignment(0.0, 0.0). X values ranging from -1 to 1 indicate the distance from left to right of the rectangle, and Y values ranging from -1 to 1 indicate the distance from top to bottom of the rectangle. Therefore, two horizontal or vertical units are equal to the width or height of the rectangle. For example, Alignment(-1.0, -1.0) indicates the left vertex of the rectangle. Alignment(1.0, 1.0) represents the bottom-right end point, while Alignment(1.0, -1.0) is the right vertex, namely Alignment. TopRight. For ease of use, the rectangle’s origin, four vertices, and four edge ends are defined as static constants in the Alignment class.

An Alignment can use its coordinate transformation formula to convert its coordinates to the specific offset coordinates of the child elements:

(Alignment.x * childWidth/2 + childWidth/2, Alignment.y * childHeight/2 + childHeight/2)
Copy the code

ChildWidth is the width of the child element, and childHeight is the height of the child element.

Now let’s look at the example above. If we put Alignment(1.0, -1.0) into the formula above, the actual offset coordinates of FlutterLogo are (60, 0). Let’s look at another example:

Align(widthFactor: 2, heightFactor: 2, alignment: alignment (2.0, 0.0), child: FlutterLogo(size: 60,)Copy the code

Now let’s look at the example above. If Alignment(2.0, 0.0) is put into the above coordinate conversion formula, the actual offset coordinate of FlutterLogo can be obtained as (90, 30). The actual operation effect is as follows:

FractionalOffset

FractionalOffset inherits self-alignment. The only difference between FractionalOffset and Alignment is the origin of the coordinates! The origin of the FractionalOffset coordinates is the left vertex of the rectangle, which is consistent with the layout system, so it is easier to understand. The coordinate conversion formula of FractionalOffset is:

(FractionalOffset.x * childWidth, FractionalOffset.y * childHeight)
Copy the code

Example:

Container(height: 120.0, width: 120.0, color: Colors. Blue [50], child: Align(alignment: FractionalOffset(0.2, 0.6), Child: FlutterLogo(size: 60,),)Copy the code

The actual running effect is as follows:

We put FractionalOffset(0.2, 0.6) into the coordinate transformation formula, and it can be obtained that the actual offset of FlutterLogo is (12, 36), which is consistent with the actual operation effect.

Align vs. Stack

Now we know that both Align and Stack/Positioned can be used to specify the offset of the child with respect to the parent, but they have two main differences:

  1. Different positioning reference systems;Stack/PositionedThe reference frame can be the four vertices of the parent container rectangle; whileAlignYou need to pass it firstalignmentParameter to determine the origin of coordinates, differentalignment(e.g.,AlignmentorFractionalOffset) will correspond to different origin, the final offset is required to passalignmentTo calculate the conversion formula.
  2. StackCan have multiple child elements, and child elements can be stacked, andAlignThere can be only one child, no stack.

Relationship between the Align component and the Center component

We have already used the Center component to house neutrons in the examples in the previous section, so let’s introduce it formally. By looking at the SDK source, we can see that the Center component is defined as follows:

class Center extends Align {
  const Center({ 
    Key key, 
    double widthFactor, 
    double heightFactor, 
    Widget child 
  }): super(
    key: key, 
    widthFactor: widthFactor, 
    heightFactor: heightFactor, 
    child: child
  );
}
Copy the code

As you can see, Center inherits from Align and has only one less alignment parameter than Align. Since Align’s constructor has an alignment value of alignment.center, we can assume that the center component is actually Align with alignment.center.

Note that the width and height of the Align component will take up as much space as possible when widthFactor or heightFactor is null. Here’s an example:

. // DecoratedBox(decoration: BoxDecoration(color: color.red), child: Center(child: Text)"xxx"),
  ),
),
DecoratedBox(
  decoration: BoxDecoration(color: Colors.red),
  child: Center(
    widthFactor: 1,
    heightFactor: 1,
    child: Text("xxx"),),)Copy the code

The running effect is as follows:

conclusion

This section focuses on the Align component and the two offset classes Alignment and FractionalOffset. Readers need to understand the difference between these two offset classes and their respective coordinate transformation formulas. In addition, readers are advised to use FractionalOffset first when they need to make some precise offsets, because it has the same coordinate origin as the layout system, which makes it easier to calculate the actual offsets.

Next we introduce the contrast between the Align component and the Stack/Positioned component, and the relationship with the Center, which the reader can see by comparison.

Finally, those familiar with Web development may notice that the characteristics of the Align component are very similar to position: Relative in Web development. Yes! Most of the time, we can use the Align component directly to achieve relative positioning on the Web, and the reader can remember by analogy.