Layouts in Flutter: how to implement page layouts using Template Method design pattern
Building page layouts in Flutter
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.
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.
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:
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.
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.
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.
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
- Create a Layout for each kind of page you want to have.
- 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.
- 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.
- 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!
Let me know your comments below.