Everything in Flutter is controlled. This article will explain how to use the basic controls and show you how to combine them with an example.

Grammar can be the basis of knowing the Dart accessibility to read this content, specific introduction can click on Flutter | Dart syntax.

Interface entry

When you create a Flutter app, you can deeply feel that everything is controlled.

The entry to the Flutter App is the main() method in the main.dart file in the lib directory:

void main() {
  runApp(MyApp());
}
Copy the code

MyApp is a control:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        appBar: AppBar(title: const Text('Welcome to Flutter')),
        body: , // This is where you can populate the controls you want to display)); }}Copy the code

MyApp inherits from StatelessWidget, which is a custom stateless control. To customize a control, override build(), which returns a Widget that is the base class for all controls.

This time it returns the MaterialApp, which is a material Design-compliant control. The Scaffold of the home property type is also a control. The scaffolding that builds the AppBar and body controls is where most of the application’s business interfaces are filled.

It can be seen that the controls in Flutter are directly new, the build layout is declarative, and the layout and logic are mixed together.

The text

Start with the basic text:

Text(
  'abc'./ / content
  style: TextStyle(
    fontSize: 12./ / size
    fontWeight: FontWeight.w400, / / word
    color: Colors.blue, / color/word
    fontFamily: 'pingfang'./ / font
    maxLines: 1 // Maximum number of rows));Copy the code

Custom fonts

The code above builds a text control and styles the text. For any custom fonts referenced in this file, you must first store the font file in the app/fonts directory (if not, create a new one) :

Then load the font in the pubspec.yaml file and you can reference it in DART:

Custom colors

In addition to using the system’s predefined colors.xxx Colors, you can also use custom Colors:

Text(
  'abc', 
  style: TextStyle(
    color: Color(0xFFB9BEC5), // Custom colors));Copy the code

Construct a Color object directly and pass in the hexadecimal value of the Color.

The rich text

// 'I am a programmer' is split into two paragraphs, with different font size and color
Text.rich(TextSpan(children: [
  TextSpan(
      text: 'I am',
      style: TextStyle(
          fontSize: 10, 
          color: Colors.blue
      )
  ),
  TextSpan(
      text: 'Programmer', 
      style: TextStyle(
          color: Colors.red, 
          fontSize: 12))))Copy the code

Text.rich() is a named constructor for the Text control that passes in a TextSpan object with a children property, which means that several TextSpan objects can be passed in, each of which can set the Text property independently. Decompose into several TextSpan objects to achieve the rich text effect.

The picture

Loading local images

Image.asset(
  'images/hot_week.webp'.// Local image name
),
Copy the code

The code above builds oneImageControl is used to display local images, where the image resource images/hot_week.webp must be stored firstapp/imagesDirectory (if not created) :

Then load the image in the pubspec.yaml file and you can reference it in dart:

Loading network images

Image.network(
  circle?.url ?? "",
  fit: BoxFit.cover,
)
Copy the code

The Image control has a convenient naming method, network(), which can load images asynchronously just by passing in the Image URL.

The fit property indicates how the image should fit the size of the control. Boxfit. cover scales the image to equal proportions until the control is full of width and height.

Control the size

The size of a Flutter control is not determined by itself, but by its parent control.

This is a proverb that must be kept in mind when arranging Flutter.

So if you want to show a 200 by 200 image, you can only say:

Container(
  width: 200,
  height: 200,
  child: Image.asset('images/hot_week.webp'))Copy the code

Right! Fill the Container with a layer and specify the width and height of the Container.

Try inheriting the above code from the MaterialApp:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Container(
        width: 200,
        height: 200,
        child: Image.asset('images/hot_week.webp'))); }}Copy the code

When you run the code, you’ll be surprised to see images fill the entire screen. The proverb took effect. Unfortunately, the parent control, the MaterialApp control, has constraints on the child. It requires that the child control cover the entire parent control, so the specified width and height of the Container will not take effect.

Another way to write it is:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        appBar: AppBar(title: const Text('Welcome to Flutter')),
        body: Container(
          width: 200,
          height: 200, color: Colors.red ), ), ); }}Copy the code

This time the 200 * 200 image becomes the Scaffold child and the result is as expected. That’s because scaffolds constrain children to be as big as they want but not bigger than me.

This leads to the second saying about the Flutter layout:

The parent control always imposes a constraint on the child that determines the range and relative position of the child’s width and height.

Margin background rounded corner

The Container control can specify dimensions, interior and exterior margins, background color, and rounded corners.

Container(
  decoration: BoxDecoration(
      borderRadius: BorderRadius.all(Radius.circular(8)), / / the rounded
      color:Colors.red / / fill color
  ),
  padding: EdgeInsets.fromLTRB(10.5.10.5),// Inner margin, specify upper left and lower right respectively
  margin: EdgeInsets.all(20),// The margin is 20
  child: Text("This is a text with rounded corners."),Copy the code

The above code is shown below:

The idea of “wrapping a parent control to determine the margin, background, and rounded corners” is not quite the same as building Android’s native interface. In the native world these are properties of the control itself. One of the obvious benefits of this approach is decoupling: margins, backgrounds, and rounded corners can be easily attached to any control, rather than having to worry about margins, backgrounds, and rounded corners for each custom control.

Linear container

A Flutter has two linear containers that do not roll: a horizontal Row and a vertical Column.

Row(
  children: [
    Text('look at here--'),
    Text('123--'),
    Text('and--'),
    Text('more--'),
    Text('gift--'),,)Copy the code

The above code looks like this:

The blue lines in the image above represent the boundaries of the Flutter control, which is the interface debugging tool that comes with Flutter. This should only be set in the main() methoddebugPaintSizeEnabledSet this to true, then run the app again (hot restart does not work) :

void main() {
  debugPaintSizeEnabled = true; 
  runApp(MyApp());
}
Copy the code

As you can see, Column’s parent controls require it to span the screen horizontally, while Column has no constraints on its children, who can determine their own size.

Instead of a vertical container, it is written similarly:

Column(
  children: [
    Text('look at here--'),
    Text('123--'),
    Text('and--'),
    Text('more--'),
    Text('gift--'),,)Copy the code

The above code looks like this:

Similarly, Column is required to cover the entire screen vertically by the parent control, but there is no constraint on the size of the child control.

Expanded

If a child control of a linear container wants to fill up the rest of the container, it can be written like this:

 Row(
  children: [
    Expanded(child: Text('look at here--')),// Fill the remaining space of the container
    Text('123--'),
    Text('and--'),
    Text('more--'),
    Text('gift--'),,)Copy the code

The above code has the following effect:

If each child of a linear container is Expanded wrapped, it can passflexAttributes to determine their proportions:

Row(
  children: [
    Expanded(child: Text('look at here--'), flex: 2),
    Expanded( child: Text('123--'), flex: 3, ),
    Expanded( child: Text('and--'), flex: 4, ),
    Expanded( child: Text('more--'), flex: 1, ),
    Expanded( child: Text('gift--'), flex: 2,),,)Copy the code

The above code looks like this:

alignment

The alignment of linear containers is divided into two axes, mainAxisAlignment and crossAxisAlignment.

For horizontal containers, the main axis is horizontal, and the axis that crosses the horizontal is vertical.

For a longitudinal container, the principal axis is vertical and the axis intersecting the vertical is horizontal.

Column(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,// Divide evenly on the main axis
  children: [
    Text('look at here--'),
    Text('123--'),
    Text('and--'),
    Text('more--'),
    Text('gift--'),,)Copy the code

The above code has the following effect:

Because the parent control requires the Column to span the entire screen vertically, dividing the layout evenly across the main axis causes the child controls to be evenly distributed vertically across the screen. The blue border shows that the size of the control itself has not changed, only its position relative to the parent control.

If you want the child control to be left aligned, you can write:

Column(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,// Divide evenly on the main axis
  crossAxisAlignment: CrossAxisAlignment.start, // Align left on the cross axis
  children: [
    Text('look at here--'),
    Text('123--'),
    Text('and--'),
    Text('more--'),
    Text('gift--'),,)Copy the code

The above code looks like this:

The overflow

Column and Row are non-scrollable controls, so if there are too many child controls on the main axis, they will not be fully displayed. This is called overflow:

Row(
  children: [
    Text('look at here--'),
    Text('123--'),
    Text('and--'),
    Text('more--'),
    Text('gift--'),
    Text('gift--'),
    Text('gift--'),
    Text('gift--'),
    Text('gift--'),
    Text('gift--'),
    Text('gift--'),,)Copy the code

Deliberately added several controls to overflow in the horizontal direction:

A yellow and black warning is displayed when an overflow occurs. 4) RenderFlex overlearning by 28 Pixels on the right

Here’s another example of an error:

 Row(
  children: [
    Text('look at here--'),
    Text('123--'),
    Text('and--'),
    Text('more--'),
    Text('gift--'),
    ListView(scrollDirection: Axis.horizontal),// Horizontal list],)Copy the code

A horizontal list was added to the horizontal container. The Horizontal viewport was given unbounded width. The Horizontal viewport had no constraint on the Horizontal dimension.

Because Column does not constrain its child controls to grow horizontally and vertically, one of the children, incidentally, is the ListView, which is also a free-growing control that grows horizontally. When two controls grow freely in the same direction, the parent control does not know how big it should be.

The solutions are as follows:

Container(
  color: Colors.red,
  child: Row(
    children: [
      Text('look at here--'),
      Text('123--'),
      Text('and--'),
      Text('more--'),
      Text('gift--'),
      ListView(
        scrollDirection: Axis.horizontal,
        shrinkWrap: true[], (), (Copy the code

ShrinkWrap adds a property to shrinkWrap the Size of the ListView as small as possible to wrap the child controls. This determines the size of the ListView and thus the size of the Column.

To see the Row boundary clearly, wrap it in a Container and add a red background. Run:

There is no error, but the effect is not quite consistent with expectations. The parent container used to fill the screen horizontally with rows, but now it fills the screen vertically with ListView.

This is because the ListView has no restrictions on the height of the child control and its own height is the maximum height of the child control, as is the case with Row. In this case, as long as the ListView child control is high enough, it is possible for the Row to go beyond the bottom of the screen, but why is there no overflow warning? The parent container’s constraint on a Row is that it “spans the screen horizontally, as high as you want, but not higher than me.”

Now comes the third proverb of the Flutter layout:

Although the size and position of the child control are constrained by the parent control, the size of the child control can sometimes affect the size of the parent control.

The integrated use of

Consider an example of a combination: the navigation bar

The navigation bar contains three horizontal buttons, each of which is a vertical combination of Image and Text. So the navigation Column should be a Row containing three columns. Let’s look at each Column:

Column(
  mainAxisSize: MainAxisSize.min, // Limit the column height so that it is always minimized and just wraps the child controls
  mainAxisAlignment: MainAxisAlignment.center, // The child controls are centered
  children: [
    Image.asset('images/call.webp'), / / icon
    Container( // Container (to increase icon and text spacing)
      margin: EdgeInsets.only(top: 8), / / spacing
      child: Text( / / text
        "CALL",
        style: TextStyle(
          fontSize: 12,
          fontWeight: FontWeight.w400,
          color: Colors.blue,
        ),
      ),
    ),
  ],
)
Copy the code

The above code looks like this:

Then embed the three columns into the Row

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',

      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            / / phone
            Column(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset('images/call.webp'),
                Container(
                  margin: EdgeInsets.only(top: 8),
                  child: Text(
                    "CALL",
                    style: TextStyle(
                      fontSize: 12,
                      fontWeight: FontWeight.w400,
                      color: Colors.blue,
                    ),
                  ),
                ),
              ],
            ),
            / / routing
            Column(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset('images/route.webp'),
                Container(
                  margin: EdgeInsets.only(top: 8),
                  child: Text(
                    "ROUTE",
                    style: TextStyle(
                      fontSize: 12,
                      fontWeight: FontWeight.w400,
                      color: Colors.blue,
                    ),
                  ),
                ),
              ],
            ),
            / / share
            Column(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset('images/share.webp'),
                Container(
                  margin: EdgeInsets.only(top: 8),
                  child: Text(
                    "SHARE",
                    style: TextStyle(
                      fontSize: 12, fontWeight: FontWeight.w400, color: Colors.blue, ), ), ), ], ) ], ), ), ); }}Copy the code

trailer

The widgets in Flutter are called widgets. They can be divided into stateful widgets and StatelessWidgets. Stateful means a control whose content changes. Stateless means a control that is statically immutable.

The next article will customize a stateful and stateless control, respectively, to better understand the differences as you customize them.

reference

List of all Flutter controls

Layouts in Flutter | Flutter