Flutter - Tutorial (1) (001-092)
Flutter - Tutorial (1) (001-092)
This tutorial walks through the basics of Flutter framework, installation of Flutter SDK,
setting up Android Studio to develop Flutter based application, architecture of Flutter
framework and developing all type of mobile applications using Flutter framework.
Audience
This tutorial is prepared for professionals who are aspiring to make a career in the field of
mobile applications. This tutorial is intended to make you comfortable in getting started
with Flutter framework and its various functionalities.
Prerequisites
This tutorial is written assuming that the readers are already aware about what a
Framework is and that the readers have a sound knowledge on Object Oriented
Programming and basic knowledge on Android framework and Dart programming.
If you are a beginner to any of these concepts, we suggest you to go through tutorials
related to these first, before you start with Flutter.
All the content and graphics published in this e-book are the property of Tutorials Point (I)
Pvt. Ltd. The user of this e-book is prohibited to reuse, retain, copy, distribute or republish
any contents or a part of contents of this e-book in any manner without written consent
of the publisher.
We strive to update the contents of our website and tutorials as timely and as precisely as
possible, however, the contents may contain inaccuracies or errors. Tutorials Point (I) Pvt.
Ltd. provides no guarantee regarding the accuracy, timeliness or completeness of our
website or its contents including this tutorial. If you discover any errors on our website or
in this tutorial, please notify us at contact@tutorialspoint.com
i
Flutter
Table of Contents
About the Tutorial ............................................................................................................................................ i
Audience........................................................................................................................................................... i
Prerequisites..................................................................................................................................................... i
Table of Contents............................................................................................................................................. ii
2. FLUTTER – INSTALLATION..................................................................................................... 3
Widgets ......................................................................................................................................................... 12
Gestures ........................................................................................................................................................ 13
Layers ............................................................................................................................................................ 13
Functions ....................................................................................................................................................... 16
ii
Flutter
Introduction................................................................................................................................................... 82
iii
Flutter
iv
1. Flutter – Introduction
In general, developing a mobile application is a complex and challenging task. There are
many frameworks available to develop a mobile application. Android provides a native
framework based on Java language and iOS provides a native framework based on
Objective-C / Shift language.
However, to develop an application supporting both the OSs, we need to code in two
different languages using two different frameworks. To help overcome this complexity,
there exists mobile frameworks supporting both OS. These frameworks range from simple
HTML based hybrid mobile application framework (which uses HTML for User Interface and
JavaScript for application logic) to complex language specific framework (which do the
heavy lifting of converting code to native code). Irrespective of their simplicity or
complexity, these frameworks always have many disadvantages, one of the main
drawback being their slow performance.
In this scenario, Flutter – a simple and high performance framework based on Dart
language, provides high performance by rendering the UI directly in the operating system’s
canvas rather than through native framework.
Flutter also offers many ready to use widgets (UI) to create a modern application. These
widgets are optimized for mobile environment and designing the application using widgets
is as simple as designing HTML.
Features of Flutter
Flutter framework offers the following features to developers:
1
Flutter
Advantages of Flutter
Flutter comes with beautiful and customizable widgets for high performance and
outstanding mobile application. It fulfills all the custom needs and requirements. Besides
these, Flutter offers many more advantages as mentioned below:
Dart has a large repository of software packages which lets you to extend the
capabilities of your application.
Developers need to write just a single code base for both applications (both Android
and iOS platforms). Flutter may to be extended to other platform as well in the future.
Flutter needs lesser testing. Because of its single code base, it is sufficient if we write
automated tests once for both the platforms.
Flutter’s simplicity makes it a good candidate for fast development. Its customization
capability and extendibility makes it even more powerful.
With Flutter, developers has full control over the widgets and its layout.
Disadvantages of Flutter
Despite its many advantages, flutter has the following drawbacks in it:
Since it is coded in Dart language, a developer needs to learn new language (though
it is easy to learn).
Modern framework tries to separate logic and UI as much as possible but, in Flutter,
user interface and logic is intermixed. We can overcome this using smart coding and
using high level module to separate user interface and logic.
Flutter is yet another framework to create mobile application. Developers are having
a hard time in choosing the right development tools in hugely populated segment.
2
2. Flutter – Installation Flutter
This chapter will guide you through the installation of Flutter on your local computer in
detail.
Installation in Windows
In this section, let us see how to install Flutter SDK and its requirement in a windows
system.
Step 4: Flutter provides a tool, flutter doctor to check that all the requirement of flutter
development is met.
flutter doctor
Step 5: Running the above command will analyze the system and show its report as
shown below:
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, v1.2.1, on Microsoft Windows [Version
10.0.17134.706], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version
28.0.3)
[√] Android Studio (version 3.2)
[√] VS Code, 64-bit edition (version 1.29.1)
[!] Connected device
! No devices available
The report says that all development tools are available but the device is not connected.
We can fix this by connecting an android device through USB or starting an android
emulator.
Step 8: Start an android emulator or connect a real android device to the system.
Step 9: Install Flutter and Dart plugin for Android Studio. It provides startup template to
create new Flutter application, an option to run and debug Flutter application in the Android
studio itself, etc.,
3
Flutter
Installation in MacOS
To install Flutter on MacOS, you will have to follow the following steps:
Step 3: Update the system path to include flutter bin directory (in ~/.bashrc file).
Step 4: Enable the updated path in the current session using below command and then
verify it as well.
source ~/.bashrc
source $HOME/.bash_profile
echo $PATH
Flutter provides a tool, flutter doctor to check that all the requirement of flutter
development is met. It is similar to the Windows counterpart.
Step 8: Start an android emulator or connect a real android device to the system to
develop android application.
Step 9: Open iOS simulator or connect a real iPhone device to the system to develop iOS
application.
Step 10: Install Flutter and Dart plugin for Android Studio. It provides the startup
template to create a new Flutter application, option to run and debug Flutter application
in the Android studio itself, etc.,
4
3. Flutter – Creating Simple Application in Flutter
Android Studio
In this chapter, let us create a simple Flutter application to understand the basics of
creating a flutter application in the Android Studio.
Step 2: Create Flutter Project. For this, click File -> New -> New Flutter Project
5
Flutter
Step 3: Select Flutter Application. For this, select Flutter Application and click Next.
6
Flutter
Android Studio creates a fully working flutter application with minimal functionality.
Let us check the structure of the application and then, change the code to do our
task.
7
Flutter
lib - Main folder containing Dart code written using flutter framework
8
Flutter
Step 7: Replace the dart code in the lib/main.dart file with the below code:
import 'package:flutter/material.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child:
Text(
'Hello World',
)
),
);
}
}
Line 1: imports the flutter package, material. The material is a flutter package
to create user interface according to the Material design guidelines specified
by Android.
Line 3: This is the entry point of the Flutter application. Calls runApp function
and pass it an object of MyApp class. The purpose of the runApp function is to
attach the given widget to the screen.
9
Flutter
method is to create a part of the UI of the application. Here, build method uses
MaterialApp, a widget to create the root level UI of the application. It has three
properties - title, theme and home.
o theme is the theme of the widget. Here, we set blue as the overall color
of the application using ThemeData class and its property,
primarySwatch.
Step 8: Now, run the application using, Run -> Run main.dart
10
Flutter
11
4. Flutter – Architecture of Flutter Application Flutter
Widgets
The core concept of the Flutter framework is In Flutter, Everything is a widget. Widgets
are basically user interface components used to create the user interface of the application.
In Flutter, the application is itself a widget. The application is the top- level widget and its
UI is build using one or more children (widgets), which again build using its children
widgets. This composability feature helps us to create a user interface of any complexity.
For example, the widget hierarchy of the hello world application (created in previous
chapter) is as specified in the following diagram:
12
Flutter
MyApp is the user created widget and it is build using the Flutter native widget,
MaterialApp.
MaterialApp has a home property to specify the user interface of the home page,
which is again a user created widget, MyHomePage.
body is used to specify its main user interface and appBar is used to specify its header
user interface.
Header UI is build using flutter native widget, AppBar and Body UI is build using
Center widget.
The Center widget has a property, Child, which refers the actual content and it is build
using Text widget.
Gestures
Flutter widgets support interaction through a special widget, GestureDetector.
GestureDetector is an invisible widget having the ability to capture user interactions such
as tapping, dragging, etc., of its child widget. Many native widgets of Flutter support
interaction through the use of GestureDetector. We can also incorporate interactive feature
into the existing widget by composing it with the GestureDetector widget. We will learn
the gestures separately in the upcoming chapters.
Concept of State
Flutter widgets support State maintenance by providing a special widget, StatefulWidget.
Widget needs to be derived from StatefulWidget widget to support state maintenance and
all other widget should be derived from StatelessWidget. Flutter widgets are reactive in
native. This is similar to reactjs and StatefulWidget will be auto re- rendered whenever its
internal state is changed. The re-rendering is optimized by finding the difference between
old and new widget UI and rendering only the necessary changes.
Layers
The most important concept of Flutter framework is that the framework is grouped into
multiple category in terms of complexity and clearly arranged in layers of decreasing
complexity. A layer is build using its immediate next level layer. The top most layer is
widget specific to Android and iOS. The next layer has all flutter native widgets. The next
layer is Rendering layer, which is low level renderer component and renders everything in
the flutter app. Layers goes down to core platform specific code.
13
Flutter
Flutter offers layered design so that any layer can be programmed depending on the
complexity of the task.
14
5. Flutter – Introduction to Dart Programming Flutter
void main()
{
print("Dart language is easy to learn");
}
Dart uses var keyword to declare the variable. The syntax of var is defined below,
The final and const keyword are used to declare constants. They are defined as below:
void main() {
final a = 12;
const pi = 3.14;
print(a);
print(pi);
}
Booleans: Dart uses the bool keyword to represent Boolean values – true and false.
Lists and Maps: It is used to represent a collection of objects. A simple List can be
defined as below:
void main() {
var list = [1,2,3,4,5];
print(list);
}
15
Flutter
void main() {
var mapping = {'id': 1,'name':'Dart'};
print(mapping);
}
Dynamic: If the variable type is not defined, then its default type is dynamic. The
following example illustrates the dynamic type variable:
void main() {
dynamic name = "Dart";
print(name);
}
Loops are used to repeat a block of code until a specific condition is met. Dart supports
for, for..in , while and do..while loops.
Let us understand a simple example about the usage of control statements and loops:
void main() {
for( var i = 1 ; i <= 10; i++ ) {
if(i%2==0)
{
print(i);
}
}
}
Functions
A function is a group of statements that together performs a specific task. Let us look into
a simple function in Dart as shown here:
void main() {
add(3,4);
}
16
Flutter
The above function adds two values and produces 7 as the output.
A class is a blueprint for creating objects. A class definition includes the following:
Fields
Constructors
Functions
class Employee {
String name;
//getter method
String get emp_name {
return name;
}
//setter method
void set emp_name(String name) {
this.name = name;
}
//function definition
void result()
{
print(name);
}
}
void main() {
//object creation
Employee emp = new Employee();
emp.name="employee1";
emp.result(); //function call
}
17
6. Flutter – Introduction to Widgets Flutter
As we learned in the earlier chapter, widgets are everything in Flutter framework. We have
already learned how to create new widgets in previous chapters.
In this chapter, let us understand the actual concept behind creating the widgets and the
different type of widgets available in Flutter framework.
Let us check the Hello World application’s MyHomePage widget. The code for this purpose
is as given below:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: Text(
'Hello World',
)),
);
}
}
Note that the StatelessWidget only requires a single method build to be implemented in
its derived class. The build method gets the context environment necessary to build the
widgets through BuildContext parameter and returns the widget it builds.
In the code, we have used title as one of the constructor argument and also used Key as
another argument. The title is used to display the title and Key is used to identify the
widget in the build environment.
Here, the build method calls the build method of Scaffold, which in turn calls the build
method of AppBar and Center to build its user interface.
18
Flutter
For a better understanding, the visual representation of the same is given below:
Android specific widgets are designed in accordance with Material design guideline by
Android OS. Android specific widgets are called as Material widgets.
iOS specific widgets are designed in accordance with Human Interface Guidelines by Apple
and they are called as Cupertino widgets.
Scaffold
AppBar
19
Flutter
BottomNavigationBar
TabBar
TabBarView
ListTile
RaisedButton
FloatingActionButton
FlatButton
IconButton
DropdownButton
PopupMenuButton
ButtonBar
TextField
Checkbox
Radio
Switch
Slider
Date & Time Pickers
SimpleDialog
AlertDialog
CupertinoButton
CupertinoPicker
CupertinoDatePicker
CupertinoTimerPicker
CupertinoNavigationBar
CupertinoTabBar
CupertinoTabScaffold
CupertinoTabView
CupertinoTextField
CupertinoDialog
CupertinoDialogAction
CupertinoFullscreenDialogTransition
CupertinoPageScaffold
CupertinoPageTransition
CupertinoActionSheet
CupertinoActivityIndicator
CupertinoAlertDialog
CupertinoPopupSurface
20
Flutter
CupertinoSlider
Layout widgets
In Flutter, a widget can be created by composing one or more widgets. To compose
multiple widgets into a single widget, Flutter provides large number of widgets with layout
feature. For example, the child widget can be centered using Center widget.
We will check the layout widgets in detail in the upcoming Introduction to layout widgets
chapter.
Widget derived from StatelessWidget does not have any state information but it may
contain widget derived from StatefulWidget. The dynamic nature of the application is
through interactive behavior of the widgets and the state changes during interaction. For
example, tapping a counter button will increase / decrease the internal state of the counter
by one and reactive nature of the Flutter widget will auto re-render the widget using new
state information.
We will learn the concept of StatefulWidget widgets in detail in the upcoming State
management chapter.
Text
Text widget is used to display a piece of string. The style of the string can be set by using
style property and TextStyle class. The sample code for this purpose is as follows:
Text widget has a special constructor, Text.rich, which accepts the child of type TextSpan
to specify the string with different style. TextSpan widget is recursive in nature and it
accepts TextSpan as its children. The sample code for this purpose is as follows:
21
Flutter
Text.rich(
TextSpan(
children: <TextSpan>[
TextSpan(text: "Hello ", style: TextStyle(fontStyle:
FontStyle.italic)),
TextSpan(text: "World", style: TextStyle(fontWeight: FontWeight.bold)),
],
),
)
style, TextStyle: Specify the style of the string using TextStyle class
textAlign, TextAlign: Alignment of the text like right, left, justify, etc., using
TextAlign class
Image
Image widget is used to display an image in the application. Image widget provides
different constructors to load images from multiple sources and they are as follows:
The easiest option to load and display an image in Flutter is by including the image as
assets of the application and load it into the widget on demand.
Create a folder, assets in the project folder and place the necessary images.
flutter:
assets:
- assets/smiley.png
Image.asset('assets/smiley.png')
22
Flutter
The complete source code of MyHomePage widget of the hello world application and
the result is as shown below:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: Image.asset("assets/smiley.png")
),
);
}
23
Flutter
Icon
Icon widget is used to display a glyph from a font described in IconData class. The code
to load a simple email icon is as follows:
Icon(Icons.email)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: Icon(Icons.email)
),
);
}
}
24
Flutter
25
7. Flutter – Introduction to Layouts Flutter
Since the core concept of Flutter is Everything is widget, Flutter incorporates a user
interface layout functionality into the widgets itself. Flutter provides quite a lot of specially
designed widgets like Container, Center, Align, etc., only for the purpose of laying out the
user interface. Widgets build by composing other widgets normally use layout widgets. Let
use learn the Flutter layout concept in this chapter.
Let us learn both type of widgets and its functionality in the upcoming sections.
For example, Center widget just centers it child widget with respect to its parent widget
and Container widget provides complete flexibility to place it child at any given place inside
it using different option like padding, decoration, etc.,
Single child widgets are great options to create high quality widget having single
functionality such as button, label, etc.,
@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
),
),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
decoration: const BoxDecoration(
border: Border(
top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
26
Flutter
Here, we have used two widgets – a Container widget and a Text widget. The result of the
widget is as a custom button as shown below:
Let us check some of the most important single child layout widgets provided by Flutter:
Padding: Used to arrange its child widget by the given padding. Here, padding can
be provided by EdgeInsets class.
Align: Align its child widget within itself using the value of alignment property. The
value for alignment property can be provided by FractionalOffset class. The
FractionalOffset class specifies the offsets in terms of a distance from the top left.
Center(
child: Container(
height: 100.0,
width: 100.0,
color: Colors.yellow,
child: Align(
alignment: FractionalOffset(0.2, 0.6),
child: Container(
height: 40.0,
width: 40.0,
color: Colors.red,
),
),
),
)
FittedBox: It scales the child widget and then positions it according to the specified
fit.
AspectRatio: It attempts to size the child widget to the specified aspect ratio
27
Flutter
ConstrainedBox
Baseline
FractinallySizedBox
IntrinsicHeight
IntrinsicWidth
LiimitedBox
OffStage
OverflowBox
SizedBox
SizedOverflowBox
Transform
CustomSingleChildLayout
Our hello world application is using material based layout widgets to design the home
page. Let us modify our hello world application to build the home page using basic layout
widgets as specified below:
Container: Generic, single child, box based container widget with alignment,
padding, border and margin along with rich styling features.
Center: Simple, Single child container widget, which centers its child widget.
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
28
Flutter
color: Colors.white,
),
padding: EdgeInsets.all(25),
child: Center(child:
Text(
'Hello World',
style: TextStyle(
color: Colors.black,
letterSpacing: 0.5,
fontSize: 20,
),
textDirection: TextDirection.ltr,
),
));
}
}
Here,
Container widget is the top level or root widget. Container is configured using
decoration and padding property to layout its content.
BoxDecoration has many properties like color, border, etc., to decorate the Container
widget and here, color is used to set the color of the container.
padding of the Container widget is set by using dgeInsets class, which provides the
option to specify the padding value.
Center is the child widget of the Container widget. Again, Text is the child of the
Center widget. Text is used to show message and Center is used to center the text
message with respect to the parent widget, Container.
29
Flutter
The final result of the code given above is a layout sample as shown below:
For example, Row widget allows the laying out of its children in horizontal direction,
whereas Column widget allows laying out of its children in vertical direction. By composing
Row and Column, widget with any level of complexity can be built.
Expanded - Used to make the children of Row and Column widget to occupy the
maximum possible area.
30
Flutter
import 'package:flutter/material.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child:
Text(
'Hello World',
)),
);
}
}
31
Flutter
Here,
Now, create a new widget, ProductBox according to the specified design as shown
below:
32
Flutter
o Container
o Expanded
o Row
o Column
o Card
o Text
o Image
33
Flutter
Now, place some dummy image (see below) for product information in the assets
folder of the application and configure the assets folder in the pubspec.yaml file as
shown below:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
iPhone.png
34
Flutter
Pixel.png
Laptop.png
Tablet.png
Pendrive.png
Floppy.png
Finally, Use the ProductBox widget in the MyHomePage widget as specified below:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
shrinkWrap: true,
35
Flutter
import 'package:flutter/material.dart';
36
Flutter
),
home: MyHomePage(title: 'Product layout demo home page'),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"),
ProductBox(
name: "Pixel",
description: "Pixel is the most featureful phone ever",
price: 800,
image: "pixel.png"),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for
meeting",
price: 1500,
image: "tablet.png"),
ProductBox(
name: "Pendrive",
description: "Pendrive is useful storage medium",
price: 100,
image: "pendrive.png"),
ProductBox(
name: "Floppy Drive",
description: "Floppy drive is useful rescue storage medium",
price: 20,
image: "floppy.png"),
],
));
}
}
37
Flutter
38
Flutter
39
8. Flutter – Introduction to Gestures Flutter
Gestures are primarily a way for a user to interact with a mobile (or any touch based
device) application. Gestures are generally defined as any physical action / movement of
a user in the intention of activating a specific control of the mobile device. Gestures are
as simple as tapping the screen of the mobile device to more complex actions used in
gaming applications.
Tap: Touching the surface of the device with fingertip for a short period and then
releasing the fingertip.
Drag: Touching the surface of the device with fingertip and then moving the
fingertip in a steady manner and then finally releasing the fingertip.
Panning: Touching the surface of the device with fingertip and moving it in any
direction without releasing the fingertip.
Flutter provides an excellent support for all type of gestures through its exclusive widget,
GestureDetector. GestureDetector is a non-visual widget primarily used for detecting the
user’s gesture. To identify a gesture targeted on a widget, the widget can be placed inside
GestureDetector widget. GestureDetector will capture the gesture and dispatch multiple
events based on the gesture.
Some of the gestures and the corresponding events are given below:
Tap
o onTapDown
o onTapUp
o onTap
o onTapCancel
Double tap
o onDoubleTap
Long press
o onLongPress
40
Flutter
Vertical drag
o onVerticalDragStart
o onVerticalDragUpdate
o onVerticalDragEnd
Horizontal drag
o onHorizontalDragStart
o onHorizontalDragUpdate
o onHorizontalDragEnd
Pan
o onPanStart
o onPanUpdate
o onPanEnd
Now, let us modify the hello world application to include gesture detection feature and try
to understand the concept.
body: Center(
child: GestureDetector(
onTap: () {
_showDialog(context);
},
child: Text(
'Hello World',
)
)
),
Observe that here we have placed the GestureDetector widget above the Text
widget in the widget hierarchy, captured the onTap event and then finally shown a
dialog window.
Implement the *_showDialog* function to present a dialog when user tabs the hello
world message. It uses the generic showDialog and AlertDialog widget to create a
new dialog widget. The code is shown below:
41
Flutter
return AlertDialog(
title: new Text("Message"),
content: new Text("Hello World"),
actions: <Widget>[
new FlatButton(
child: new Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
The application will reload in the device using Hot Reload feature. Now, simply click
the message, Hello World and it will show the dialog as below:
Now, close the dialog by clicking the close option in the dialog.
42
Flutter
import 'package:flutter/material.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
43
Flutter
body: Center(
child: GestureDetector(
onTap: () {
_showDialog(context);
},
child: Text(
'Hello World',
))),
);
}
}
Finally, Flutter also provides a low-level gesture detection mechanism through Listener
widget. It will detect all user interactions and then dispatches the following events:
PointerDownEvent
PointerMoveEvent
PointerUpEvent
PointerCancelEvent
Flutter also provides a small set of widgets to do specific as well as advanced gestures.
The widgets are listed below:
IgnorePointer: Hides the widget and its children from the gesture detection
process.
AbsorbPointer: Stops the gesture detection process itself and so any overlapping
widget also can not able to participate in the gesture detection process and hence,
no event is raised.
44
9. Flutter – State Management Flutter
Managing state in an application is one of the most important and necessary process in
the life cycle of an application.
Once user is logged in, the application should persist the logged in user detail in all
the screen.
Again, when the user selects a product and saved into a cart, the cart information
should persist between the pages until the user checked out the cart.
User and their cart information at any instance is called the state of the application
at that instance.
A state management can be divided into two categories based on the duration the
particular state lasts in an application.
Ephemeral - Last for a few seconds like the current state of an animation or a single
page like current rating of a product. Flutter supports its through StatefulWidget.
app state - Last for entire application like logged in user details, cart information,
etc., Flutter supports its through scoped_model.
Let us create a widget, RatingBox with state maintenance. The purpose of the widget is to
show the current rating of a specific product. The step by step process for creating a
RatingBox widget with state maintenance is as follows:
45
Flutter
Create the user interface of the RatingBox widget in build method of _RatingBoxState.
Usually, the user interface will be done in the build method of RatingBox widget itself. But,
when state maintenance is needed, we need to build the user interface in _RatingBoxState
widget. This ensures the re-rendering of user interface whenever the state of the widget
is changed.
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
iconSize: _size,
),
),
],
);
}
46
Flutter
Here, we have used three star, created using IconButton widget and arranged it using Row
widget in a single row. The idea is to show the rating through the sequence of red stars.
For example, if the rating is two star, then first two star will be red and the last one is in
white.
void _setRatingAsOne() {
setState( () {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState( () {
_rating = 2;
});
}
void _setRatingAsThree() {
setState( () {
_rating = 3;
});
}
Here, each method sets the current rating of the widget through setState
Wire the user gesture (tapping the star) to the proper state changing method.
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
47
Flutter
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
Here, the onPressed event calls the relevant function to change the state and subsequently
change the user interface. For example, if a user clicks the third star, then
_setRatingAsThree will be called and it will change the _rating to 3. Since the state is
changed, the build method will be called again and the user interface will be build and
rendered again.
void _setRatingAsOne() {
setState( () {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState( () {
_rating = 2;
});
}
void _setRatingAsThree() {
setState( () {
_rating = 3;
});
}
48
Flutter
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
}
Let us create a new application and use our newly created RatingBox widget to show the
rating of the product.
49
Flutter
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child:
Text(
'Hello World',
)),
);
}
}
Here,
Create a ProductBox widget to list the product along with rating as specified below:
50
Flutter
padding: EdgeInsets.all(2),
height: 120,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.name,
style: TextStyle(fontWeight:
FontWeight.bold)),
Text(this.description),
Text("Price: " + this.price.toString()),
RatingBox(),
],
)))
])));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"),
ProductBox(
name: "Pixel",
description: "Pixel is the most feature phone ever",
price: 800,
image: "pixel.png"),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
51
Flutter
price: 2000,
image: "laptop.png"),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for
meeting",
price: 1500,
image: "tablet.png"),
ProductBox(
name: "Pendrive",
description: "Pendrive is useful storage medium",
price: 100,
image: "pendrive.png"),
ProductBox(
name: "Floppy Drive",
description: "Floppy drive is useful rescue storage
medium",
price: 20,
image: "floppy.png"),
],
));
}
}
import 'package:flutter/material.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
52
Flutter
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"),
ProductBox(
name: "Pixel",
description: "Pixel is the most featureful phone ever",
price: 800,
image: "pixel.png"),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for
meeting",
price: 1500,
image: "tablet.png"),
ProductBox(
name: "Pendrive",
description: "iPhone is the stylist phone ever",
price: 100,
image: "pendrive.png"),
ProductBox(
name: "Floppy Drive",
description: "iPhone is the stylist phone ever",
price: 20,
image: "floppy.png"),
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"),
ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"),
],
));
}
}
53
Flutter
int _rating = 0;
void _setRatingAsOne() {
setState( () {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState( () {
_rating = 2;
});
}
void _setRatingAsThree() {
setState( () {
_rating = 3;
});
}
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3 ? Icon(Icons.star, size: _size,) :
Icon(Icons.star_border, size: _size,)),
54
Flutter
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
}
55
Flutter
Finally, run the application and see the State management - Product list page
Results as shown here:
56
Flutter
Clicking the rating star will update the rating of the product. For example, setting 2-star
rating for iPhone will display the rating as below:
Model
Model encapsulates the state of an application. We can use as many Model (by inheriting
Model class) as needed to maintain the application state. It has a single method,
notifyListeners, which needs to be called whenever the Model state changes.
notifyListeners will do necessary things to update the UI.
57
Flutter
notifyListeners();
}
}
ScopedModel
ScopedModel is a widget, which holds the given model and then passes it to all the
descendant widget if requested. If more than one model is needed, then we need to nest
the ScopedModel.
Single model
ScopedModel<Product>(
model: item,
child: AnyWidget()
)
Multiple model
ScopedModel<Product>(
model: item1,
child: ScopedModel<Product>(
model: item2,
child: AnyWidget(),
),
)
ScopedModel.of is a method used to get the model underlying the ScopedModel. It can be
used when no UI changes are necessary even though the model is going to change. The
following will not change the UI (rating) of the product.
ScopedModel.of<Product>(context).updateRating(2);
58
Flutter
ScopedModelDescendant
ScopedModelDescendant is a widget, which gets the model from the upper level widget,
ScopedModel and build its user interface whenever the model changes.
ScopedModelDescendant has a two properties – builder and child. child is the UI part
which does not change and will be passed to builder. builder accepts a function with
three arguments:
return ScopedModelDescendant<ProductModel>(
builder: (context, child, cart) => { ... Actual UI ... },
child: PartOfTheUI(),
);
Let us change our previous sample to use the scoped_model instead of StatefulWidget
Replace the default startup code (main.dart) with our product_state_app code.
Copy the assets folder from product_nav_app to product_rest_app and add assets
inside the pubspec.yaml file
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
dependencies:
scoped_model: ^1.0.1
Here, you should use the latest version of the http package
Click Get dependencies option. Android studio will get the package from Internet
and properly configure it for the application.
59
Flutter
Replace the default startup code (main.dart) with our startup code.
import 'package:flutter/material.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child:
Text(
'Hello World',
)),
);
}
}
import 'package:scoped_model/scoped_model.dart';
import 'package:scoped_model/scoped_model.dart';
60
Flutter
notifyListeners();
}
}
Here, we have used notifyListeners to change the UI whenever the rating is changed.
Let us write a method getProducts in the Product class to generate our dummy
product records.
items.add(Product(
"Pixel",
"Pixel is the most feature-full phone ever",
800,
"pixel.png", 0));
items.add(Product(
"Laptop",
"Laptop is most productive development tool",
2000,
"laptop.png", 0));
items.add(Product(
"Tablet",
"Tablet is the most useful device ever for meeting",
1500,
"tablet.png", 0));
items.add(Product(
"Pendrive",
"Pendrive is useful storage medium",
100,
"pendrive.png", 0));
items.add(Product(
61
Flutter
"Floppy Drive",
"Floppy drive is useful rescue storage medium",
20,
"floppy.png", 0));
return items;
}
import product.dart in main.dart
import 'Product.dart';
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (item.rating >= 1
? Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)),
color: Colors.red[500],
onPressed: () => this.item.updateRating(1),
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (item.rating >= 2
? Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
62
Flutter
)),
color: Colors.red[500],
onPressed: () => this.item.updateRating(2),
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (item.rating >= 3
? Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)),
color: Colors.red[500],
onPressed: () => this.item.updateRating(3),
iconSize: _size,
),
),
],
);
}
}
Let us modify our ProductBox widget to work with Product, ScopedModel and
ScopedModelDescendant class.
63
Flutter
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name,
style:
TextStyle(fontWeight:
FontWeight.bold)),
Text(this.item.description),
Text("Price: " +
this.item.price.toString()),
ScopedModelDescendant<Product>(
builder: (context, child, item) {
return RatingBox(item: item);
})
],
))))
]),
));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Navigation")),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ProductBox(item: items[index]);
},
));
}
}
Product.dart
import 'package:scoped_model/scoped_model.dart';
64
Flutter
void cn
"Laptop is most productive development tool",
2000,
"laptop.png", 0));
items.add(Product(
"Tablet"cnvn,
"Tablet is the most useful device ever for meeting",
1500,
"tablet.png", 0));
items.add(Product(
"Pendrive",
"Pendrive is useful storage medium",
100,
"pendrive.png", 0));
items.add(Product(
"Floppy Drive",
"Floppy drive is useful rescue storage medium",
20,
"floppy.png", 0));
return items;
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import 'Product.dart';
65
Flutter
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Product state demo home page'),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Navigation")),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ProductBox(item: items[index]);
},
));
}
}
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (item.rating >= 1
? Icon(
Icons.star,
size: _size,
)
: Icon(
66
Flutter
Icons.star_border,
size: _size,
)),
color: Colors.red[500],
onPressed: () => this.item.updateRating(1),
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (item.rating >= 2
? Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)),
color: Colors.red[500],
onPressed: () => this.item.updateRating(2),
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (item.rating >= 3
? Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)),
color: Colors.red[500],
onPressed: () => this.item.updateRating(3),
iconSize: _size,
),
),
],
);
}
}
67
Flutter
height: 140,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: ScopedModel<Product>(
model: this.item,
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name,
style:
TextStyle(fontWeight:
FontWeight.bold)),
Text(this.item.description),
Text("Price: " +
this.item.price.toString()),
ScopedModelDescendant<Product>(
builder: (context, child, item) {
return RatingBox(item: item);
})
],
))))
]),
));
}
}
Finally, compile and run the application to see its result. It will work similar to previous
example except the application uses the scoped_model concept.
MaterialPageRoute
MaterialPageRoute is a widget used to render its UI by replacing the entire screen with a
platform specific animation.
Here, builder will accepts a function to build its content by suppling the current context of
the application.
Navigation.push
68
Flutter
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Widget()),
);
Navigation.pop
Navigation.pop is used to navigate to previous screen.
Navigator.push(context);
Copy the assets folder from product_nav_app to product_state_app and add assets
inside the pubspec.yaml file
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
Replace the default startup code (main.dart) with our startup code.
import 'package:flutter/material.dart';
69
Flutter
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child:
Text(
'Hello World',
)),
);
}
}
class Product {
final String name;
final String description;
final int price;
final String image;
Let us write a method getProducts in the Product class to generate our dummy
product records.
items.add(Product(
"Pixel",
"Pixel is the most feature-full phone ever",
800,
"pixel.png"));
items.add(Product(
"Laptop",
"Laptop is most productive development tool",
2000,
"laptop.png"));
items.add(Product(
"Tablet",
"Tablet is the most useful device ever for meeting",
1500,
"tablet.png"));
items.add(Product(
"Pendrive",
"Pendrive is useful storage medium",
70
Flutter
100,
"pendrive.png"));
items.add(Product(
"Floppy Drive",
"Floppy drive is useful rescue storage medium",
20,
"floppy.png"));
return items;
}
import product.dart in main.dart
import 'Product.dart';
void _setRatingAsOne() {
setState(() {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState(() {
_rating = 2;
});
}
void _setRatingAsThree() {
setState(() {
_rating = 3;
});
}
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
71
Flutter
72
Flutter
Let us modify our ProductBox widget to work with our new Product class.
Let us rewrite our MyHomePage widget to work with Product model and to list all
products using ListView.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Navigation")),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
73
Flutter
return GestureDetector(
child: ProductBox(item: items[index]),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductPage(item:
items[index]),
),
);
},
);
},
));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.item.name),
),
body: Center(
child: Container(
padding: EdgeInsets.all(0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset("assets/appimages/" +
this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name,
style: TextStyle(fontWeight:
FontWeight.bold)),
Text(this.item.description),
Text("Price: " +
this.item.price.toString()),
RatingBox(),
74
Flutter
],
)))
]),
),
),
);
}
}
import 'package:flutter/material.dart';
class Product {
final String name;
final String description;
final int price;
final String image;
items.add(Product(
"Pixel", "Pixel is the most featureful phone ever", 800,
"pixel.png"));
items.add(Product(
"Tablet",
"Tablet is the most useful device ever for meeting",
1500,
"tablet.png"));
items.add(Product(
"Pendrive", "iPhone is the stylist phone ever", 100,
"pendrive.png"));
items.add(Product(
"Floppy Drive", "iPhone is the stylist phone ever", 20,
"floppy.png"));
items.add(Product(
"iPhone", "iPhone is the stylist phone ever", 1000,
"iphone.png"));
return items;
}
}
75
Flutter
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Navigation")),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return GestureDetector(
child: ProductBox(item: items[index]),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductPage(item:
items[index]),
),
);
},
);
},
));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
76
Flutter
title: Text(this.item.name),
),
body: Center(
child: Container(
padding: EdgeInsets.all(0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset("assets/appimages/" + this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name,
style: TextStyle(fontWeight:
FontWeight.bold)),
Text(this.item.description),
Text("Price: " +
this.item.price.toString()),
RatingBox(),
],
)))
]),
),
),
);
}
}
void _setRatingAsOne() {
setState(() {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState(() {
_rating = 2;
});
}
void _setRatingAsThree() {
setState(() {
77
Flutter
_rating = 3;
});
}
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 1
? Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 2
? Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_rating >= 3
? Icon(
Icons.star,
size: _size,
)
78
Flutter
: Icon(
Icons.star_border,
size: _size,
)),
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
}
79
Flutter
Run the application and click any one of the product item. It will show the relevant
details page. We can move to home page by clicking back button. The product list
page and product details page of the application are shown as follows:
80
Flutter
81
10. Flutter – Animation Flutter
Introduction
Animation is a process of showing a series of images / picture in a particular order within
a specific duration to give an illusion of movement. The most important aspects of the
animation are as follows:
Animation have two distinct values: Start value and End value. The animation starts
from Start value and goes through a series of intermediate values and finally ends at
End values. For example, to animate a widget to fade away, the initial value will be
the full opacity and the final value will be the zero opacity.
The intermediate values may be linear or non-linear (curve) in nature and it can be
configured. Understand that the animation works as it is configured. Each
configuration provides a different feel to the animation. For example, fading a widget
will be linear in nature whereas bouncing of a ball will be non-linear in nature.
The duration of the animation process affects the speed (slowness or fastness) of the
animation.
The ability to control the animation process like starting the animation, stopping the
animation, repeating the animation to set number of times, reversing the process of
animation, etc.,
In Flutter, animation system does not do any real animation. Instead, it provides only
the values required at every frame to render the images.
Animation
Generates interpolated values between two numbers over a certain duration. The most
common Animation classes are:
82
Flutter
Here, controller controls the animation and duration option controls the duration of
the animation process. vsync is a special option used to optimize the resource used
in the animation.
CurvedAnimation
Similar to AnimationController but supports non-linear animation. CurvedAnimation can
be used along with Animation object as below:
Tween<T>
Derived from Animatable<T> and used to generate numbers between any two numbers
other than 0 and 1. It can be used along with Animation object by using animate method
and passing actual Animation object.
Here, controller is the actual animation controller. curve provides the type of non-linearity
and the customTween provides custom range from 0 to 255.
Define and start the animation controller in the initState of the StatefulWidget.
Add animation based listener, addListener to change the state of the widget
83
Flutter
child: Container(
height: animation.value,
width: animation.value,
child: <Widget>,
)
Working Application
Let us write a simple animation based application to understand the concept of animation
in Flutter framework.
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
import 'package:flutter/material.dart';
84
Flutter
@override
void initState() {
super.initState();
controller = AnimationController(duration: const Duration(seconds: 10),
vsync: this);
animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller);
controller.forward();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
Here,
85
Flutter
: super(key: key);
86
Flutter
value, animation.value to set the opacity of the child widget. In effect, the widget
will animate the child widget using opacity concept.
Finally, create the MyHomePage widget and use the animation object to animate
any of its content.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
FadeTransition(child: ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"),
opacity: animation),
MyAnimatedWidget(child: ProductBox(
name: "Pixel",
description: "Pixel is the most featureful phone ever",
price: 800,
image: "pixel.png"),
animation: animation),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for
meeting",
price: 1500,
image: "tablet.png"),
ProductBox(
name: "Pendrive",
description: "Pendrive is useful storage medium",
price: 100,
image: "pendrive.png"),
ProductBox(
name: "Floppy Drive",
description: "Floppy drive is useful rescue storage
medium",
price: 20,
image: "floppy.png"),
],
87