Flutter Lab Manual(R22) (1)
Flutter Lab Manual(R22) (1)
UGC AUTONOMOUS
Kandlakoya(V), Medchal Road, Hyderabad – 501 401
Accredited by NBA and NAAC with A Grade
Approved by AICTE, New Delhi and Affiliated to JNTU, Hyderabad
UI DESIGN-FLUTTER
FLUTTER LAB MANUAL (R22)
COURSE CODE: 22AM507PC
Prepared by:
Mr. G. Aravind
Mr. V.N.V Sri Harsha
Assistant Professor
LIST OF EXPERIMENTS:
TEXT BOOK:
REFERENCE BOOKS:
2. Rap Payne, Beginning App Development with Flutter: Create Cross-Platform Mobile
Apps, 1stedition, Apress.
3. Frank Zammetti, Practical Flutter: Improve your Mobile Development with Google’s
Latest Open-Source SDK, 1stedition, Apress
Lab Session 1:
To install Flutter and the Dart SDK, you can follow these steps:
a) Download Flutter: Visit the Flutter website's Get Started page and download the
Flutter SDK for your operating system (Windows, macOS, or Linux).
b) Extract the Flutter SDK: After downloading, extract the contents of the
compressed file to a location on your computer where you want to store the Flutter
SDK. For example, you can extract it to C:\flutter on Windows, /Users/<your-
username>/flutter on macOS, or ~/flutter on Linux.
c) Add Flutter to your PATH: Update your system's PATH variable to include the
Flutter bin directory. This step allows you to execute Flutter commands from any
directory in your terminal or command prompt. The precise steps for updating the
PATH vary depending on your operating system.
Windows:
From the Start search bar, type 'env' and select 'Edit the system environment variables'. Click on
'Environment Variables'.
Under 'System Variables', find the 'Path' variable, select it, and click 'Edit'.
Click 'New' and add the path to the bin directory inside the Flutter directory (e.g., C:\flutter\bin).
Click 'OK' on all open dialogs to save your changes.
Verify the Flutter installation: Open a new terminal window, and run the following command to
verify that Flutter is properly installed:
flutter --version
This command should display the Flutter version and other relevant information if the installation
was successful.
Install Flutter dependencies: Depending on your development environment, you may need to
install additional dependencies, such as Android Studio to fully set up your Flutter development
environment.
Download Dart SDK (if not bundled with Flutter): Flutter comes with the Dart SDK bundled, so
if you've installed Flutter, you should have the Dart SDK as well. However, if you need to install
Dart separately; you can download it from the Dart "SDK archive".
b) Write a simple dart program to understand the language basics
// Define a main function, which is the entry point of a Dart program.
void main() {
// Variables and data types
int myNumber = 10;
double myDouble = 3.14;
String myString = 'Hello World';
bool myBool = true;
// Printing variables
print('My number is: $myNumber');
print('My double is: $myDouble');
print('My string is: $myString');
print('My boolean is: $myBool');
// Basic arithmetic operations
int result = myNumber + 5;
print('Result of addition: $result');
// Conditional statements
if (myBool)
{
print('myBool is true');
}
else
{
print('myBool is false');
}
// Loops
for (int i = 0; i < 5; i++)
{
print('Iteration $i');
}
// Lists
List<int> numbers = [1, 2, 3, 4, 5];
print('First element of the list: ${numbers[0]}');
print('Length of the list: ${numbers.length}');
// Maps
Map<String, int> ages = { 'Kiran': 30,'Raj': 25,'Alekya': 35,};
print('Kiran\'s age: ${ages['Kiran']}' );
}
OUTPUT:
VIVA QUESTIONS AND ANSWERS
1) What is Flutter?
2) What is Dart?
It is open-source and developed by Google in 2011. The purpose of Dart programming is to create
frontend user interfaces for the web and mobile apps.
Dart is a client-optimized language for developing fast apps on any platform. Its goal is to offer
the most productive programming language for multi-platform development.
Flutter widgets are built using a modern framework that takes inspiration from React. The central
idea is that you build your UI out of widgets. Widgets describe what their view should look like
given their current configuration and state. When a widget’s state changes, the widget rebuilds its
description, which the framework diffs against the previous description to determine the minimal
changes needed in the underlying render tree to transition from one state to the next.
It is the project's configuration file that will use a lot during working with the Flutter project. It
allows you how your application works. It also allows us to set the constraints for the app. This
file contains:
o Project general settings such as name, description, and version of the project.
o Project dependencies.
o Project assets (e.g., images, audio, etc.).
Lab Session 2:
Layout Widgets:
Container: A versatile widget that can contain other widgets and provides options for alignment,
padding, margin, and decoration.
Row and Column: Widgets that arrange their children in a horizontal or vertical line respectively.
Stack: Allows widgets to be stacked on top of each other, enabling complex layouts.
List View and Grid View: Widgets for displaying a scrollable list or grid of children, with support
for various layouts and scrolling directions.
Scaffold: Implements the basic material design layout structure, providing app bars, drawers, and
floating action buttons.
Text: Displays a string of text with options for styling such as font size, color, and alignment.
Rich Text: Allows for more complex text styling and formatting, including different styles within
the same text span.
Text Style: A class for defining text styles that can be applied to Text widgets.
Input Widgets:
Text Field: A widget for accepting user input as text, with options for customization and validation.
Checkbox and Radio: Widgets for selecting from a list of options, either through checkboxes or
radio buttons.
Dropdown Button: Provides a dropdown menu for selecting from a list of options.
Button Widgets:
Elevated Button and Text Button: Widgets for displaying buttons with different styles and
customization options.
Icon Button: A button widget that displays an icon and responds to user taps.
Gesture Detector: A versatile widget that detects gestures such as taps, swipes, and drags, allowing
for custom interactions
Image and Icon Widgets:
Image: Widget for displaying images from various sources, including assets, network URLs, and
memory.
Navigation Widgets:
Navigator: Manages a stack of route objects and transitions between different screens or pages in the
app.
Page Route Builder: A customizable widget for building page transitions and animations.
Animation Widgets:
Animated Container: An animated version of the Container widget, with support for transitioning
properties over a specified duration.
Animated Opacity, Animated Positioned, Animated Builder: Widgets for animating opacity,
position, and custom properties respectively.
App Bar: A material design app bar that typically contains a title, leading and trailing widgets, and
actions.
Bottom Navigation Bar: Provides a navigation bar at the bottom of the screen for switching betwee
different screens or tabs.
Card: Displays content organized in a card-like structure with optional elevation and padding.
Cupertino Text Field: A text field widget with the iOS style.
These are just a few examples of the many widgets available in Flutter. Each widget comes with its
set of properties and customization options, allowing developers to create highly customizable and
responsive user interfaces.
b) User implement different layout structures using Row, Column, and
Stack widgets
Row widgets:
import 'package:flutter/material.dart';
void main() { runApp(MyApp()); }
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage()
);
}
}
Output:
Column Widget
import 'package:flutter/material.dart';
Output:
Stack Widget
import 'package:flutter/material.dart';
Output:
VIVA QUESTIONS AND ANSWERS
A package is a group of similar types of classes, interfaces, and sub-packages. The packages and
plugins help us to build the app without having to develop everything from packages. In Flutter,
it allows you to import new widgets or functionality into the app.
When you build the Flutter app the first time, it will take a longer time. It is because the Flutter
built the device-specific APK or IPA file. Thus, the Gradle and Xcode are used to build the file,
taking a long time.
Android: This folder holds a complete Android project. It is used when you create the Flutter
application for Android. When the Flutter code is compiled into the native code, it will get
injected into this Android project, so that the result is a native Android application.
iOS: This folder holds a complete Mac project. It is used when you build the Flutter application
for iOS. It is similar to the Android folder, which is used when developing an app for Android.
When the Flutter code is compiled into the native code, it will get injected into this iOS project,
so that the result is a native iOS application.
The hot reload feature allows you to quickly and easily perform an experiment in the project. It
helps to build UI, add new features, fix bugs, and make app development fast. To perform hot
reloading of a Flutter app, do the following steps:
Today, many organizations use Flutter for building the app. Some of the most popular app built
on Flutter are as follows:
o Google Ads
o Reflectly
o Alibaba
o Birch Finance
o Coach Yourself
Lab Session 3:
Output::
b) Implement media queries and breakpoints for responsiveness
],
),
],
),
);
}
}
OUTPUT:
VIVA QUESTIONS AND ANSWERS
The most used and popular database packages used in the Flutter are as follows:
The Container in Flutter is a parent widget that can contain multiple child widgets and manage
them efficiently through width, height, padding, background color, etc. If we have a widget that
needs some background styling may be a color, shape, or size constraints, we may wrap it in a
container widget.
The SizedBox widget in Flutter is a box that comes with a specified size. Unlike Container, it
does not allows us to set color or decoration for the widget.
The main reason behind this is that the StatefulWidget uses a separate State class without
building a method inside its body. It means all fields inside a Widget are immutable and includes
all its sub-classes.
On the other hand, the StatelessWidget has its build and associated methods inside its body. It is
due to the nature of StatelessWidget, which is rendered completely on the screen using the
provided info. It also doesn't allow any future changes in its State information.
The Flutter tooling supports three modes while compiling the application. These compilation
modes can be chosen by depending on where we are in the development cycle. The name of the
modes are:
o Debug
o Profile
o Release
Lab Session 4:
void main() {
runApp(MyApp());
}
Output::
b) Implement navigation with named routes
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
Navigator.pushNamed(context, '/third');
},
child: Text('Go to Third Screen'),
),
),
);
}
}
Output::
VIVA QUESTIONS AND ANSWERS
WidgetsApp:- A convenience class that wraps several widgets that are commonly required for an
application.
One of the primary roles that WidgetsApp provides is binding the system back button to pop the
Navigator or quitting the application.
MaterialApp:- A convenience widget that wraps several widgets that are commonly required for
material design applications.
It builds upon a WidgetsApp by adding material-design specific functionality, such as
AnimatedTheme and GridPaper.
DevTools in Flutter are a set of tools used for performance management and debugging.
With these tools, you can inspect the UI layout, diagnose the UI performance issues, perform
source-level debugging, view general log & diagnostics information, and more. This tool is still
in preview release but you can test the alpha version of this tool by clicking the “beaker” icon
in the upper-right corner of DevTools.
The Flex widget allows you to control the axis along which the children are placed
(horizontal or vertical). This is referred to as the main axis. If you know the main axis in
advance, then consider using a Row (if it’s horizontal) or Column (if it’s vertical) instead,
because that will be less verbose.
4) What is LayoutBuilder?
LayoutBuilder Widget is similar to the Builder widget except that the framework calls the
builder function at layout time and provides the parent widget’s constraints. This is useful
when the parent constrains the child’s size and doesn’t depend on the child’s intrinsic size.
Stateless Widgets:
Definition: Stateless widgets are widgets that do not have any mutable state. Once created, their
properties (configuration) cannot change.
Characteristics:
They are immutable and lightweight.
They only depend on their configuration and the build context provided during
construction. Their appearance (UI) is purely a function of their configuration.
They are ideal for UI elements that do not change over time, such as static text labels, icons,
or simple buttons.
import 'package:flutter/material.dart';
void main()
{
runApp(MyApp());
}
const CardItem({
Key key,
@required this.title,
@required this.subtitle,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: ListTile(
title: Text(title),
subtitle: Text(subtitle),
leading: CircleAvatar(
child: Text('${title.substring(0, 1)}'),
),
onTap: () {
// Handle card tap
},
),
);
}
Output::
b) Implement state management using set state and provider
Stateful Widgets:
Definition: Stateful widgets are widgets that maintain state, allowing them to change and
update over time in response to user actions, network events, or other factors.
Characteristics:
They have an associated mutable state that can change during the widget's lifetime.
The state is stored in a separate class that extends State and is associated with the
stateful widget. Changes to the state trigger a rebuild of the widget's UI, allowing
dynamic updates.
They are ideal for UI elements that need to change or react to user interactions, such
as input forms, animations, or scrollable lists.
import 'package:flutter/material.dart';
@override
Widget build(BuildContext context) { return
Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ Text(
'Counter:',
style: TextStyle(fontSize: 24),
),
Text( '$_counter',
style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment', child:
Icon(Icons.add),
),
);
}
}
Output::
Stateful widgets are composed of two classes: the stateful widget itself (which extends
StatefulWidget) and its corresponding state class (which extends State). The state class is
responsible for maintaining the widget's mutable state and updating the UI accordingly via
the setState() method.
stateless widgets are static and immutable, while stateful widgets are dynamic and can
change over time by managing their internal state. Understanding the difference between
these two types of widgets is essential for designing and building efficient and responsive
Flutter UIs.
import 'package:flutter/material.dart';
void main()
{ runApp(MyApp());
}
Output::
State Management using provider package:
// main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'provider/movie_provider.dart';
import 'screens/home_screen.dart';
void main() {
runApp(ChangeNotifierProvider<MovieProvider>(
child: const MyApp(),
create: (_) => MovieProvider(), // Create a new ChangeNotifier object
));
}
return MaterialApp(
// Remove the debug banner
debugShowCheckedModeBanner: false, title:
'State Management using provider', theme:
ThemeData(
primarySwatch: Colors.indigo,
),
Create a provider folder and create movie_provider.dart inside the provider folder
// provider/movie_provider.dart import
'package:flutter/material.dart'; import 'dart:math';
import '../models/movie.dart';
// A list of movies
final List<Movie> initialData = List.generate( 50,
(index) => Movie(
title: "Moview $index",
runtime: "${Random().nextInt(100) + 60} minutes"));
// screens/home_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../provider/movie_provider.dart';
import 'my_list_screen.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
var movies = context.watch<MovieProvider>().movies; var
myList = context.watch<MovieProvider>().myList;
return Scaffold( appBar: AppBar(
title: const Text('State Management using provider'),
),
body: Padding(
padding: const EdgeInsets.all(15), child:
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ ElevatedButton.icon(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const MyListScreen(),
),
);
},
icon: const Icon(Icons.favorite), label: Text(
"Go to my list (${myList.length})", style: const
TextStyle(fontSize: 24),
),
style: ElevatedButton.styleFrom(
primary:Colors.red,
padding: const EdgeInsets.symmetric(vertical: 20)),
),
const SizedBox( height: 15,
),
Expanded(
child: ListView.builder( itemCount:
movies.length, itemBuilder: (_, index) {
final currentMovie = movies[index]; return
Card(
key: ValueKey(currentMovie.title), color:
Colors.amberAccent.shade100, elevation: 4,
child: ListTile(
title: Text(currentMovie.title), subtitle:
Text(currentMovie.runtime ?? 'No information'),
trailing: IconButton(
icon: Icon( Icons.favorite,
color: myList.contains(currentMovie)
? Colors.red
: Colors.white,
size: 30,
),
onPressed: () {
if (!myList.contains(currentMovie)) { context
.read<MovieProvider>()
.addToList(currentMovie);
} else { context
.read<MovieProvider>()
.removeFromList(currentMovie);
}
},
),
),
);
}),
),
],
),
),
);
}
}
// screens/my_list_screen.dart
import 'package:flutter/material.dart'; import
'package:provider/provider.dart';
import '../provider/movie_provider.dart'; class
MyListScreen extends StatefulWidget {
const MyListScreen({Key? key}) : super(key: key);
@override
State<MyListScreen> createState() => _MyListScreenState();
}
return Card(
key: ValueKey(currentMovie.title), elevation: 4,
child: ListTile(
title: Text(currentMovie.title),
subtitle: Text(currentMovie.runtime ?? ''), trailing:
TextButton(
child: const Text( 'Remove',
style: TextStyle(color: Colors.red),
),
onPressed: () {
context.read<MovieProvider>().removeFromList(currentMovie);
},
),
),
);
}),
);
}
}
Output::
VIVA QUESTIONS AND ANSWERS
dynamic: can change the TYPE of the variable, & can change the VALUE of the variable later in
code.
var: can’t change TYPE of the variable, but can change VALUE of the variable later in code.
final: can’t change TYPE of the variable, & can’t change VALUE of the variable later in code.
3) What is State?
A widget’s “state” is the information or data that it holds over time. It determines how the widget
should be displayed on the screen. When a widget’s state changes, it is rebuilt to reflect the
updated state. The result is a dynamic, responsive user interface. In simple words, State is the data
that changes and updates the widgets on the app’s UI.
Flutter is built with C, C++, Dart, and Skia (a 2D rendering engine). See this architecture diagram
for a better picture of the main components. For a more detailed description of the layered
architecture of Flutter, read the architectural overview.
The AOT-compiled code runs inside an efficient Dart runtime that enforces the sound Dart type
system and manages memory using fast object allocation and a generational garbage collector.
Lab Session 6:
@override
Widget build(BuildContext context) { return
ElevatedButton(
onPressed: onPressed, child:
Text(text!),
);
}
}
void main()
{
runApp(MyApp());
}
),
),
),
home: HomePage(),
);
}
}
Output:
VIVA QUESTIONS AND ANSWERS
Extension methods, introduced in Dart 2.7, are a way to add functionality to existing libraries.
You might use extension methods without even knowing it. For example, when you use code
completion in an IDE, it suggests extension methods alongside regular methods.
Concurrency is the execution of several instruction sequences at the same time. It involves
performing more than one task simultaneously. Dart uses Isolates as a tool for doing work in
parallel.
Every webpage can be considered an object and it exists inside a browser window. We can access
the webpage using the web browser and it needed to be connected to the internet. The DOM is the
acronym for the Document object model. A Document object denotes the HTML document that
is displayed in that window.
Lab Session 7:
import'package:flutter/material.dart';
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){returnMateri
alApp(
title:'FormExample',
theme:ThemeData(primarySwatch:Colors.blue,
),
home:FormPage(),
);
}
}
classFormPageextendsStatefulWidget{@override
_FormPageStatecreateState()=>_FormPageState();
}
class_FormPageStateextendsState<FormPage>{final_formKey =
GlobalKey<FormState>();
String_name;String_email;
bool_subscribeToNewsletter=false;String
_selectedCountry = 'USA';
@override
Widgetbuild(BuildContextcontext){returnScaffo
ld(
appBar:AppBar(
title:Text('FormExample'),
),
body:Padding(
padding:EdgeInsets.all(20.0),child:Form(
key:_formKey,child:Column(
crossAxisAlignment:CrossAxisAlignment.start,children:<Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Name'),onSaved:
(value) {
_name=value;
},
),
SizedBox(height:20),TextFormField(
decoration: InputDecoration(labelText: 'Email'),onSaved:
(value) {
_email=value;
},
),
SizedBox(height:20),Row(
children:<Widget>[ Checkbox(
value:_subscribeToNewsletter,onChanged:
(value) {setState((){
_subscribeToNewsletter=value;
});
},
),
Text('SubscribetoNewsletter'),
],
),
SizedBox(height:20),Row(
children:<Widget>[
Text('Country:'),SizedBox(width:20),Dropd
ownButton<String>(value:_selectedCountr
y,onChanged: (value) {
setState((){
_selectedCountry=value;
});},
items:<String>['USA','Canada','UK','Australia']
.map<DropdownMenuItem<String>>((String value)
{returnDropdownMenuItem<String>(
value:value,child:Text(value),
);
}).toList(),
),
],
),
SizedBox(height:20),ElevatedButton(onP
ressed: () {
_formKey.currentState.save();
//Submittheformdataprint('Name:$_name');print('Email:$_email');
print('SubscribetoNewsletter:$_subscribeToNewsletter');
print('Country:$_selectedCountry');
},
child:Text('Submit'),
),
],
),
),
),
);
}
}
Output:
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){returnMateri
alApp(
home:Scaffold(appBar:AppBar(
title:Text('FormExample'),
),
body:SingleChildScrollView(padding:EdgeIns
ets.all(16),child:FormWidget(),
),
),
);
}
}
classFormWidgetextendsStatefulWidget{@override
_FormWidgetStatecreateState()=>_FormWidgetState();
}
class_FormWidgetStateextendsState<FormWidget>{
final_formKey=GlobalKey<FormState>();String_na
me;
String_email;String_password;String_
phone;String_address;
@override
Widgetbuild(BuildContextcontext){returnForm(
key:_formKey,child:Column(
crossAxisAlignment:CrossAxisAlignment.start,children:
<Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Name'),validator:
(value) {
if(value.isEmpty){
return'Pleaseenteryourname';
}
returnnull;
},
onSaved:(value)=>_name=value,
),
SizedBox(height:16),TextFormField(
decoration:InputDecoration(labelText:'Email'),
keyboardType:TextInputType.emailAddress,validator:
(value) {
if(value.isEmpty){
return'Pleaseenteryouremail';
}
},
onSaved:(value)=>_email=value,
),
SizedBox(height:16),TextFormField(
decoration:InputDecoration(labelText:'Password'),
obscureText:true,validator:(value){
if(value.isEmpty){
return'Pleaseenterapassword';
}
//Addmorecomplexpasswordvalidationlogicifneededreturnnu
ll;
},
onSaved:(value)=>_password=value,
),
SizedBox(height:16),TextFormField(
decoration:InputDecoration(labelText:'Phone'),
keyboardType:TextInputType.phone,validator:
(value) {
if(value.isEmpty){
return'Pleaseenteryourphonenumber';
}
},
onSaved:(value)=>_phone=value,
),
SizedBox(height:16),TextFormField(
decoration: InputDecoration(labelText:
'Address'),maxLines:3,
validator:(value){
if(value.isEmpty){
return'Pleaseenteryouraddress';
}
returnnull;
},
onSaved:(value)=>_address=value,
),
SizedBox(height:16),ElevatedButton(onPr
essed:_submitForm,child:Text('Submit'),
),
],
),
);
}
void_submitForm(){
if(_formKey.currentState.validate()){
_formKey.currentState.save();
//Performformsubmissionwiththesavedformdataprint('Forms
ubmitted:');
print('Name:$_name');
print('Email:$_email');print('Password:$_passw
ord');print('Phone:$_phone');print('Address:$_
address');
}
}
}
Output:
There are several ways to handle user input in Flutter, depending on the type of input and the
widget you are using.
The Flutter engine is a low-level graphics rendering and layout engine that is responsible for
rendering the user interface (UI) of a Flutter app. It uses a portable graphics engine called Skia to
draw graphics, which allows Flutter to run on multiple platforms such as Android, iOS, and web.
The engine also manages the animation and layout of UI elements.
The Navigator widget is used to manage the navigation stack in a Flutter app. It allows you to
push new routes onto the navigation stack, pop routes off the stack
Lab Session 8:
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){returnMateri
alApp(
home:Scaffold(appBar:AppBar(
title:Text('AnimationExample'),
),
body:AnimationWidget(),
),
);
}
}
classAnimationWidgetextendsStatefulWidget{@override
_AnimationWidgetStatecreateState()=>_AnimationWidgetState();
}
@override
void initState() {super.initState();
_controller=AnimationController(duration:
Duration(seconds: 1),vsync:this,
);
_animation=Tween<double>(begin:0,end:300).animate(_controller)
..addListener((){
setState((){});//Triggerrebuildwhenanimationvaluechanges
});
}
@override
Widgetbuild(BuildContextcontext){returnCenter
(
child:Column(
mainAxisAlignment:MainAxisAlignment.center,
children:<Widget>[
Container(
width:_animation.value,height:_animatio
n.value,color:Colors.blue,
child:FlutterLogo(size:100),
),
SizedBox(height:20),ElevatedButton(onP
ressed: () {
if(_controller.status==AnimationStatus.completed){
_controller.reverse();
}else{
_controller.forward();
}
},
child:Text(
_controller.status==AnimationStatus.completed
?'ReverseAnimation'
:'Start Animation',
),
),
],
),
);
}
@override
voiddispose(){
_controller.dispose();super.dispose();
}
}
Output:
b) Experiment with different types of animations like fade,slide,etc.
Fade Animation:
import'package:flutter/material.dart';
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){returnMateri
alApp(
home:Scaffold(appBar:AppBar(
title:Text('FadeAnimationExample'),
),
body:FadeAnimation(),
),
);
}
}
classFadeAnimationextendsStatefulWidget{@overrid
e
_FadeAnimationStatecreateState()=>_FadeAnimationState();
}
class_FadeAnimationStateextendsState<FadeAnimation>wit
h SingleTickerProviderStateMixin
{AnimationController_controller;
Animation<double>_animation;
@override
void initState() {super.initState();
_controller=AnimationController(vsync:this,
duration:Duration(seconds:2),
);
_animation=Tween<double>(begin:0.0, end: 1.0,
).animate(_controller);
_controller.forward();
}
@override
Widgetbuild(BuildContextcontext){returnCenter
(
child:FadeTransition(opacity:_animation
,child:Container(width:200,
height:200,
color:Colors.blue,
),
),
);
}
@override
voiddispose(){
_controller.dispose();super.dispose();
}
}
Slide Animation:
import'package:flutter/material.dart';
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){
returnMaterialApp(home:Scaffold(app
Bar:AppBar(
title:Text('SlideAnimationExample'),
),
body:SlideAnimation(),
),
);
}
}
classSlideAnimationextendsStatefulWidget{@override
_SlideAnimationStatecreateState()=>_SlideAnimationState();
}
class_SlideAnimationStateextendsState<SlideAnimation>wit
h SingleTickerProviderStateMixin
{AnimationController_controller;
Animation<Offset>_animation;@override
void initState() {super.initState();
_controller=AnimationController(
vsync:this,
duration:Duration(seconds:2),
);
_animation=Tween<Offset>(begin: Offset(-
1.0, 0.0),
end:Offset(0.0,0.0),
).animate(_controller);
_controller.forward();
}
@override
Widgetbuild(BuildContextcontext){returnCenter
(
child:SlideTransition(position:_animatio
n,child:Container(width:200,
height:200,
color:Colors.blue,
),
),
);
}
@override
voiddispose(){
_controller.dispose();super.dispose();
}
}
ScaleAnimation:
import'package:flutter/material.dart';
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){returnMateri
alApp(
home:Scaffold(appBar:AppBar(
title:Text('ScaleAnimationExample'),
),
body:ScaleAnimation(),
),
);
}
}
classScaleAnimationextendsStatefulWidget{@override
_ScaleAnimationStatecreateState()=>_ScaleAnimationState();
}
class_ScaleAnimationStateextendsState<ScaleAnimation>wit
h SingleTickerProviderStateMixin
{AnimationController_controller;
Animation<double>_animation;
@override
void initState() {super.initState();
_controller=AnimationController(vsync:this,
duration:Duration(seconds:2),
);
_animation=Tween<double>(begin:0.0,
end: 1.0,
).animate(_controller);
_controller.forward();
}
@override
Widgetbuild(BuildContextcontext){returnCenter
(
child:ScaleTransition(scale:_animation,c
hild:Container(width:200,
height:200,
color:Colors.blue,
),
),
);
}
@override
voiddispose(){
_controller.dispose();super.dispose();
}
}
Output:
VIVA QUESTIONS AND ANSWERS
1) What are the points of difference between runApp() and main() in Flutter?
Main()
When rendering the widget tree on the screen, it returns the widgets connected to the screen as
the widget tree’s root.
Primary function refers to the function that drives the app
RunApp()
It is a feature that is used to launch the software. You cannot create any program in Flutter
without the main() function.
Our preferences determine how a row and column widget aligns with its children using the
CrossAxisAlignment and PrimaryAxisAlignment.
PrimaryAxisAlignment
In PrimaryAxisAlignment, the columns run vertically while the rows run horizontally.
CrossAxisAlignment
In CrossAxisAlignment, the columns run horizontally while the rows run vertically.
3) What are the keys fluttering, and where should developers apply them?
In Flutter, widgets, elements, and semantic nodes are identified by keys. The subclasses of Key
are GlobalKeys and LocalKeys. Keys in the widget tree are in charge of keeping modified
widgets in their original state. You can also rearrange and change collections of widgets having
the same type and state using keys. Flutter developers can use keys to alter a widget tree that
includes stateful widgets rather than a tree entirely made up of stateless widgets.
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){returnMateri
alApp(
home:HomePage(),
);
}
}
classHomePageextendsStatefulWidget{@override
_HomePageStatecreateState()=>_HomePageState();
}
class_HomePageStateextendsState<HomePage>{List<dynami
c> _data = [];
@override
void initState() {super.initState();
_fetchDataFromApi();
}
Future<void>_fetchDataFromApi()async{
finalresponse=awaithttp.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if(response.statusCode==200){setState((){
_data=json.decode(response.body);
});
}else{
throwException('Failedtoloaddata');
}
}
@override
Widgetbuild(BuildContextcontext){returnScaffo
ld(
appBar:AppBar(
title:Text('APIDataExample'),
),
body:ListView.builder(itemCount:_data.length
,itemBuilder:(context,index){returnListTile(
title:Text(_data[index]['title']),subtitle:Text(_dat
a[index]['body']),
);
},
),
);
}
Output:
b) Display the fetched data in a meaningful way in the UI
import'dart:convert';
import'package:flutter/material.dart';
import'package:http/http.dart'ashttp;
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){returnMateri
alApp(
home:HomePage(),
);
}
}
classHomePageextendsStatefulWidget{@override
_HomePageStatecreateState()=>_HomePageState();
}
class_HomePageStateextendsState<HomePage>{List<dynami
c> _data = [];
bool_isLoading=false;
@override
void initState() {super.initState();
_fetchDataFromApi();
}
Future<void>_fetchDataFromApi()async{setState(()
{
_isLoading=true;
});
finalresponse=awaithttp.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if(response.statusCode==200){setState((){
_data=json.decode(response.body);
_isLoading=false;
});
}else{
throwException('Failedtoloaddata');
}
}
@override
Widgetbuild(BuildContextcontext){returnScaffo
ld(
appBar:AppBar(
title:Text('APIDataExample'),
),
body:_isLoading
? Center(
child:CircularProgressIndicator(),
)
:ListView.builder(itemCount:_data.length,
itemBuilder:(context,index){returnPostCard(
title:_data[index]['title'],
body:_data[index]['body'],
);
},
),
);
}
}
classPostCardextendsStatelessWidget{final String
title;
finalStringbody;
constPostCard({Keykey,@requiredthis
.title,
@requiredthis.body,
}):super(key:key);
@override
Widgetbuild(BuildContextcontext){returnCard(
margin:EdgeInsets.symmetric(horizontal:16,vertical:8),child
:Padding(
padding:EdgeInsets.all(16),child:Column(
crossAxisAlignment:CrossAxisAlignment.start,
children:<Widget>[Text(
title,
style:TextStyle(fontSize:18,fontWeight:FontWeight.bold),
),
SizedBox(height:8),Text( body, style:TextStyle(fontSize:16),
),
],
),
),
);
}
}
Output:
The first step in building an app using Flutter Flow is to create an account and get started.
2) For what reason does the app require a private member named asset path?
The purpose of defining a private member called asset path is to identify the location of the
image asset file and provide a path to it.
The purpose of the widget tree in FlutterFlow is to enable users to isolate different parts of the
app and structure it from scratch or use templates.
Constraints are used in the app to control the size and position of the widget and its children.
The app’s image widget displays images on the screen, allowing users to customise their
appearance.
Lab Session 10:
import'package:flutter/material.dart';
import'package:flutter_test/flutter_test.dart';
import'package:your_app/post_card.dart';
voidmain(){
testWidgets('PostCard displays title and body',(WidgetTester tester)async{
await tester.pumpWidget(
MaterialApp(
home:PostCard(
title: 'Test Title',
body:'TestBody',
),
),
);
expect(find.text('Test Title'),
findsOneWidget);
expect(find.text('Test Body'), findsOneWidget);
});
testWidgets('PostCardwidgethascorrectstyling',(WidgetTestertester)async{
//Buildourwidgetandtriggeraframe.awaittester.pu
mpWidget(MaterialApp(
home:PostCard(title: 'Test
Title',body:'TestBody',
),
),
);
//Verifythatthetextstylesareappliedcorrectly.
finaltitleText=tester.widget<Text>(find.text('TestTitle'));exp
ect(titleText.style.fontSize,18);expect(titleText.style.fontWei
ght,FontWeight.bold);
finalbodyText=tester.widget<Text>(find.text('TestBody'));exp
ect(bodyText.style.fontSize,16);
});
}
In this test:
We use the testWidgets function from the flutter_test package to define our test cases.
In the first test case, we ensure that the PostCard widget correctly displays the provided title and
body text.
In the second test case, we verify that the text styles applied to the title and body texts are as
expected. We use expect statements to assert that the expected UI elements are found on the
screen and that their properties match the expected values.
Make sure to replace your_app with the appropriate package name where your PostCard widget
resides.
demonstrate the use of Flutter's debugging tools, let's consider a scenario where we have a
simple counter app, but there's a bug where the counter is not incrementing when the "+" button
is pressed. We'll use Flutter's debugging tools to identify and fix this issue. Here's the code for
the counter app:
import 'package:flutter/material.dart';
void main() {runApp(MyApp());
}
classMyAppextendsStatelessWidget{@override
Widgetbuild(BuildContextcontext){returnMateri
alApp(
home:CounterApp(),
);
}
}
classCounterAppextendsStatefulWidget{@override
_CounterAppStatecreateState()=>_CounterAppState();
}
class_CounterAppStateextendsState<CounterApp>{int
_counter = 0;
void_incrementCounter(){
_counter++;
}
@override
Widgetbuild(BuildContextcontext){returnScaffo
ld(
appBar:AppBar(
title:Text('CounterApp'),
),
body:Center(child:Column(mainAxisAlignment:MainAxisAlignment.center,
children:<Widget>[Text(
'Counter:',
style:TextStyle(fontSize:24),
),
Text('$_counter',
style:TextStyle(fontSize:36,fontWeight:FontWeight.bold),
),
],
),
),
floatingActionButton:FloatingActionButton(onPressed:_i
ncrementCounter,
tooltip:'Increment',child:Icon(Icons.add),
),
);
}
}
Now, let's use Flutter's debugging tools to identify and fix the issue:
Widget Inspector: First, let's inspect the widget tree to see if the "+" button is correctly wired to the
_incrementCounter method. We can do this by running the app in debug mode and enabling the widget
inspector. You can do this by clicking the "Open DevTools" button in your IDE (Android Studio/IntelliJ
IDEA or Visual Studio Code) or running the following command in your terminal: flutter run –debug
Once the app is running, click on the "Toggle Widget Inspector" button in the top-right corner of your
app. Then, select the FloatingActionButton widget representing the "+" button. Ensure that the
onPressed callback is correctly set to _incrementCounter.
Debugging Console: If everything looks fine in the widget inspector, we can add some debug print
statements to the _incrementCounter method to see if it's being called when the button is pressed.
Modify the _incrementCounter method as follows:
void_incrementCounter(){
print('Incrementingcounter');
_counter++;
}
Now, run the app again in debug mode and observe the console output when you press the
"+" button. If you don't see the "Incrementing counter" message in the console, it means the
_incrementCounter method is not being called.
Breakpoints: As a final step, let's set a breakpoint in the _incrementCounter method and
debug the app to see if it's being hit. Add a breakpoint by clicking on the left margin of the
_incrementCounter method in your code editor. Then, run the app in debug mode and press
the "+" button. The app should pause at the breakpoint, allowing you to inspect the current
state and variables. You can step through the code to see if there are any issues with the
execution flow.
By using Flutter's debugging tools, you should be able to identify the issue with the counter
app and fix it accordingly. In this case, if the debugging process reveals that the
_incrementCounter method is not being called, you can double-check the on Pressed callback
of the FloatingActionButton to ensure it's correctly wired to the _incrementCounter method
1) Could you please explain how the app’s image banner is used?
The image banner is implemented by wrapping the image in a container and providing options
like padding or height. Constraints are also used to control the container’s size.
2) To what end does an app’s front end serve when developed with Flutter Flow?
The purpose of the front end in an app built into Flutter Flow is to consider aesthetics, buttons,
animation, and other user preferences.
Adding padding to each text widget controls the size and position of the widget and its children.
4) For the four corners, what are the various cushioning schemes?
A constant called LTRB controls the padding schemes for the left, right, top, and bottom edges.
Defining a static constant called horizontal padding ensures consistency in the padding schemes
used throughout the app.