How we build Flutter Layout

In our previous section we’ve learned some key components of a layout model in Flutter. Now, in this section, we would like to build a layout on top of that.

According to the layout model, the invisible widgets use constraintalignaspect ratiobaseline and other Widgets to arrange visible widgets such as TextImage or Icon. However, some of them, again are also invisible.

We have seen how invisible widgets like RowColumn, or Stack have been used in our previous section – What is Layout in Flutter?

As a result, we’ve seen such screenshot like the following.

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

If you’re a beginner and have interest in learning Flutter layout from scratch, you might take a look at the respective GitHub repository.

Now, we want to move forward. Therefore, we want to make it sure that, we can add more rows like the above screenshot and, moreover, we can scroll down to the lower part, as well.

To make it happen, we need a scrolling widget like ListView. Although the Column widget places its children widgets in its main axis vertically, but after a certain limit it exhausts. And the overflow error is thrown.

Just to avoid such accidental hiccups, let us break our code in several custom widgets, first.

We keep the custom Custom Paint object in the model folder. This pain object extends abstract class Custom Painter, and builds our background.

import 'package:flutter/material.dart';

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;
}

Now, let’s start building the layout with the root app.

import 'package:flutter/material.dart';

import 'view/my_app.dart';

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

The My App follows the Material Design guidelines and extends those properties to a custom widget Dashboard Home.

import 'package:flutter/material.dart';

import 'dash_board.dart';

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

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

The Dashboard Home scaffolds the body where we keep three Container widgets inside a ListView.

import 'package:flutter/material.dart';
import '/model/shaping_painter.dart';

import 'all_containers.dart';

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

  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.black12,
        leading: const Icon(Icons.menu),
        title: const Text(
          'Let\'s Go!',
          textAlign: TextAlign.center,
        ),
      ),
      body: Stack(
        children: <Widget>[
          Container(
            padding: const EdgeInsets.all(5),
            child: CustomPaint(
              painter: ShapingPainter(),
              child: Container(
                height: size.height / 1,
              ),
            ),
          ),
          ListView(
            children: const [
              FirstContainer(),
              SecondContainer(),
              ThirdContainer()
            ],
          ),
        ],
      ),
    );
  }
}

Therefore, we need to take a look at the file where we’ve kept all containers. Each Containers will have three rows that again will have three Column widgets each.

import 'package:flutter/material.dart';

import 'all_columns.dart';

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

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(10),
      child: Padding(
        padding: const EdgeInsets.all(10),
        child: Row(
          children: const [
            FirstColumn(),
            SecondColumn(),
            ThirdColumn(),
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(10),
      child: Padding(
        padding: const EdgeInsets.all(10),
        child: Row(
          children: const [
            FirstColumn(),
            SecondColumn(),
            ThirdColumn(),
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(10),
      child: Padding(
        padding: const EdgeInsets.all(10),
        child: Row(
          children: const [
            FirstColumn(),
            SecondColumn(),
            ThirdColumn(),
          ],
        ),
      ),
    );
  }
}

We can place each Column widget in a single file. So that it looks like the following screenshot.

Building layout in Flutter with ListView, the upper part
Building layout in Flutter with ListView, the upper part

However, that’s the upper portion of the screen. Before we take a look at the lower part, let’s take a look at the code where we’ve kept the Column widgets.

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return 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 SecondColumn extends StatelessWidget {
  const SecondColumn({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return 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,
            ),
          ),
        ),
      ],
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return 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,
            ),
          ),
        ),
      ],
    );
  }
}

As we can see, each Column widget places two child widgets in its main axis. One is Image and the other is the Text widget.

Finally, we’ve successfully built the layout model based on the principle that we can break the main widget tree in several small widget trees that will again house several different type of Widgets. Of these widgets, some are visible and some of them invisible.

Now, we can scroll down and take a look at the lower portion of the screen.

Building layout in Flutter with ListView, scrolling to the lower part
Building layout in Flutter with ListView, scrolling to the lower part

Our next challenge will be to make a more complex tree of widgets and layout based on the same principle. For this code snippet, please visit the respective GitHub repository.

Till then, stay tuned and keep reading on. Happy reading and coding Flutter.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

Courses at Educative

GitHub repository

Technical blog

Twitter

Comments

3 responses to “How we build Flutter Layout”

  1. […] widget is one of the main layout widgets that we’ll need to use very often to build any kind of Flutter […]

  2. […] How we build Flutter Layout […]

  3. […] We have seen before that the Container Widget in Flutter refers to the Layout Widgets.  […]

Leave a Reply