stewartt6Photo by Hal Gatewood on Unsplash

Layouts in Flutter: how to implement page layouts using Template Method design pattern

Building page layouts in Flutter

Bernardo Iribarne
Published in
5 min readNov 15, 2023

--

Flutter provides us a simple way to composite our widgets to build a view. It is pretty simple to add widgets and get working a beautiful view.

When your app has a few screens it is easy to maintain the widgets disposition, to change it. For example, all your screen could have a header with the screen title, a body and a footer you can have 2 common widgets, one for the Header and one for the Footer and share them between the different pages.

Page Layout: common header and footer

So, when we define a widgets disposition on the screen, we called it Page Layout: Header — Body — Footer. If you have to change the widgets disposition all you have to do is change the page layout.

Off course your App could be bigger than this, and could has different layout templates. You can define layouts regarding the type of the page, the level of a page, you have several options where you can define page layouts.

Different Page Layouts

There is a behavioral design pattern that will hep us to define our page layouts: Template method

Template Method design pattern

The idea of the Template method is to design a skeleton of an operation. That operation will have steps, and those steps call be concrete methods or abstract methods, so the class which contains the template method will be an abstract class and its subclass will define the abstract methods.

You are a programmer, so you know what is an algorithm, right? It is a sequence of steps to resolve a problem. Let’ see:

An algorithm

So the Template method will define the algorithm but some of its steps will be abstract, and there will be sub-classes which will implement them.

Template Method design pattern

Page layout implementation

We are going to define layouts, a generic layout which will use the template method design pattern and its sub-classes that will be the specific layouts, or could be an abstract class with a new template method inside.

You are free of course to build your custom Layouts, for this example, I will create one layout for the login view and another layout with an App Bar.

Examples of page layouts

Additionally, I will add a feature to each layout, I will add it a property that will represent the page that will be rendered into the layout, the green part of the graphic and I will do it through an interface. Let’s see.

Layouts

Fiona is my cat, so I choose that name because of that. FionaLayout defines the template method called build() and then it has two unimplemented “steps”, buildHeader() and buildFooter(). For example, FionaLoginLayout will draw the logo in buildHeader() and FionaAppBarPageLayout will draw the App Bar and the page title.

Layout classes

FionaLayout

import 'package:fiona_layout/src/presentation/layouts/ifiona_layout_page.dart';
import 'package:flutter/material.dart';

abstract class FionaLayout extends StatelessWidget{

IFionaLayoutPage page;

FionaLayout(this.page);

Widget build(BuildContext context){
return Scaffold(
body: Container(
child: Column(
children: [
Expanded(flex: 1, child: buildHeader(context)),
Expanded(flex: 10, child: page.buildBody(context)),
Expanded(flex: 1, child: buildFooter(context)),
],
)),
);
}

buildHeader(BuildContext context);

buildFooter(BuildContext context);
}

IFionaLayoutPage

This interface will be implemented by our pages. The idea is to decouple our layouts from the view pages, so if one page wants to have a layout, it has to implement IFionaLayoutPage.

import 'package:flutter/material.dart';

abstract class IFionaLayoutPage{

Widget buildBody(BuildContext context);
}

FionaLoginLayout

import 'package:fiona_layout/src/presentation/layouts/fiona_layout.dart';
import 'package:flutter/material.dart';

class FionaLoginLayout extends FionaLayout{

FionaLoginLayout(super.page);

@override
buildFooter(BuildContext context) {
return const Text("I'm the footer of the login page");
}

@override
buildHeader(BuildContext context) {
return const Text("I'm the header of the login page. A logo will be here");
}
}

FionaAppBarPageLayout

import 'package:fiona_layout/src/presentation/layouts/fiona_layout.dart';
import 'package:fiona_layout/src/presentation/layouts/ifiona_appbar_layout_page.dart';
import 'package:flutter/material.dart';

class FionaAppBarLayout extends FionaLayout {

IFionaAppBarLayoutPage appBarPage;

FionaAppBarLayout(this.appBarPage):super(appBarPage);

@override
buildHeader(BuildContext context) {
return Container(
child: Column(
children: [
Expanded(flex: 1, child: const Text("App bar here")),
Expanded(flex: 9, child: Text( appBarPage.getTitle() )),
],
));
}

@override
buildFooter(BuildContext context) {
return const Text( "A footer for abb bar layout here" );
}

}

As you can see here wee need additional information from the page, the title, so I extended the interfacte IFionaLayout and created a new one called IFionaAppBarLayoutPage:


import 'package:fiona_layout/src/presentation/layouts/ifiona_layout_page.dart';

abstract class IFionaAppBarLayoutPage extends IFionaLayoutPage{

String getTitle();

}

An example of how to use it

I will show you how to use the layouts we’ve created.

Our login page will look like this:


...

class LoginPage extends StatelessWidget implements IFionaLayoutPage {

@override
Widget build(BuildContext context) {
return FionaLoginLayout(this)
}

@override
Widget buildBody(BuildContext context) {

return const Text("Hi!, I'm the login body");
}


}

And a page with app bar layout will look like this:

...

class ListCustomerPage extends StatelessWidget implements IFionaAppBarLayoutPage {

@override
Widget build(BuildContext context) {
return FionaAppBarLayout(this)
}

@override
Widget buildBody(BuildContext context) {

return const Text("Hi!, I'm the custom list body page");
}

@override
String getTitle() {
return "List Customers";
}

}

Conclusion

  1. Create a Layout for each kind of page you want to have.
  2. Each layout also could have a template method to be defined in its sub-classes. This will be useful if you want to use common sections.
  3. When you need to take additional information of the page you want to show, extend the page layout interface and use it for your layout.
  4. As you can see, it is very simple, and believe me, when your app grows up and your customer says “Ey, I would like to put a logo here on all this pages” you are going to go back here and give me some claps.

Thanks for reading, Clap if you like it!

Photo by Wil Stewart on Unsplash

Let me know your comments below.

--

--

Bernardo Iribarne
Nerd For Tech

Passionate about design patterns, frameworks and well practices. Becoming a Flutter expert