Unit - 4
Unit - 4
A typical example is a login form, in which the app generally could ask you for email and password. Once a
confirmation button in pressed, an HTTP request or another type of authentication process happens
Different functions to create form and validate
Form()
_formKey is used to uniquely identify the form and validate it later.
dispose()
dispose() is called when the widget is removed from the widget tree.
It frees up resources by disposing the controllers, which is important for
memory management.
Form submission()
This function is triggered when the user clicks the Submit button.
It checks if the form is valid (validate()).If valid, it shows a small notification
(SnackBar) and prints the entered data.
SnackBar()
If valid, it shows a small notification (SnackBar) and prints the entered data.
Steps to create a form
void main() {
runApp(MyApp());
}
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
super.dispose();
}
void _submitForm() {
if (_formKey.currentState!.validate()) {
// Process data
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Processing Data')),
);
print('Name: ${_nameController.text}');
print('Email: ${_emailController.text}');
}
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _nameController,
decoration: InputDecoration(labelText: 'Name'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your name';
}
return null;
},
),
TextFormField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
if (!RegExp(r'\S+@\S+\.\S+').hasMatch(value)) {
return 'Please enter a valid email address';
}
return null;
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _submitForm,
child: Text('Submit'),
),
],
),
);
}
}
Gestures
Purpose: Allows for more natural or immersive interactions, often hidden or less
explicit.
onTap,
onDoubleTap,
onLongPress,
onVerticalDragStart,
onVerticalDragEnd
Swipe to Dismiss
Gestures Detector
GestureDetector(
onDoubleTap: () {
print("Double tapped");
},
onLongPress: () {
print("Long pressed");
},
child: Container(
color: Colors.red,
width: 100,
height: 100,
),
)
Steps for Creating Gesture in Flutter
Step 1 : Importing Material Library
Step 2 : main() Function
Step 3 : MyApp Class
Step 4 : Gesture Example
Step 5 : Creating state class for Gesture
Step 6 : Create handleTap()
Step 7 : Use GestureDetector()
Step 8 : Make use of onTap()
Example for Gesture
Code :
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
void _handleTap() {
setState(() {
_message = 'Box tapped!';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Gesture Example")),
body: Center(
child: GestureDetector(
onTap: _handleTap,
child: Container(
width: 150,
height: 150,
color: Colors.blue,
child: Center(
child: Text(
_message,
style: TextStyle(color: Colors.white),
textAlign: TextAlign.center,
),
),
),
),
),
);
}
}
Tap Gestures
Callback Description
onTap Called when the user taps the widget.
Called when a pointer that might cause a tap has
onTapDown
contacted the screen.
onTapUp Called when a tap has occurred.
onTapCancel Called when the tap gesture was aborted.
onDoubleTap Called when the user double-taps.
onLongPress Called when the user presses for a long duration.
onLongPressStart Called when a long press gesture starts.
onLongPressMoveUpdate Called when the pointer moves during a long press.
Called when the user lifts their finger after a long
onLongPressEnd
press.
Called when the user releases the pointer after a long
onLongPressUp
press.
Drag Gestures (Pan)
Callback Description
onPanEnd Called when the user lifts their finger after a pan.
Callback Description
onScaleStart Called when a scale gesture starts (pinch or zoom).
onScaleUpdate Called when the user changes the scale.
onScaleEnd Called when the scale gesture ends.
GestureDetector(
onTap: () => print("Tapped"),
onDoubleTap: () => print("Double Tapped"),
onLongPress: () => print("Long Pressed"),
onPanUpdate: (details) => print("Panning: ${details.delta}"),
onScaleUpdate: (details) => print("Scaling: ${details.scale}"),
child: Container(
width: 150,
height: 150,
color: Colors.green,
),
)
Flutter Route Navigation
Organizing information across several screens is one of the most important
building blocks of any architecture.
In the Flutter world, your app’s pages are called routes, or screens, and they are
the equivalent of Activities in Android or ViewControllers in iOS.
Very intuitively, routes/ is going to contain all those UI widgets representing a route of the app.
Inside widgets/ we recommend putting all those reusable widgets that support the creation of your
app’s pages.
Placing this code in widgets/footer_name.dart is very convenient because you know it’s an "utility"
piece of UI that will be reused across multiple pages as a footer. It can be integrated with const
FooterName() and a simple change on footer_name.dart is automatically reflected everywhere.
Steps for Navigation & Routing
1. Creation of Routes
2. The main.dart file (Setup the routes)
3. The routes.dart file
4. Navigation between the pages
5. Navigator 2.0
1.Creation of Routes
We’re going to create a simple application with two screens: HomePage, the
first route which appears when the app starts, and RandomPage, a route that
displays a random number at the center of the screen.
// Located in routes/random_page.dart
2. The main.dart file
Steps in main.dart file
1.This is the widget located at the root of the tree which has the task to setup
the various routes and redirect the user to the first page.
2. This is a string. We’re going to explain what is RouteGenerator in a moment;
it basically tells Flutter which is the first route that has to be loaded.
3. This is a method reference. The navigation between pages in Flutter works
like if you were using a browser. Each page has a name, which is like an "url" and
you show a page by "navigating" to that address
Route Generator
Navigator.pushNamed(context, '/home');
3. The routes.dart file
There must be a route named '/' which has to map to the first page that’s being shown when
your app starts. It’s a requirement, not a just a good practice.
1. Actually this class is just a "wrapper" for a single static function because declaring global
functions is possible, but it’s not a good idea.generateRoute() is the main actor.
2. Each page of the app is uniquely identified by a string; it’s the same thing you’re used to
see on the internet where web pages are identified by URLs. In this case:
• The HomePage route is associated with the '/' path
• The RandomPage route is associated with the '/random' path
Do you want to press on a button and show the RandomPage widget? It’s very easy, you
just need to write...
Navigator.of(context)?.pushNamed(RouteGenerator.randomPage);
... and the new screen appears. The pushNamed() method takes a path, which is linked to
a page, and navigates to it; in this case it looks for '/random' and shows the widget that’s
been assigned to it.
4.Navigation between the pages
At this point, we have our routes properly set up inside routes.dart and we’re
ready to move
from one page to the other. A quick recap of the job we’ve done so far:
• creation of two routes called HomePage and RandomPage;
• setup of the routes in the MaterialApp() of main.dart;
• The creation of the RouteGenerator class which maps an URI to a widget so
that the
Navigator class can open routes
5. Navigator 2.0
Passing data between pages and widgets
1. in a layout with many tabs, you need to pass data from a tab to another;
2. you have a route (a page) which has to send a primitive type or a complex
object to another route when navigating to it;
3. in the same page, two widgets need to exchange data.
Navigator Class
The Navigator class allows you to move from a route to another going back and
forth. The pages you navigate to are "overlapped" and the framework keeps
track of them using a stack.
How to use Navigator :
Navigator.of(context)?.pushNamed("/route_name")
Navigator.of(context)?.pop()
Navigator.pushNamed(context, "/route_name")
Navigator.pop(context)
Passing data with Navigator
We’re creating a simple to-do app; when an item of the list is tapped, a new
route appears with a description of the selected to-do.
In the first page, called TodosPage, we’re creating a list of Todos that are
displayed using a ListView.
When a to-do is tapped, a new route called InfoPage is opened to show the
description of the selected item.
Info page
Flutter Animations
Flutter animation refers to the process of adding motion and visual effects to
Flutter app’s UI components to enhance user experience.
Flutter provides a powerful and flexible framework for creating both simple and
complex animations.
1.Implicit Animations
2.The animation library
3.Custom Animations
1.Implicit Animations
Easier to implement.
Use built-in widgets like AnimatedContainer, AnimatedOpacity, AnimatedAlign,
etc.
You just change a property, and Flutter animates the change for you.
Example :
AnimatedContainer(
duration: Duration(seconds: 1),
width: isExpanded ? 200 : 100,
height: 100,
color: Colors.blue,
);
Implicit animation in Flutter allows you to animate changes to a widget’s
properties with minimal code. Flutter handles the animation automatically
when the property changes.
Key Points :
Uses special animated widgets.
You specify a duration and the framework animates the transition.
No need for AnimationController or Tween.
Common Implicitly Animated Widgets:
AnimatedContainer
AnimatedOpacity
AnimatedAlign
AnimatedPadding
AnimatedPositioned
AnimatedCrossFade
AnimatedDefaultTextStyle
Steps for Implicit Animation
Step 1 : Import the Flutter material package
Step 2 : Main function - Entry Point
Step 3 : Root Widget (MyApp)
Step 4 : AnimationDemo Stateful Widget & State Class (_AnimationDemoState)
Step 5 : UI Build Method
Step 6 : Floating Action Button
AnimatedContainer - Example
import 'package:flutter/material.dart';
Flutter provides a rich set of animation libraries built into the framework. These
are part of the flutter/animation.dart and flutter/widgets.dart packages,
giving you tools for both implicit and explicit animations.
•AnimatedContainer
•AnimatedOpacity
•AnimatedAlign
•AnimatedPadding
•AnimatedPositioned
•AnimatedCrossFade
•AnimatedSwitcher
•AnimatedDefaultTextStyle
2.Explicit Animation Library
Used for fine-grained control over animations. Requires managing an
AnimationController.
Core Classes:
AnimationController
AnimationTween :
Animated.timing()
Animated.spring()
Animated.decay()
AnimatedBuilder
AnimatedWidget
AnimationController
In Flutter, the AnimationController is a core class used to manage animations.
It provides control over animation timing, including starting, stopping,
reversing, and repeating animations.
AnimationController({
required TickerProvider vsync,
Duration? duration,
double lowerBound = 0.0,
double upperBound = 1.0,
double value = 0.0,
})
AnimationTween :
1. Animated.timing()
Description: Animates a value over a set duration using easing functions.
Use case: Standard animations like fade, translate, or scale over time.
2. Animated.spring()
Description: Animates using spring physics. It creates a bouncy, natural
motion.
Use case: Buttons, popups, or any element needing "physical" feel.
3. Animated.decay()
Description: Starts with an initial velocity and gradually slows down to a stop.
Use case: Flick/swipe gestures, like when scrolling stops naturally.
3.Animation Curves
Curves define timing and easing of animations to make them feel natural.
Common Curves:
Curves.easeIn
Curves.easeOut
Curves.bounceIn
Curves.elasticOut
Curves.linearToEaseOut
Common Curves
1.Curves.easeIn
Description: Starts slow, then speeds up toward the end.
Use Case: Great for fade-ins, entering elements, or when you want to draw the user's
attention at the end of the motion.
2.Curves.easeOut
Description: Starts fast, then slows down at the end.
Use Case: Used for elements exiting, like sliding out panels or fading out text.
3. Curves.bounceIn
Description: Begins by bouncing before reaching the final value — it overshoots and
rebounds into place.
Use Case: Playful entry animations like buttons or emojis popping into view.
Behavior: The object appears to bounce as it enters.
4.Curves.elasticOut
Description: Overshoots its final position and then bounces back with an elastic
effect.
Use Case: Great for dramatic, elastic animations like popping UI elements or
bouncing balls.
5.Curves.linearToEaseOut
Description: Starts with a constant speed (linear) and then eases out (slows
down).
Use Case: Good for smooth transitions where speed consistency is needed
initially, like loading indicators or progress bars.
4.Physics-based Animation
Animations based on real-world physics such as springs, friction, or gravity.
Classes:
SpringSimulation
FrictionSimulation
BouncingScrollSimulation
DraggableScrollableSheet
AnimatedPhysics
SpringSimulation
simulates a spring using three key parameters:
mass: The mass of the object.
stiffness: How strong the spring is.
damping: How quickly the spring stops oscillating.
It's part of the Flutter physics engine (flutter/physics.dart), and typically used
with a Ticker or AnimationController
FrictionSimulation
It simulates an object that starts with a certain initial velocity and slows down
over time due to a drag (friction) factor.
FrictionSimulation(
double drag, // friction or resistance (typically between 0 and 1)
double position, // starting position
double velocity // initial velocity
)
BouncingScrollSimulation
In Flutter, BouncingScrollSimulation is a physics simulation that mimics the iOS-style
bouncy scrolling behavior when the user overscrolls a scrollable area.
It’s typically used under the hood by Flutter's scroll physics but can also be used
directly for custom simulations or animations.
BouncingScrollSimulation({
required double spring,
required double position,
required double velocity,
required double leadingExtent,
required double trailingExtent,
Tolerance tolerance = Tolerance.defaultTolerance,
})
DraggableScrollableSheet
in Flutter is a built-in widget that allows you to create a scrollable bottom sheet that
users can drag up and down. It’s great for features like bottom drawers, expandable
panels, or nested scroll views.
DraggableScrollableSheet(
initialChildSize: 0.3, // default visible height (30%)
minChildSize: 0.1, // minimum height (10%)
maxChildSize: 0.9, // maximum height (90%)
builder: (context, scrollController) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
boxShadow: [BoxShadow(blurRadius: 10, color: Colors.black26)],
),
child: ListView.builder(
controller: scrollController, // important!
itemCount: 25,
itemBuilder: (context, index) => ListTile(
title: Text('Item #$index'),
),
5.Third-party Animation Libraries
1. flutter_animate
•Chainable, declarative animations.
•Easy syntax: Text("Hi").animate().fade().scale()
2. lottie
•Render After Effects animations exported as JSON.
3. rive
•State machine-based, interactive animations.
4. simple_animations
•Simplified API for timeline-based complex animations.
5. animated_text_kit
•Animated text effects like typewriter, wave, fade, etc.
Custom Animations
• Creating custom animations in Flutter gives you full control over how widgets
animate—positions, sizes, opacity, colors, and more.
Stack: overlaps a series of children and allows custom positioning using the
Positioned widget.
Key Terms :
SingleTickerProviderStateMixin: Allows this state object to act as a
TickerProvider, which is required by the AnimationController (to manage frame
ticks efficiently).
late final: Means the variable will be assigned later (in initState) but only once.
_controller: Manages the animation's timing (start, stop, repeat, etc.).
vsync: this: Provides the ticker using the current class (which mixes in
SingleTickerProviderStateMixin).
Matrix4.skewY(0.1): Applies a vertical skew (shearing the widget slightly)..
rotateY(...): Chains a Y-axis 3D rotation (full circle over the animation).
value * 2π: Maps the 0–1 animation range to a full 360° rotation.
child: This is the unchanged Container
Steps for Custom Animation
Step 1 : Importing Material libraries
Step 2 : Main Function
Step 3 : Route Widget
Step 4 : DemoApp
Step 5 : Create state for DemoAppState(_DemoAppState)
Step 6 : Create initState()
Step 7 : call dispose()
Step 8 : For rebuild use - AnimatedBuilder()
Step 9 : use Transform()
Step 10 : Skew()
Step 11: Container()
import 'package:flutter/material.dart';
scale: Starts at 1.0 (normal size) and shrinks to 0.5 as animation progresses.
newPos: Starts at 20 pixels and moves up to 420 pixels diagonally (both X and Y).