What is layout in Flutter

Layout in Flutter is controlled by Widgets. Some of them are visible such as Text, Image or Icon. However, some of them are also invisible, like Row, Column, or Stack.

Although invisible, yet Row, Column or Stack play very important role in building layout in Flutter.

As we know, almost everything in Flutter is Widget; therefore, layout model is no exception. According to the layout model, the invisible widgets use constraint, align, aspect ratio, baseline and other Widgets to arrange visible widgets.

We always create a layout by composing Widgets to build more complex Widget structures, or tree.

Consider the following screenshot. That will explain how we’ve built this layout by mixing visible and invisible widgets.

Basic Layout widgets example in Flutter
Basic Layout widgets example in Flutter

In the previous section we’ve discussed how we can paint our canvas or screen in Flutter. As an extension, we’ve used the same background; and, after that we design our layout on top of that background.

How do I create a layout in Flutter?

Now, the time has come to take a look at the full code snippet.

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'A Custom Home Page',
      home: DashBoard(
          // size: size,
          ),
    );
  }
}

class DashBoard extends StatelessWidget {
  //final Size size;
  const DashBoard({
    Key? key,
    //required this.size,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;
    return MaterialApp(
      title: 'A Custom Home Page',

      /// ignore: todo
      ///TODO: we'll make a custom global theme later
      ///

      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.black12,
          leading: const Icon(Icons.menu),
          title: const Text(
            "A Custom Home Page",
            textAlign: TextAlign.center,
          ),
        ),
        body: Stack(
          children: <Widget>[
            Container(
              padding: const EdgeInsets.all(5),
              child: CustomPaint(
                painter: ShapingPainter(),
                child: Container(
                  height: size.height / 1,
                ),
              ),
            ),
            Container(
              margin: const EdgeInsets.all(10),
              child: Padding(
                padding: const EdgeInsets.all(10),
                child: Row(
                  children: [
                    Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Image.network(
                          'https://cdn.pixabay.com/photo/2021/12/05/10/28/nature-6847175_960_720.jpg',
                          width: 150,
                          height: 100,
                        ),
                        Container(
                          padding: const EdgeInsets.all(7),
                          child: const Text(
                            'Let\'s go',
                            style: TextStyle(
                              fontSize: 25,
                              fontWeight: FontWeight.bold,
                              color: Colors.white,
                            ),
                          ),
                        ),
                      ],
                    ),
                    Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Image.network(
                          'https://cdn.pixabay.com/photo/2021/11/13/23/06/tree-6792528_960_720.jpg',
                          width: 150,
                          height: 100,
                        ),
                        Container(
                          padding: const EdgeInsets.all(7),
                          child: const Text(
                            'Let\'s go',
                            style: TextStyle(
                              fontSize: 25,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ),
                      ],
                    ),
                    Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Image.network(
                          'https://cdn.pixabay.com/photo/2021/12/12/20/26/flow-6866055_960_720.jpg',
                          width: 150,
                          height: 100,
                        ),
                        Container(
                          padding: const EdgeInsets.all(7),
                          child: const Text(
                            'Let\'s go',
                            style: TextStyle(
                              fontSize: 25,
                              fontWeight: FontWeight.bold,
                              color: Colors.blue,
                            ),
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

class ShapingPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint();

    /// setting the paint color greyish
    /// so it could cover the lower half of the screen
    ///
    paint.color = Colors.black12;

    /// Creating a rectangle with size and width same as the canvas
    /// It'll be going to cover the whole screen
    ///
    var rect = Rect.fromLTWH(0, 0, size.width, size.height);

    /// Drawing the rectangle using the paint
    ///
    canvas.drawRect(rect, paint);

    /// Covering the upper half of the rectangle
    ///
    paint.color = Colors.purpleAccent;
    // Firstly, creating a path to form the shape
    var path = Path();
    path.lineTo(0, size.height);
    path.lineTo(size.width, 0);
    // Secondly, closing the path to form a bounded shape
    path.close();
    canvas.drawPath(path, paint);
    // Setting the color property of the paint
    paint.color = Colors.white;
    // Center of the canvas is (x,y) => (width/2, height/2)
    var center = Offset(size.width / 2, size.height / 2);
    // Finally, drawing the circle with center having radius 95.0
    canvas.drawCircle(center, 95.0, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}

If we read the code carefully, what we’ll find?

We find that we’ve designed a layout that starts with the Stack widget.

We’ll discuss Stack in great detail later, so don’t worry. You can always use the search button in the website to find out what you need.

Stack widget basically keeps other widgets on top of the base widget. One after another. Therefore, here we’ve painted our background as the base widget.

 body: Stack(
          children: <Widget>[
            Container(
              padding: const EdgeInsets.all(5),
              child: CustomPaint(
                painter: ShapingPainter(),
                child: Container(
                  height: size.height / 1,
                ),
              ),
            ),
...
/// the following widgets will be placed on top of this Container

As a result, first we’ve designed a background layout first. To do that, we’ve first created a Custom Painter Widget “ShapingPainter” and passed it as the named parameter of CustomPaint widget.

 child: CustomPaint(
                painter: ShapingPainter(),
                child: Container(
                  height: size.height / 1,
                ),
              ),
...

As a result, the base widget of our Stack works as a background. For the respective code snippet please visit the GitHub repository.

We've used paint in Flutter to get a custom home background
We’ve used paint in Flutter to get a custom home background

Next, on top of this base background, we’ve created the Widget tree using visible and invisible widgets.

Now, as we might expect, it looks like that. Each Column inside the Row widget, has Image, Container, Text, and TextStyle widgets. We’ve used a Container to add padding, margin, alignment etc.

For instance, each Text widget is placed inside a Container to add padding or margin.

The rest of the design and layout follow the rules that we’ve set by controlling different properties.

Let’s think about Row, or Column. Although they are invisible, still they can specify how their children will be aligned, vertically, or horizontally. Moreover, they can set how much space the children widgets should occupy.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

Courses at Educative

GitHub repository

Technical blog

Twitter

Comments

One response to “What is layout in Flutter”

  1. […] we’ve used a color gradient as its background, that matches with our Application’s background color […]

Leave a Reply