0% found this document useful (0 votes)
13 views79 pages

Mad Sem

The document provides an introduction to Flutter, an open-source UI SDK by Google for building natively compiled applications across multiple platforms from a single codebase. It covers key features of Flutter, the lifecycle events of Stateless and Stateful Widgets, the differences between Widget and Element Trees, and the installation process for the Flutter SDK. Additionally, it includes steps for creating a 'Hello World' app and a starter project template, along with an overview of Dart programming language used in Flutter development.

Uploaded by

noobvi631
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views79 pages

Mad Sem

The document provides an introduction to Flutter, an open-source UI SDK by Google for building natively compiled applications across multiple platforms from a single codebase. It covers key features of Flutter, the lifecycle events of Stateless and Stateful Widgets, the differences between Widget and Element Trees, and the installation process for the Flutter SDK. Additionally, it includes steps for creating a 'Hello World' app and a starter project template, along with an overview of Dart programming language used in Flutter development.

Uploaded by

noobvi631
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 79

UNIT-1:FLUTTER INTRODUCTION

1.INTRODUCTION TO FLUTTER:

Flutter is an open-source UI software development kit (SDK) created by Google. It


is widely used to build natively compiled applications for mobile (Android and
iOS), web, and desktop from a single codebase. Flutter stands out due to its
efficiency, expressiveness, and flexibility, making it a popular choice for
developers creating visually appealing and high-performing apps.

Key Features of Flutter:

1. Single Codebase: Write once, deploy on multiple platforms.


2. Widgets: Rich and customizable widgets for creating complex UIs.
3. Hot Reload: Instant updates to the app interface during development
without restarting the application.
4. Dart Programming Language: Utilizes Dart, a fast, object-oriented
language optimized for UI development.
5. Native Performance: Provides near-native performance by compiling to
native ARM code.
6. Cross-Platform: Supports building apps for Android, iOS, web, Windows,
macOS, and Linux.
7. Community Support: Backed by a growing community with extensive
resources and plugins.

2.WIDGET LIFECYCLE EVENTS

In Flutter, widgets are the building blocks of the user interface. They can be
categorized into Stateless Widgets and Stateful Widgets, based on their ability to
maintain state and respond to changes. Understanding the widget lifecycle events
is essential for effective Flutter development.
Stateless Widgets
A Stateless Widget is immutable. It does not hold or manage any state that might
change during its lifecycle. Once created, its appearance and properties remain
fixed until rebuilt.

Lifecycle of a Stateless Widget

Since Stateless Widgets don’t maintain state, their lifecycle is straightforward:

1. Constructor: Initializes the widget.


2. build(): Returns a widget tree to render.

Stateless widgets are rebuilt whenever their parent widget rebuilds.

Example:

class MyStatelessWidget extends StatelessWidget {

@override

Widget build(BuildContext context) {

return Center(

child: Text('I am a Stateless Widget'),

);

}
}

Stateful Widgets
A Stateful Widget can maintain state that may change during its lifecycle. They
consist of two classes:

1. StatefulWidget: Defines the widget's structure.


2. State: Holds mutable state information and defines behavior.

Lifecycle of a Stateful Widget

1. createState():
○ Called when the widget is created.
○ Links the widget with its associated state object.
2. initState():
○ Invoked once when the state object is inserted into the widget tree.
○ Used for one-time initialization (e.g., setting up listeners or streams).
3. didChangeDependencies():
○ Called when a dependency of the State object changes (e.g., inherited
widgets).
4. build():
○ Invoked whenever the widget needs to be rendered.
○ Returns the UI representation.
5. setState():
○ Triggers a rebuild to update the UI when the state changes.
6. didUpdateWidget():
○ Called when the parent widget rebuilds and passes new data to the
widget.
7. deactivate():
○ Called when the widget is removed temporarily.
8. dispose():
○ Invoked when the widget is permanently removed from the widget
tree.
○ Used to release resources (e.g., closing streams or disposing
controllers).
Example:

class MyStatefulWidget extends StatefulWidget {

@override

_MyStatefulWidgetState createState() => _MyStatefulWidgetState();

class _MyStatefulWidgetState extends State<MyStatefulWidget> {

int _counter = 0;

@override

void initState() {

super.initState();

print("Widget Initialized");

void _incrementCounter() {

setState(() {

_counter++;

});

@override

Widget build(BuildContext context) {


return Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

Text('Count: $_counter'),

ElevatedButton(

onPressed: _incrementCounter,

child: Text('Increment'),

),

],

);

@override

void dispose() {

print("Widget Disposed");

super.dispose();

}
Comparison: Stateless vs. Stateful Widgets

Feature Stateless Widget Stateful Widget

State Immutable; cannot change Mutable; maintains


Management state state

Rebuild Only rebuilt when parent Rebuilt on


rebuilds setState()

Performance Lightweight and faster Slightly heavier due to


state

Use Cases Static UIs Dynamic, interactive


UIs
Conclusion

● Use Stateless Widgets for static layouts or UI components that don’t


change.
● Use Stateful Widgets for interactive or dynamic components that need to
update in response to user actions or data changes.

3. WIDGET TREE AND ELEMENT TREE

In Flutter, Widget Tree and Element Tree are two essential concepts that describe
how the user interface is constructed and managed. While they are closely related,
they serve different purposes in the UI framework.

Widget Tree
The Widget Tree represents the structure and hierarchy of all the widgets in the
app. It is a blueprint that defines what should appear on the screen.

Key Points:

1. Immutable: Widgets are immutable and describe the UI.


2. Rebuilt Often: Flutter rebuilds widgets whenever the state or configuration
changes.
3. Declarative: Developers declare the UI using widgets, such as Text,
Container, and Row.

Example:
dart
Copy code
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Widget Tree Example'),
),
body: Center(
child: Text('Hello, Flutter!'),
),
),
);
}
}

In this example, the MaterialApp, Scaffold, AppBar, and Text widgets


form the Widget Tree.

Element Tree
The Element Tree is the runtime representation of the Widget Tree. It acts as a
bridge between the immutable Widget Tree and the mutable Render Tree. Each
widget in the Widget Tree corresponds to an Element in the Element Tree.

Key Points:

1. Mutable: Unlike widgets, elements are mutable.


2. Lifecycle: Elements manage the lifecycle of widgets, handling updates and
rebuilding.
3. Parent-Child Relationship: It maintains the hierarchical relationship
between widgets at runtime.
4. Efficiency: Flutter updates the Element Tree during widget rebuilds to
minimize unnecessary changes.

Relationship to Widgets:
● Stateless Widgets: A single StatelessElement is created for the
widget.
● Stateful Widgets: A StatefulElement is created and links to a State
object to manage mutable state.

Comparison: Widget Tree vs. Element Tree


Feature Widget Tree Element Tree

Nature Blueprint (immutable) Runtime representation


(mutable)

Role Describes the UI structure Manages widgets and their


lifecycle

Update Rebuilt often Updates selectively for


Frequency efficiency

Examples Text, Container, StatelessElement,


Button widgets StatefulElement

4. INSTALLING THE FLUTTER SDK

Installing the Flutter SDK is the first step to building cross-platform applications.
Below is a step-by-step guide for setting up Flutter on various operating systems:

1. Prerequisites
● Operating System:
○ Windows, macOS, or Linux
● Disk Space:
○ Around 2 GB for the SDK, plus space for IDEs and dependencies
● Software:
○ Git (required for cloning the Flutter repository)
○ IDE (like Android Studio, Visual Studio Code, or IntelliJ)

2. Installation Steps
For Windows

1. Download the Flutter SDK:


○ Visit Flutter’s official website and download the latest stable release
for Windows.
2. Extract the ZIP file:
○ Extract the downloaded ZIP file to a suitable location, such as
C:\src\flutter. Avoid locations requiring admin privileges.
3. Update the PATH variable:
○ Add the flutter\bin directory to your system's PATH.
■ Steps:
■ Right-click on This PC or My Computer >
Properties > Advanced System Settings.
■ Click on Environment Variables.
■ In the System Variables section, find the Path
variable and click Edit.
■ Add the path to your Flutter SDK’s bin directory.
4. Run Flutter Doctor:

Open a command prompt and run:

flutter doctor

○ Follow the instructions to install missing dependencies like the


Android SDK, Java, or other tools.

3. Install Android Studio (Optional, but Recommended)


1. Download Android Studio from Android Studio's official site.
2. Install and configure:
○ Open Android Studio and install the Android SDK.
○ Set up an emulator for testing your apps.

4. Run Your First Flutter App


Create a new Flutter project:

flutter create my_first_app

1. Navigate to the project directory:

cd my_first_app
2. Run the app:

flutter run

5. Common Issues and Solutions


● Flutter Doctor reports missing Android SDK:
○ Ensure Android Studio is installed, and its SDK paths are correctly
set.
● PATH variable issues:
○ Double-check the directory added to PATH.
● Permission Denied Errors:
○ Ensure the SDK directory has the necessary read/write permissions.

5.CREATING HELLO WORLD APP

Creating a "Hello World" app in Flutter is a great way to get started with the
framework. Follow the steps below to create and run your first Flutter application.

Step 1: Set Up Your Environment


Ensure you have completed the following:

1. Installed the Flutter SDK.


2. Set up an IDE (recommended: Android Studio or Visual Studio Code).
3. Installed an emulator (or have a physical device connected).

Step 2: Create a New Flutter Project


Using the Command Line:
Open a terminal and run the following command:

flutter create hello_world


Navigate to the project directory:
cd hello_world

Step 3: Open the Project in an IDE


● Open the hello_world project in your preferred IDE.

You will see the following folder structure:

hello_world/
├── android/
├── ios/
├── lib/
├── test/
├── web/
└── pubspec.yaml

Step 4: Modify the Main Dart File


1. Navigate to the lib/ directory and open the main.dart file.

Replace the existing code with the following:


dart
Copy code
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


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

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hello World App',
home: Scaffold(
appBar: AppBar(
title: const Text('Hello World App'),
),
body: const Center(
child: Text(
'Hello, World!',
style: TextStyle(fontSize: 24),
),
),
),
);
}
}

Step 5: Run the Application


Using an Emulator:
1. Start your emulator from your IDE or terminal.

Run the app:


flutter run

Using a Physical Device:

1. Connect your device to your computer and ensure USB debugging is


enabled.

Run the app:


flutter run

Step 6: View the Output


● You should see a screen with an app bar that says "Hello World App" and a
centered text that says "Hello, World!".

UNIT2: LEARNING DART

Dart is an open-source, general-purpose programming language developed by


Google. It is primarily used for building web and mobile applications, especially
for developing Flutter applications. Dart was designed to be easy to learn, efficient,
and fast, making it a popular choice for both client-side and server-side
development.

Key Features of Dart

1. Object-Oriented: Dart is an object-oriented language, which means it uses


classes and objects for organizing and managing code.
2. Strongly Typed: Dart uses static typing, meaning variables must be defined
with a type (e.g., int, String, bool).
3. Compiles to Native Code: Dart can be compiled both just-in-time (JIT)
during development and ahead-of-time (AOT) for production, making it
suitable for both rapid development and performance-optimized apps.
4. Asynchronous Programming: Dart supports asynchronous programming
with Future, async, and await, allowing you to work with operations
like HTTP requests and file I/O without blocking the main thread.

1.CREATING A STARTER PROJECT TEMPLATE

Creating a starter project template in Flutter can save you time when starting new
projects. A well-structured template includes basic configurations, reusable
components, and project organization that suits your development style.

Here’s how you can create a Flutter starter project template:

Step 1: Create a New Project


Open your terminal and run:
flutter create starter_template
Go into the project folder:
cd starter_template

Step 2: Basic Folder Structure


Your project will have the following structure:

starter_template/
├── lib/
│ ├── main.dart # Entry point
│ ├── home_screen.dart # Main screen of the app
│ ├── utils.dart # Utility functions or constants
│ ├── widgets/ # Reusable widgets folder
├── pubspec.yaml # Dependency file

We’ll keep this structure simple to start.

Step 3: Modify main.dart


This is the starting point of the app. Here, we define the app widget and set the
HomeScreen as the first screen.

import 'package:flutter/material.dart';
import 'home_screen.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


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

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Starter Template',
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomeScreen(),
);
}
}

Step 4: Create home_screen.dart


This is a simple screen with some text in the center.

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {


const HomeScreen({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home Screen'),
),
body: const Center(
child: Text(
'Welcome to the Starter Template!',
style: TextStyle(fontSize: 20),
),
),
);
}
}

Step 5: Add a Utility File


In lib/utils.dart, add some constants like colors or text values. This keeps
your code organized.

import 'package:flutter/material.dart';

const Color primaryColor = Colors.blue;


const String welcomeMessage = 'Welcome to the Starter Template!';

Step 6: Add a Reusable Widget


In lib/widgets/custom_button.dart, define a reusable button.

import 'package:flutter/material.dart';

class CustomButton extends StatelessWidget {


final String text;
final VoidCallback onPressed;

const CustomButton({Key? key, required this.text, required this.onPressed})


: super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(text),
);
}
}

Using the Custom Button in home_screen.dart:

Update the home_screen.dart file to include the custom button:

import 'package:flutter/material.dart';
import 'widgets/custom_button.dart';

class HomeScreen extends StatelessWidget {


const HomeScreen({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home Screen'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Welcome to the Starter Template!',
style: TextStyle(fontSize: 20),
),
const SizedBox(height: 20),
CustomButton(
text: 'Click Me',
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Button Pressed!')),
);
},
),
],
),
),
);
}
}

Step 7: Update pubspec.yaml

Add any additional assets or dependencies to the pubspec.yaml file. For


example:

flutter:
assets:
- assets/images/

Run this command to fetch any dependencies:

flutter pub get

Step 8: Run the App


Run the following command to test your starter project:

flutter run
What You Get

1. A simple app with a home screen.


2. A reusable custom button.
3. Constants for better code organization.
4. A basic structure to expand into more complex apps.

Feel free to extend this template as you learn more about Flutter!

2.BUILDING THE FULL WIDGET TREE

Full Widget Tree - Explanation

A Full Widget Tree in Flutter refers to the complete hierarchy of widgets that
make up the entire structure of your app's user interface. Each widget in Flutter is a
building block of the UI, and the full widget tree represents all of them, starting
from the root widget down to the leaf nodes.

Structure of the Widget Tree

The widget tree can be broken down into several layers, each responsible for a
specific part of the app's UI. It follows a hierarchical structure, with parent widgets
containing child widgets. The deeper you go into the tree, the more specific the
functionality and styling of the UI become.

Here’s an overview of how a full widget tree is structured:

1. Root Widget (Top Level):

○ The entry point of your app is usually a MaterialApp or


CupertinoApp widget, which is responsible for setting up the app’s
theme and navigation.
2. App Layout:
○ The layout typically starts with a Scaffold widget, which provides
the basic structure for your app’s visual elements: app bar, body,
floating action buttons, etc.
3. Navigation Structure:

○ If the app has multiple screens, the widget tree may include
navigational widgets like Navigator or Drawer to enable screen
transitions.
4. Widgets in the Body:

○ The body of the app is where you place most of your UI components
like buttons, images, text, and containers. These widgets can be
arranged in various layouts such as:
■ Column (for vertical layouts),
■ Row (for horizontal layouts),
■ Stack (for overlapping widgets),
■ GridView (for grid-based layouts).
5. Interaction and Functionality:

○ You can add interactive elements like TextField,


ElevatedButton, or GestureDetector that allow users to
interact with the UI.
○ State management widgets like StatefulWidget and
InheritedWidget manage and update the widget tree when the
state changes.
6. Styling and Themes:

○ The theme of the app (e.g., colors, fonts) is defined using the
ThemeData class, and individual widgets like Text, Container,
Button, etc., can have specific styling applied.
How the Full Widget Tree Works

1. Parent-Child Relationships:

○ Widgets in Flutter are arranged in a parent-child relationship. A parent


widget (like Scaffold) can contain several child widgets (like
Column, Row, Container).
○ This allows for complex layouts where multiple widgets can be nested
inside one another, creating a tree-like structure.
2. Building the Tree:

○ When you run a Flutter app, the framework starts at the root widget
(MaterialApp or CupertinoApp) and recursively builds the
widget tree.
○ Each widget is created and rendered according to its configuration,
starting from the top-most widget and going down to the deepest,
nested widget.
3. Rendering Process:

○ Each widget is associated with a RenderObject (like a RenderBox)


that controls how the widget is laid out and painted on the screen.
○ Flutter uses a two-phase process for rendering the widget tree: layout
phase (determining size and position) and painting phase (actually
drawing the widget on the screen).
4. Rebuilding the Tree:

○ Flutter uses an immutable widget model. When the app's state


changes, Flutter rebuilds the widget tree.
○ If a widget’s state changes (e.g., button clicked, text changed), Flutter
marks the widget as "dirty" and rebuilds only the part of the tree that
needs updating, which makes the app efficient.

Example of a Full Widget Tree Concept


1. MaterialApp: The root of the app that sets up material design and
navigation.
○ Scaffold: Provides the basic layout structure, with app bar and body.
■ AppBar: Contains the title and optional actions.
■ Body: Contains the main content of the screen.
■ Column: A vertical layout widget that arranges its
children vertically.
■ Text: Displays a text widget with a greeting.
■ Button: A clickable button that triggers actions
(like navigating to another screen or performing an
operation).
■ Image: Displays an image from the assets or
network.
■ Footer: A part of the UI, which could be a
BottomNavigationBar, Drawer, or SnackBar.

import 'package:flutter/material.dart';

void main() {

runApp(const MyApp());

class MyApp extends StatelessWidget {

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

@override

Widget build(BuildContext context) {

return MaterialApp(

home: Scaffold(

appBar: AppBar(

title: const Text('Full Widget Tree'),


),

body: Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

const Text(

'Hello, Full Widget Tree!',

style: TextStyle(fontSize: 20),

),

const SizedBox(height: 20),

ElevatedButton(

onPressed: () {

print('Button Pressed!');

},

child: const Text('Click Me'),

),

],

),

),

),

);
}

Key Concepts in Full Widget Tree

● Stateful vs Stateless Widgets:

○ StatelessWidget: Widgets that don't change once created (e.g., Text,


Icon).
○ StatefulWidget: Widgets that can change over time (e.g.,
TextField, Checkbox). When state changes, the widget is rebuilt.
● Inherited Widgets:

○ Used for passing data down the widget tree efficiently without
needing to pass data manually at every level.
● Flutter Widgets:

○ Flutter offers many built-in widgets to help you create rich UIs, such
as:
■ Container, Column, Row, Stack, GridView
■ Text, Image, Icon, Button
■ ListView, Form, TextField, Checkbox

Visualizing the Widget Tree

Here’s a breakdown of how a simple app's full widget tree might look:

MaterialApp
└── Scaffold
├── AppBar
├── Body (Center)
│ └── Column
│ ├── Text (Welcome message)
│ ├── SizedBox (Space)
│ ├── ElevatedButton (Click Me)
└── BottomNavigationBar

Each of these widgets is part of a larger tree, and they each manage a specific part
of the UI.

3.BUILDING A SHALLOW WIDGET TREE

Shallow Widget Tree - Explanation

A Shallow Widget Tree is a simplified version of the full widget tree, where the
widget hierarchy is kept minimal and only the basic layout structure is defined.
Unlike the full widget tree, which includes all the detailed widgets, styles, and
functionality, a shallow widget tree only focuses on the high-level layout without
diving deep into widget-specific details.

Characteristics of a Shallow Widget Tree

1. Minimal Hierarchy: Only the main components of the app’s layout are
included, with few or no nested widgets.
2. No Detailed Styling or Functionality: The shallow tree does not include
things like custom styles, padding, or interactive functionality.
3. Focus on Layout: The goal of a shallow widget tree is to sketch out the
layout or the basic structure of the app, often for rapid prototyping or testing.

Why Use a Shallow Widget Tree?

● Quick Prototyping: A shallow tree is useful when you're rapidly creating a


layout to visualize the structure of your app without getting bogged down in
details.
● Simpler Debugging: If you're trying to troubleshoot layout issues or get a
rough idea of the UI, working with a shallow tree helps you avoid
complexity.
● Focus on High-Level Structure: It's helpful when you just want to check
the arrangement of major UI components (like app bars, buttons, and text
fields) without worrying about every small detail.

Example of a Shallow Widget Tree

Let's consider an app with a simple layout consisting of:

● An app bar.
● A text widget.
● A button widget.

import 'package:flutter/material.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


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

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Shallow Widget Tree'),
),
body: Center(
child: Column(
children: const [
Text('Hello!'),
ElevatedButton(onPressed: null, child: Text('Click Me')),
],
),
),
),
);
}
}

Explanation of the Shallow Widget Tree

1. Root Widget (MaterialApp): The MaterialApp widget is the root of


the application, setting up things like the app theme and routing.
2. Scaffold: Provides the basic structure of the app, including the app bar
and body.
○ AppBar: Displays the title "Shallow Widget Tree."
○ Center: Centers its child widgets (in this case, a Column).
3. Column: Arranges its children vertically. Here, we have two children:
○ A Text widget displaying the text "Hello!"
○ An ElevatedButton that has no onPressed functionality (for
simplicity).

Visualizing the Shallow Widget Tree

Here’s a simplified view of the shallow widget tree:

MaterialApp
└── Scaffold
├── AppBar
└── Body (Center)
└── Column
├── Text (Hello!)
└── ElevatedButton (Click Me)

Key Points in the Shallow Widget Tree


1. Minimal Depth: The tree is not very deep, and the widgets are only nested a
few levels.
2. No Complex Widgets: We don’t have widgets like TextField,
ListView, or custom containers. The tree consists of simple components
that define the layout.
3. Limited Functionality: The button in this shallow tree doesn’t do anything
because the onPressed is set to null, meaning there's no interaction.

Use Cases for a Shallow Widget Tree

1. Rapid Prototyping: Quickly sketch out a basic UI to visualize the layout.


2. Testing Layouts: Check how elements are arranged on the screen without
worrying about their behavior or appearance in detail.
3. UI Debugging: Troubleshoot general UI structures, such as verifying the
placement of app bars or buttons, before fine-tuning their look or
functionality.

When to Transition to a Full Widget Tree

Once you're satisfied with the layout or structure of the shallow widget tree, you
can begin adding more complexity:

● Add more detailed styling (e.g., colors, padding, margins).


● Implement functionality for interactive widgets (e.g., buttons, forms).
● Use more complex layout widgets like GridView, ListView, or Stack
for advanced layouts.

Summary

A Shallow Widget Tree is a basic, high-level representation of your app’s layout


without detailed styling, interaction, or deep nesting of widgets. It's ideal for quick
layouts, prototyping, and testing the structure of your app before diving into finer
details like styling, animations, or state management.
UNIT3: INTERMEDIATE FLUTTER

What is Animation in Flutter?

In Flutter, animation refers to the process of changing the properties of a widget


over time. It adds smooth transitions or effects, enhancing the user experience.
Flutter provides built-in tools to animate properties like size, color, position, or
even complex custom animations. These animations can be either implicit (built-in
and automatic) or explicit (requiring more control, such as custom animation
controllers).

Animations are essential in modern applications to provide visual feedback, such


as fading, scaling, or moving elements, making the app feel interactive and
dynamic.

ADDING ANIMATION TO AN APP

Animations add interactivity and visual appeal to your app, providing a better user
experience. Flutter offers several built-in animation widgets to easily animate your
app's UI. Here are a few commonly used animation widgets in Flutter:

1. AnimatedContainer
2. AnimatedCrossFade
3. AnimatedOpacity
4. AnimationController

1. AnimatedContainer

AnimatedContainer is a widget that animates changes in the properties of a


Container, such as its dimensions, color, padding, margin, and decoration.
Whenever the properties of the AnimatedContainer change, it automatically
animates the change, making the transition smooth.
Use Case:
● When you need to animate changes in a Container's size, color, or
decoration.
Example:
import 'package:flutter/material.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatefulWidget {


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

@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {


double _width = 200;
double _height = 200;
Color _color = Colors.blue;

void _animate() {
setState(() {
_width = _width == 200 ? 300 : 200;
_height = _height == 200 ? 300 : 200;
_color = _color == Colors.blue ? Colors.red : Colors.blue;
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("AnimatedContainer Example")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedContainer(
width: _width,
height: _height,
color: _color,
duration: const Duration(seconds: 1),
curve: Curves.easeInOut,
),
ElevatedButton(
onPressed: _animate,
child: const Text("Animate Container"),
),
],
),
),
),
);
}
}

Explanation:

● When the properties (like width, height, or color) are updated using
setState, the AnimatedContainer animates the transition smoothly.

2. AnimatedCrossFade

AnimatedCrossFade is a widget that smoothly transitions between two child


widgets by fading one out and the other in. It's useful for scenarios where you want
to toggle between two views.
Use Case:
● Switching between two widgets with a smooth fade transition (e.g.,
swapping between two images or UI states).
Example:
import 'package:flutter/material.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatefulWidget {


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

@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {


bool _isFirst = true;

void _toggle() {
setState(() {
_isFirst = !_isFirst;
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("AnimatedCrossFade Example")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedCrossFade(
firstChild: const FlutterLogo(size: 100),
secondChild: const Icon(Icons.star, size: 100),
crossFadeState: _isFirst ? CrossFadeState.showFirst :
CrossFadeState.showSecond,
duration: const Duration(seconds: 1),
),
ElevatedButton(
onPressed: _toggle,
child: const Text("Switch Widgets"),
),
],
),
),
),
);
}
}

Explanation:

● AnimatedCrossFade switches between firstChild and


secondChild with a smooth fade effect.
● The crossFadeState determines which child is visible (showFirst or
showSecond).

3. AnimatedOpacity

AnimatedOpacity is a widget that animates the opacity of a child widget. It


allows you to fade in or fade out a widget smoothly.
Use Case:

● Animating the visibility of a widget (e.g., fading in/out an element like a text
or image).
Example:
import 'package:flutter/material.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatefulWidget {


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

@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {


double _opacity = 1.0;

void _toggleOpacity() {
setState(() {
_opacity = _opacity == 1.0 ? 0.0 : 1.0;
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("AnimatedOpacity Example")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedOpacity(
opacity: _opacity,
duration: const Duration(seconds: 1),
child: const FlutterLogo(size: 100),
),
ElevatedButton(
onPressed: _toggleOpacity,
child: const Text("Toggle Opacity"),
),
],
),
),
),
);
}
}

Explanation:

● AnimatedOpacity smoothly changes the opacity of its child. The


opacity can be toggled between 1.0 (fully visible) and 0.0 (fully invisible)
when the button is pressed.

4. AnimationController

AnimationController is a lower-level widget used for creating custom


animations. It provides control over the animation's lifecycle and allows you to
animate properties of widgets, such as position, size, or color, over a given
duration.
Use Case:

● When you need more control over the animation, such as looping, reversing,
or customizing the animation's duration and curve.
Example:
import 'package:flutter/material.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatefulWidget {


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

@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin


{
late AnimationController _controller;
late Animation<double> _animation;

@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animation = Tween<double>(begin: 0.0, end: 200.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
_controller.repeat(reverse: true); // Loop the animation
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("AnimationController Example")),
body: Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.blue,
);
},
),
),
),
);
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}
}

Explanation:

● AnimationController is used to control the animation's duration and


timing. In this case, it animates a container’s size using a Tween.
● AnimatedBuilder listens to the changes in the animation and rebuilds
the widget.
● The animation is repeated with reverse: true, meaning it will
continuously grow and shrink.

Conclusion

Flutter provides a variety of animation widgets that make it easy to add interactive
and smooth transitions to your app. Here's a quick summary of the widgets:
● AnimatedContainer: Automatically animates changes to a container's
properties like size and color.
● AnimatedCrossFade: Smoothly switches between two widgets with a
fade transition.
● AnimatedOpacity: Animates the opacity of a widget, creating fade-in or
fade-out effects.
● AnimationController: Provides fine control over animations,
allowing you to animate widget properties with custom duration, curves, and
behavior.

2.FORM WIDGET AND DECORATORS

Form Widgets and Decorators in Flutter

In Flutter, form widgets are used to create and manage user input forms. These
widgets allow you to capture user data, perform validation, and apply custom
styling. Decorators are used to style these form fields, enhancing the user
experience. Let's explore form widgets and decorators in detail.

1. Form Widget

The Form widget in Flutter is used to group multiple form fields together. It helps
manage the state of those fields, perform validation, and save the entered data. A
form can include text fields, checkboxes, switches, etc.
Key Features:

● Validation:
You can validate form fields to ensure the entered data is correct
before submitting the form.
● Saving: After validation, the form data can be saved.
● Resetting: The form can be reset to its initial values.

Example of Form Widget:


import 'package:flutter/material.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {


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

@override
Widget build(BuildContext context) {
return MaterialApp(
home: const Scaffold(body: MyForm()),
);
}
}

class MyForm extends StatefulWidget {


const MyForm({Key? key}) : super(key: key);

@override
_MyFormState createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {


final _formKey = GlobalKey<FormState>();
String _name = '';
String _email = '';

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey, // Form key for validation
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your name';
}
return null;
},
onSaved: (value) => _name = value!,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Email'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
if
(!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$").hasMatch(va
lue)) {
return 'Please enter a valid email address';
}
return null;
},
onSaved: (value) => _email = value!,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save(); // Save form data
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Name: $_name, Email: $_email')),
);
}
},
child: const Text('Submit'),
),
),
],
),
),
);
}
}

Explanation:

● GlobalKey: The Form widget uses a GlobalKey to manage its state,


allowing you to validate and save data across multiple form fields.
● TextFormField: These are individual input fields where the user provides
their data. validator is used for validation, and onSaved stores the
input after validation.
● Submit Button: The button triggers validation and saves the data if all fields
are valid.

2. TextFormField Widget

The TextFormField widget is one of the most commonly used input fields in a
form. It is an extension of TextField that integrates with the Form widget,
allowing validation and data saving functionality.
Key Properties:

● controller: Manages text input and listens for changes.


● decoration: Customizes the UI of the text field (label, hint, etc.).
● validator: Validates the input before submitting the form.
● onSaved: Saves the field data after validation.
Example:
TextFormField(
decoration: const InputDecoration(
labelText: 'Email',
hintText: 'Enter your email',
icon: Icon(Icons.email),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
if
(!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$").hasMatch(va
lue)) {
return 'Please enter a valid email address';
}
return null;
},
onSaved: (value) {
print('Saved email: $value');
},
)

Explanation:

● The InputDecoration widget is used here to add styling like


decoration:
a label, hint text, and an icon.
● validator: Ensures the entered email is valid.
● onSaved: This callback is triggered after the form is validated, saving the
data.

3. InputDecoration

InputDecoration is used to style and customize the appearance of a


TextFormField or TextField. It allows you to add labels, icons, borders,
and hints, making your form more user-friendly.
Common Properties:

● labelText: The label displayed inside the form field when it is not focused.
● hintText: A placeholder that is shown when the field is empty.
● icon: An icon placed inside the field.
● border: Defines the appearance of the input field's border.
Example:
TextFormField(
decoration: InputDecoration(
labelText: 'Username',
hintText: 'Enter your username',
icon: Icon(Icons.person),
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2.0),
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your username';
}
return null;
},
)

Explanation:

● labelText: Displays a label for the text field.


● hintText: Placeholder text that disappears when the user starts typing.
● icon: Displays an icon inside the text field.
● border: Adds a border around the text field, which can be customized (e.g.,
OutlineInputBorder for a box-shaped border).

4. FormField Widget
The FormField widget allows for creating custom form fields that are not
limited to text inputs. It can be used for complex form inputs like checkboxes,
switches, or even custom widgets that need validation.
Example: Using FormField for Checkbox:
FormField<bool>(
initialValue: false,
builder: (FormFieldState<bool> state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
CheckboxListTile(
title: const Text('Agree to terms and conditions'),
value: state.value,
onChanged: (bool? newValue) {
state.didChange(newValue); // Updates field state
},
),
if (state.hasError)
Text(
state.errorText!,
style: TextStyle(color: Colors.red),
),
],
);
},
validator: (value) {
if (value == null || !value) {
return 'You must agree to the terms';
}
return null;
},
)
Explanation:

● FormField: The FormField widget is used to create a checkbox input. The


field state is updated using state.didChange.
● validator: Ensures the checkbox is checked before the form can be
submitted.

5. Handling Form Submission

Once all form fields have been validated, you can submit the form. You typically
use FormState.validate() to validate the fields and
FormState.save() to save the field data.

Example: Submitting the Form:


ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save(); // Save form data
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Form submitted!')),
);
}
},
child: const Text('Submit'),
)

Explanation:

● validate(): Checks if all form fields are valid according to their validators.
● save(): Saves the form field values after successful validation.

Conclusion

In Flutter, form widgets like Form, TextFormField, and FormField are used
to handle user input in a structured way. InputDecoration allows you to style
these form fields by adding labels, icons, borders, and other visual enhancements.
These tools help in building dynamic, interactive, and user-friendly forms in your
applications.

By leveraging form widgets and decorators, you can create a seamless user
experience with data validation and custom styling.

UNIT5: NAVIGATION,EFFECTS AND LAYOUTS

1.EXPLAIN ABOUT THE NAVIGATOR

Navigator in Flutter

The Navigator in Flutter is used to manage a stack of routes (screens). It allows


you to push and pop screens, providing a way to navigate between different pages
or screens in an app. The stack-based navigation approach means that when a new
screen is pushed, it is placed on top of the current screen, and when it is popped,
the previous screen is revealed.

Key Concepts:

● Push: Adds a new route (screen) to the stack.


● Pop: Removes the top route from the stack and goes back to the previous
screen.

Hero Animation

Hero animations are used to create a smooth transition between two screens. The
Hero widget takes an object (like an image or text) and animates it from one
screen to another with a shared animation.

● The widget with the same tag on both screens is connected, and Flutter
animates the transition between them.
● Hero animations are typically used for smooth transitions, such as moving
images, icons, or widgets between different screens.
Example Explanation:

● Suppose you have an image on the first screen, and when you navigate to the
second screen, that image smoothly animates from its position on the first
screen to its position on the second screen. This effect is achieved by
wrapping the image in a Hero widget on both screens with the same tag.

import 'package:flutter/material.dart';

void main() {

runApp(MaterialApp(home: FirstScreen()));

class FirstScreen extends StatelessWidget {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(title: Text("First Screen")),

body: Center(

child: GestureDetector(

onTap: () {

Navigator.push(

context,

MaterialPageRoute(builder: (context) => SecondScreen()),


);

},

child: Hero(

tag: 'hero-tag',

child: Container(

width: 100,

height: 100,

color: Colors.blue,

),

),

),

),

);

class SecondScreen extends StatelessWidget {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(title: Text("Second Screen")),


body: Center(

child: Hero(

tag: 'hero-tag',

child: Container(

width: 200,

height: 200,

color: Colors.blue,

),

),

),

);

Bottom Navigation Bar

The BottomNavigationBar widget allows you to provide an easy-to-use


bottom navigation for users to switch between different views or sections in your
app. It's commonly used in apps where the user needs to switch between a small
number of top-level destinations.

Key Features:

● Icons/Labels: Displays a list of items, each with an icon and an optional


label.
● Selected/Unselected Items: Users can tap an item, and the selected item
will be highlighted.
Use Case:

● You may use a BottomNavigationBar to navigate between Home,


Search, Profile, etc., on different screens within the app.

import 'package:flutter/material.dart';

void main() {

runApp(MaterialApp(home: BottomNavBarExample()));

class BottomNavBarExample extends StatefulWidget {

@override

_BottomNavBarExampleState createState() => _BottomNavBarExampleState();

class _BottomNavBarExampleState extends State<BottomNavBarExample> {

int _selectedIndex = 0;

void _onItemTapped(int index) {

setState(() {

_selectedIndex = index;
});

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(title: Text("Bottom Navigation Bar")),

body: Center(

child: Text('Selected Index: $_selectedIndex'),

),

bottomNavigationBar: BottomNavigationBar(

currentIndex: _selectedIndex,

onTap: _onItemTapped,

items: const <BottomNavigationBarItem>[

BottomNavigationBarItem(

icon: Icon(Icons.home),

label: 'Home',

),

BottomNavigationBarItem(

icon: Icon(Icons.search),

label: 'Search',
),

BottomNavigationBarItem(

icon: Icon(Icons.account_circle),

label: 'Profile',

),

],

),

);

BottomAppBar

The BottomAppBar is similar to BottomNavigationBar, but it provides


more flexibility. It is a container for custom widgets placed at the bottom of the
screen, often used in combination with FloatingActionButton to create a
more customizable bottom navigation experience.

Key Features:

● Customizable Widgets: You can place custom widgets like buttons, icons,
or any other widget in the BottomAppBar.
● Floating Action Button (FAB): Often paired with a FAB, allowing for
actions like creating a new post or sending a message.
Use Case:
● You might use a BottomAppBar with a FAB for creating posts or taking
actions related to the app, with additional icons or custom elements
alongside the button.

import 'package:flutter/material.dart';

void main() {

runApp(MaterialApp(home: BottomAppBarExample()));

class BottomAppBarExample extends StatelessWidget {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(title: Text("Bottom AppBar Example")),

body: Center(child: Text("Content Goes Here")),

floatingActionButton: FloatingActionButton(

onPressed: () {},

child: Icon(Icons.add),

),

floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

bottomNavigationBar: BottomAppBar(

shape: CircularNotchedRectangle(),
child: Row(

mainAxisAlignment: MainAxisAlignment.spaceAround,

children: <Widget>[

IconButton(icon: Icon(Icons.home), onPressed: () {}),

IconButton(icon: Icon(Icons.search), onPressed: () {}),

],

),

),

);

TabBar and TabBarView

TabBar and TabBarView work together to provide a tab-based navigation


system within a single screen. They are typically used for creating a tabbed
interface where the user can swipe or tap on tabs to view different sections.

● TabBar: A widget that displays the tabs (like headings or categories).


● TabBarView: A widget that displays the content associated with each tab. It
usually displays a different view for each tab.
Key Features:

● TabBar:
Displays a horizontal row of tabs that users can click to switch
between views.
● TabBarView: Displays the content associated with each selected tab. Each
tab corresponds to a different view or section of the app.
import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(home: TabBarExample()));
}

class TabBarExample extends StatelessWidget {


@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3, // Number of tabs
child: Scaffold(
appBar: AppBar(
title: Text("TabBar Example"),
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.home), text: 'Home'),
Tab(icon: Icon(Icons.search), text: 'Search'),
Tab(icon: Icon(Icons.account_circle), text: 'Profile'),
],
),
),
body: TabBarView(
children: [
Center(child: Text('Home Tab')),
Center(child: Text('Search Tab')),
Center(child: Text('Profile Tab')),
],
),
),
);
}
}
How Each Widget Fits Together

1. Navigator: Allows navigating between different screens.


2. Hero Animation: Used for creating smooth transitions when navigating
between screens.
3. BottomNavigationBar: Allows users to quickly switch between main
sections of the app, typically at the bottom of the screen.
4. BottomAppBar: Provides more flexibility than the
BottomNavigationBar, allowing for custom widgets.
5. TabBar and TabBarView: Together, they provide tabbed navigation within
a single screen, offering a way to switch between content in a tabbed format.

Example Explanation Without Code

Imagine you're building an app with several sections:

1. A home screen that displays posts (using BottomNavigationBar to


navigate between Home, Search, and Profile).
2. On the Home screen, there's a list of posts. When you tap a post, it takes you
to a detail screen where the post's image smoothly transitions using a Hero
animation.
3. Each section of the app (e.g., Home, Search, Profile) is displayed as a tab
(using TabBar and TabBarView), which lets the user swipe between
different sections without leaving the page.
4. The BottomAppBar might hold actions like a FAB for creating a new post,
giving you more control over what you place at the bottom of the screen.

Summary

● Navigator: Manages screen transitions using a stack of routes.


● Hero Animation: Smooth transition between screens for shared elements
like images or icons.
● BottomNavigationBar: A bottom bar with icons for navigating between
different top-level sections of the app.
● BottomAppBar: More customizable than BottomNavigationBar,
often used with a FAB.
● TabBar and TabBarView: Create a tabbed interface that allows easy
navigation within a single screen by switching between different content
views.

Each of these widgets plays a crucial role in making navigation and transitions in
your app smoother and more user-friendly.

2.CREATING THE LAYOUT SETTING UP GESTURE DETECTOR

In Flutter, layout refers to the organization and arrangement of widgets on the


screen. Flutter provides a wide variety of layout widgets that help structure your
UI, such as Column, Row, Stack, Container, etc.

Creating Layouts in Flutter

The most commonly used layout widgets are:

● Column: Arranges children widgets vertically.


● Row: Arranges children widgets horizontally.
● Stack: Places widgets on top of each other.
● Container: Used for styling, padding, and decoration of widgets.

Flutter also has other layout widgets like Expanded, Align, and Padding,
which give more flexibility in creating complex layouts.

Setting Up GestureDetector

GestureDetector is a widget that allows you to detect user gestures, such as


taps, drags, and swipes, within a widget. This is useful when you want to add
interaction to elements like images, buttons, or other UI components.

The most common gestures detected by GestureDetector are:


● onTap: A tap gesture.
● onDoubleTap: A double-tap gesture.
● onLongPress: A long press gesture.
● onPanUpdate: Detects drag or swipe gestures.
● onHorizontalDragUpdate: Detects horizontal drag gestures.

Example: Creating a Layout with GestureDetector

Here’s an example of creating a layout using Column and setting up


GestureDetector to detect taps on different sections of the UI:

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(home: GestureDetectorExample()));
}

class GestureDetectorExample extends StatelessWidget {


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Gesture Detector Example")),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
print("Tapped on the first container");
},
child: Container(
width: 200,
height: 100,
color: Colors.blue,
child: Center(child: Text('Tap Me', style: TextStyle(color: Colors.white))),
),
),
SizedBox(height: 20),
GestureDetector(
onDoubleTap: () {
print("Double-tapped on the second container");
},
onLongPress: () {
print("Long pressed on the second container");
},
child: Container(
width: 200,
height: 100,
color: Colors.green,
child: Center(child: Text('Double Tap or Long Press', style:
TextStyle(color: Colors.white))),
),
),
],
),
);
}
}

Explanation:

● The Column widget arranges the containers vertically.


● The first container detects a simple tap gesture and prints a message to the
console when tapped.
● The second container detects both double-tap and long press gestures,
printing different messages based on the action.

Using Other Gestures

You can also detect more advanced gestures with GestureDetector. For
instance, you can detect drag gestures using onPanUpdate:
GestureDetector(
onPanUpdate: (details) {
print("Dragged! Position: ${details.localPosition}");
},
child: Container(
width: 100,
height: 100,
color: Colors.orange,
child: Center(child: Text('Drag Me', style: TextStyle(color: Colors.white))),
),
)

In this example, when the user drags the container, it prints the position of the drag.

Summary:

● Layout Widgets: Use Column, Row, Stack, and Container to create


structured and flexible layouts.
● GestureDetector: Detect user interactions like taps, double-taps, long
presses, and drags with simple handlers.
● These tools help in creating interactive and well-structured UIs in Flutter.

UNIT 5:DATABASE AND CLOUD DEPLOYMENT

1.WHAT IS FIREBASE AND FIORESTORE.ADDING THE FIREBASE


AND FIRESTORE BACKEND :FIREBASE AND CLOUD.

What is Firebase?

Firebase is a platform developed by Google that provides various backend services


and tools to help developers build mobile and web applications more easily. It
provides functionalities like authentication, real-time databases, cloud storage, and
hosting, making it easier to manage app data and users without needing to manage
your own server infrastructure.
What is Firestore?

Firestore is a flexible, scalable NoSQL cloud database from Firebase. It allows you
to store and sync data between users and devices in real-time. It is part of Firebase
and works seamlessly with other Firebase features like Firebase Authentication.

Setting Up Firebase and Firestore in Flutter

To integrate Firebase and Firestore into your Flutter app, you need to:

1. Create a Firebase project.


2. Add Firebase to your Flutter project.
3. Use Firestore for storing and retrieving data.

Steps to Set Up Firebase and Firestore in Flutter

1. Add Firebase to your Flutter app:

● Go to the Firebase Console and create a new project.


● Set up Firebase for your iOS or Android app by following the instructions in
the Firebase console.
2. Install Firebase and Firestore dependencies:

In your pubspec.yaml file, add the dependencies for Firebase and Firestore.

dependencies:
flutter:
sdk: flutter
firebase_core: ^2.0.0
cloud_firestore: ^5.0.0

Run flutter pub get to install the dependencies.

3. Initialize Firebase in your app:

In your main.dart file, you need to initialize Firebase before using any Firebase
services.
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

void main() async {


WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(); // Initialize Firebase
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Firebase Example',
home: FirestoreExample(),
);
}
}

4. Using Firestore:

Here’s a simple example to add, read, and display data using Firestore.

class FirestoreExample extends StatefulWidget {


@override
_FirestoreExampleState createState() => _FirestoreExampleState();
}

class _FirestoreExampleState extends State<FirestoreExample> {


final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final TextEditingController _controller = TextEditingController();

// Add data to Firestore


Future<void> _addData() async {
await _firestore.collection('users').add({
'name': _controller.text,
'age': 25, // Example static data
});
}

// Fetch data from Firestore


Stream<List<Map<String, dynamic>>> _getData() {
return _firestore.collection('users').snapshots().map((querySnapshot) {
return querySnapshot.docs.map((doc) {
return doc.data() as Map<String, dynamic>;
}).toList();
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Firestore Example')),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: 'Enter Name',
),
),
),
ElevatedButton(
onPressed: _addData,
child: Text('Add Data'),
),
Expanded(
child: StreamBuilder<List<Map<String, dynamic>>>(
stream: _getData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('No data available.'));
} else {
final data = snapshot.data!;
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(data[index]['name']),
subtitle: Text('Age: ${data[index]['age']}'),
);
},
);
}
},
),
),
],
),
);
}
}

Explanation:

1. Firebase Initialization:

○ The Firebase.initializeApp() method initializes Firebase


before using any Firebase services (Firestore in this case).
2. Adding Data to Firestore:

○ The _addData method adds a new document to the users


collection in Firestore with the entered name and a static age of 25.
3. Reading Data from Firestore:

○ The _getData method listens for real-time changes in the users


collection and retrieves the data as a stream.
○ StreamBuilder listens to this stream and updates the UI with the
data.
4. UI:

○ A TextField to enter the user's name.


○ A button to trigger the data insertion into Firestore.
○ A StreamBuilder to display the fetched data in a ListView.

Firestore Data Structure:

● In this example, a Firestore collection named users is created.


● Each document inside the users collection contains the name and age
fields.

Additional Firebase and Firestore Setup:

● Firebase Authentication: For user management (sign-in, sign-up).


● Firebase Cloud Functions: For running backend code like processing
requests or interacting with other services.
● Firebase Cloud Storage: For storing files such as images or videos.

Summary:

● Firebase is a platform offering various backend services like authentication,


storage, and databases.
● Firestore is a real-time NoSQL database provided by Firebase, useful for
storing and syncing data across users.
● Setting up Firebase and Firestore in Flutter involves adding dependencies,
initializing Firebase, and using Firestore methods like add(), get(), and
snapshots() to handle data.

This setup allows you to manage backend operations like storing user data and
handling real-time updates in your Flutter app.

2.CONFIGURING THE FIREBASE PROJECT

Configuring the Firebase Project for Flutter

To use Firebase services (like Firestore, Authentication, etc.) in your Flutter app,
you need to configure your Firebase project. Below are the steps to configure
Firebase for your Flutter project.

Step-by-Step Guide to Configuring Firebase for Flutter

1. Create a Firebase Project

1. Go to the Firebase Console.


2. Click on "Add project".
3. Follow the prompts to create a new Firebase project:
○ Name your project.
○ Choose your country/region.
○ Opt-in for Google Analytics (optional).
2. Add Firebase to Your Flutter App

Once your Firebase project is created, you need to connect it to your Flutter app.
The steps will be different depending on whether you are using Android or iOS, so
let's go through each.
For Android:

1. In the Firebase Console, go to the Project Overview page and click the
Android icon to add Firebase to your Android app.
2. Register your app by entering the Android package name (found in
android/app/src/main/AndroidManifest.xml).
3. Download the google-services.json file after registration.
4. Move this google-services.json file into your Flutter project's
android/app directory.

For iOS:

1. In the Firebase Console, go to the Project Overview page and click the iOS
icon to add Firebase to your iOS app.
2. Enter your iOS bundle ID (found in ios/Runner.xcodeproj).
3. Download the GoogleService-Info.plist file.
4. Open your Flutter project in Xcode and drag the
GoogleService-Info.plist into the ios/Runner directory of
your Flutter project.
3. Modify Platform-Specific Code:

For Android:

1. Open android/build.gradle and add the following classpath under


dependencies:

classpath 'com.google.gms:google-services:4.3.3'

2. Open android/app/build.gradle and add this line at the bottom of


the file:

apply plugin: 'com.google.gms.google-services'

For iOS:

1. Open the ios/Podfile and add this line if it's not already present:

platform :ios, '10.0'


2. Run pod install from the ios directory to install dependencies.

4. Install Firebase Dependencies in Flutter

Add the necessary Firebase packages to your pubspec.yaml file. For Firestore
and Firebase core, the dependencies will look like this:

dependencies:
flutter:
sdk: flutter
firebase_core: ^2.0.0
cloud_firestore: ^5.0.0
firebase_auth: ^4.0.0 # If you're using Firebase Authentication

Run flutter pub get to install the dependencies.

5. Initialize Firebase in Your Flutter App

Now that you've added Firebase to your project and installed dependencies,
initialize Firebase in the main.dart file before using any Firebase services.

Here’s an example of Firebase initialization:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

void main() async {


WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(); // Initialize Firebase
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Firebase Example',
home: FirestoreExample(),
);
}
}

class FirestoreExample extends StatelessWidget {


final FirebaseFirestore _firestore = FirebaseFirestore.instance;

// Example method to get data from Firestore


Stream<List<Map<String, dynamic>>> _getData() {
return _firestore.collection('users').snapshots().map((querySnapshot) {
return querySnapshot.docs.map((doc) {
return doc.data() as Map<String, dynamic>;
}).toList();
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Firestore Example")),
body: StreamBuilder<List<Map<String, dynamic>>>(
stream: _getData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('No data available.'));
} else {
final data = snapshot.data!;
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(data[index]['name']),
subtitle: Text('Age: ${data[index]['age']}'),
);
},
);
}
},
),
);
}
}

6. Test Your App

● Run your Flutter app using flutter run and verify that Firebase services
are working correctly (e.g., Firestore can store and retrieve data, or Firebase
Authentication can sign in users).
● If everything is set up correctly, your app should be able to interact with
Firebase features such as Firestore and Authentication.

Additional Setup:

● Firebase Authentication: Set up Firebase Authentication if you need to


handle user logins. You can use firebase_auth for this.
● Firebase Storage: If you need cloud storage, use firebase_storage to
upload files.
● Cloud Functions: Set up Firebase Cloud Functions to execute backend code
when specific events happen (e.g., when a document is added to Firestore).

Conclusion:

● To configure Firebase in Flutter, you need to create a Firebase project, add


Firebase to your Flutter app, install dependencies, and initialize Firebase in
the app.
● After configuring, you can easily use Firebase services such as Firestore,
Authentication, and more in your Flutter project.

This guide should help you get started with Firebase in Flutter! Let me know if you
need further assistance with any specific Firebase features.

3.ADDING A CLOUD FIRESTORE DATABASE AND IMPLEMENTING


SECURITY

Adding a Cloud Firestore Database to Your Flutter App

Cloud Firestore is a flexible, scalable NoSQL cloud database for storing and
syncing data in real-time. To add Firestore to your Flutter app and implement
security rules, follow these steps:

Step 1: Set Up Firestore in Your Firebase Project

Before you can add Firestore to your Flutter app, make sure you have created a
Firebase project and connected it to your Flutter app as discussed in the previous
sections.

1. Go to the Firebase Console: Firebase Console.


2. Select your Firebase project.
3. In the left-hand menu, click on Firestore Database.
4. Click on Create database.
5. Choose Start in test mode (you can later switch to secure mode once your
app is working).
6. Set your Firestore location and click Enable.

Step 2: Install Firestore Dependency

In your pubspec.yaml file, add the Firestore dependency:

dependencies:
flutter:
sdk: flutter
firebase_core: ^2.0.0
cloud_firestore: ^5.0.0

Run flutter pub get to install the dependencies.

Step 3: Initialize Firebase in Your App

In your main.dart, initialize Firebase before using Firestore:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

void main() async {


WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Firestore Example',
home: FirestoreExample(),
);
}
}

Step 4: Add Data to Firestore

Here’s a simple example where we add and display data in Firestore:

class FirestoreExample extends StatelessWidget {


final FirebaseFirestore _firestore = FirebaseFirestore.instance;
// Method to add data to Firestore
Future<void> _addData() async {
await _firestore.collection('users').add({
'name': 'John Doe',
'age': 30,
});
}

// Method to get data from Firestore


Stream<List<Map<String, dynamic>>> _getData() {
return _firestore.collection('users').snapshots().map((querySnapshot) {
return querySnapshot.docs.map((doc) {
return doc.data() as Map<String, dynamic>;
}).toList();
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Firestore Example")),
body: Column(
children: [
ElevatedButton(
onPressed: _addData,
child: Text('Add Data'),
),
Expanded(
child: StreamBuilder<List<Map<String, dynamic>>>(
stream: _getData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('No data available.'));
} else {
final data = snapshot.data!;
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(data[index]['name']),
subtitle: Text('Age: ${data[index]['age']}'),
);
},
);
}
},
),
),
],
),
);
}
}

Step 5: Implement Firestore Security Rules

Firestore security rules help you control who can read and write to your Firestore
database.

1. Go to the Firebase Console.


2. In the left-hand menu, click Firestore Database.
3. Click on the Rules tab.
4. Firebase provides some default rules that you can modify for your app's
needs.

Here’s an example of Firestore security rules that allow authenticated users to


read and write their own data:
service cloud.firestore {
match /databases/{database}/documents {
// Allow read and write only if the user is authenticated
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}

Step 6: Handling Authentication

To ensure only authenticated users can access your Firestore database, you can use
Firebase Authentication.
1. Set Up Firebase Authentication

● In the Firebase Console, navigate to Authentication.


● Enable the desired sign-in methods (e.g., Email/Password, Google Sign-In,
etc.).
2. Authenticate Users

Here’s an example using email and password authentication:

1. Add the Firebase Authentication dependency to pubspec.yaml:

dependencies:
firebase_auth: ^4.0.0

2. Implement authentication in your app:

import 'package:firebase_auth/firebase_auth.dart';

class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// Sign up with email and password
Future<User?> signUp(String email, String password) async {
try {
UserCredential userCredential = await
_auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
return userCredential.user;
} catch (e) {
print(e);
return null;
}
}

// Sign in with email and password


Future<User?> signIn(String email, String password) async {
try {
UserCredential userCredential = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
return userCredential.user;
} catch (e) {
print(e);
return null;
}
}

// Sign out
Future<void> signOut() async {
await _auth.signOut();
}

// Get current user


User? getCurrentUser() {
return _auth.currentUser;
}
}

3. Update Firestore Rules

Update your Firestore rules to ensure that users can only access their data. For
example:

service cloud.firestore {
match /databases/{database}/documents {
// Allow read and write to "users" collection if the user is authenticated
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}

This rule ensures that users can only access their own document in the users
collection.

Step 7: Testing Firestore and Security Rules

1. Test Firestore Database:


○ Use Firebase Console to check if your data is being written correctly.
○ Test reading data from your Flutter app.
2. Test Security Rules:
○ Test that only authenticated users can read and write to their data.
○ Ensure that unauthenticated users can't access or modify any data.
Summary

1. Adding Firestore to Flutter: You integrate Firestore by adding Firebase


dependencies, initializing Firebase, and using Firestore methods to read and
write data.
2. Firestore Security Rules: You set up Firestore security rules to control who
can access and modify data in the Firestore database.
3. Firebase Authentication: Implement authentication in your Flutter app to
ensure that only authenticated users can access Firestore data. The security
rules can be modified to allow users to access only their data.

By following these steps, you can effectively use Firestore as a database for your
Flutter app while ensuring data security through Firebase authentication and
Firestore security rules.

You might also like