UI Design Flutter For CSE
UI Design Flutter For CSE
1
Regulation: NR23
Narsimha Reddy Engineering College III B.Tech. I
(Autonomous) Semester
Code: 23CS517 L T P
UI Design-Flutter Lab
Credits: 1 - - 2
Course Objectives:
• Learns to Implement Flutter Widgets and Layouts
• Understands Responsive UI Design and with Navigation in Flutter
• Knowledge on Widges and customize widgets for specific UI elements, Themes
• Understand to include animation apart from fetching data
Course Outcomes: At the end of the course, students will be able to:
• Implements Flutter Widgets and Layouts
• Responsive UI Design and with Navigation in Flutter
• Create custom widgets for specific UI elements and also Apply styling using themes and custom styles.
• Design a form with various input fields, along with validation and error handling
• Fetches data and write code for unit Test for UI components and also animation
10.
a) Write unit tests for UI components.
b) Use Flutter's debugging tools to identify and fix issues.
TEXT BOOK: Marco L. Napoli, Beginning Flutter: A Hands-on Guide to App Development.
2
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
b) for your operating system (Windows, macOS, or Linux).
c) 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
d) 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.
g) 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.
h) 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".
3
// Printing variables
print('My number is: $myNumber');
print('My double is: $myDouble'); print('My string is: $myString'); print('My boolean is: $myBool');
// 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:
4
Lab Session 2:
Flutter provides a rich set of widgets to build user interfaces for mobile,web,and desktop
applications.These widgets help in creating visually appealing and interactive UIs. Here are some
of the commonly used Flutter widgets categorized by their functionalities:
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.
ListView and GridView: 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
floatingaction buttons.
RichText: Allows for more complex text styling and formatting, including different styles within the
same text span.
TextStyle: A class for defining text styles that can be applied to Text widgets.
Input Widgets:
TextField: 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.
Button Widgets:
ElevatedButton and TextButton: Widgets for displaying buttons with different styles and
customizationoptions.
IconButton: A button widget that displays an icon and responds to user taps.
GestureDetector: A versatile widget that detects gestures such as taps, swipes, and drags, allowing for
custom interactions.
5
Icon: Displays a Material Design icon.
Navigation Widgets:
Navigator: Manages a stack of route objects and transitions between different screens or pages in the
app.
Animation Widgets:
AnimatedContainer: An animated version of the Container widget, with support for transitioning
properties over a specified duration.
BottomNavigationBar: 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.
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.
6
width: 100,
height: 100,
),
Container(
color: Colors.green,
width: 100,
height: 100,
),
Container(
color: Colors.blue,width: 100,
height: 100,
),
],
),
),
);
}
}
Output:
2. Column Layout:
Output:
3. Stack Layout:
import 'package:flutter/material.dart'; void main() {
runApp(MyApp());
}
),
body: Stack(
alignment: Alignment.center,children:
<Widget>[
Container(
color: Colors.red,width: 200,
height: 200,
8
),
Container(
color: Colors.green,width: 150,
height: 150,
),
Container(
color: Colors.blue,width: 100,
height: 100,
),
],
),
),
);
}
}
Output:
9
Lab Session 3:
Output:
Mobile View:
Desktop View:
11
b) Implement media queries and breakpoints for responsiveness
12
SizedBox(height: 20), ElevatedButton( onPressed: ()
{}, child: Text('Button'),
),
],
),
);
}
13
),
],
),
],
),
);
}
}
Output:
14
Lab Session 4:
Output:
Navigator.pushNamed(context, '/second');
},
child: Text('Go to Second Screen'),
),
),
);
}
}
class SecondScreen extends StatelessWidget { @override
Widget build(BuildContext context) { return Scaffold(
appBar: AppBar(
title: Text('Second Screen'),
),
body: Center(
child: ElevatedButton( onPressed: () {
Navigator.pushNamed(context, '/third');
},
child: Text('Go to Third Screen'),
),
),
);
}
}
appBar: AppBar(
title: Text('Third Screen'),
),
body: Center(
child: ElevatedButton( onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
},
child: Text('Go Back to Home'),
),
17
),
);
}
}
Output:
18
Lab Session 5:
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';
}
}
@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:
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,
20
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:
21
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.
@override
Widget build(BuildContext context) { return Scaffold(
appBar: AppBar(
title: Text('Counter Example (setState)'),
),
body: Center( child:
22
Column(
mainAxisAlignment: MainAxisAlignment.center,children:
<Widget>[ Text(
'Counter Value:',
),
Text( '$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton( onPressed: _incrementCounter,
tooltip: 'Increment', child: Icon(Icons.add),
),
);
}
}
Output:
23
lOMoAR cPSD| 37701387
main() { runApp(ChangeNotifierProvider<MovieProvider>(child:
const MyApp(),
create: (_) => MovieProvider(), // Create a new ChangeNotifier object
));
}
@override
Widget build(BuildContext context) {
return MaterialApp(
// Remove the debug banner debugShowCheckedModeBanner: false,title:
'State Management using provider',theme:
ThemeData(
primarySwatch: Colors.indigo,
),
create a model folder for models and create file movie.dart class Movie {
final String title;
final String? runtime; // how long this movie is (in minute)
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"));
initialData;
// Favorite movies (that will be shown on the MyList screen) final List<Movie> _myList = [];
movie) {
_myList.add(movie); notifyListeners();
}
// screens/home_screen.dart
import 'package:flutter/material.dart'; import 'package:provider/provider.dart';
@override
State<HomeScreen> createState() => _HomeScreenState();
}
size: 30,
),
onPressed: () {
if (!myList.contains(currentMovie)) {context
.read<MovieProvider>()
.addToList(currentMovie);
} else { context
.read<MovieProvider>()
.removeFromList(currentMovie);
}
},
),
),
);
}),
),
],
),
),
);
}
}
26
lOMoAR cPSD| 37701387
// screens/my_list_screen.dart
import 'package:flutter/material.dart'; import 'package:provider/provider.dart';
@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:
27
lOMoAR cPSD| 37701387
we use the provider package to manage state. We define a Counter class that extends
ChangeNotifier, and the counter value is stored inside it. Whenever the counter is incremented,
we call notifyListeners() to informthe listeners about the change.
28
lOMoAR cPSD| 37701387
Lab Session 6:
AppBar(
title: Text('Custom Widget Example'),
),
body: Column( mainAxisAlignment:
MainAxisAlignment.center,children:
<Widget>[ Padding( padding: const
EdgeInsets.all(8.0),child: CustomTextField( hintText: 'Enter your name', onChanged: (value) {
print('Name changed:
$value');
},
),
),
SizedBox(height
: 20),Padding( padding: const
EdgeInsets.all(8.0),child: CustomTextField( hintText: 'Enter Email', onChanged: (value) {
print('Name changed:
$value');
},
),
),
SizedBox(height
: 20),Padding( padding: const
EdgeInsets.all(8.0),child: CustomTextField( hintText: 'Enter Roll Number', onChanged: (value) {
print('Name changed: $value');
},
),
),
SizedBox(height
: 20),
CustomButton( text: 'Press Me', onPressed: () {
print('Button pressed!');
},
),
],
29
lOMoAR cPSD| 37701387
),
),
);
}
}
@override Widget
build(BuildContext context) {return TextField( onChanged: onChanged, decoration:
InputDecoration( hintText: hintText,
border: OutlineInputBorder(),
),
);
}
}
Output:
30
lOMoAR cPSD| 37701387
In Flutter, you can apply styling to your widgets using themes and custom styles to maintain
consistency and make your UI morevisually appealing.
),
),
),
home: HomePage(),
);
}
}
style: Theme.of(context).textTheme.headline1,
),
SizedBox(height
: 20),
ElevatedButton( onPressed: () {},
child: Text('Get Started'),
),
],
),
),
);
}
}
Output:
In this example:
We define a custom theme using ThemeData and apply it to the entire app using the theme
property ofMaterialApp.
The theme specifies primary and accent colors, a custom font family, and text styles for different
textelements (headline6 and bodyText2).
In the HomePage widget, we use Theme.of(context) to access the custom theme properties and
applythem to various widgets such as Text and ElevatedButton.
We also demonstrate custom styling for a Container widget with a custom background
color and borderradius.
Using themes and custom styles like this helps maintain a consistent visual identity throughout
your app and makes it easier to manage and update styling across multiple widgets.
32
lOMoAR cPSD| 37701387
Lab Session 7:
form with various input fields such as text fields, checkboxes, radio buttons, and a dropdown
menuimport 'package:flutter/material.dart';
void main()
{
runApp (MyAp p());
}
St ri ng
_n a m e; St ri ng
_e m ail
;
bool
_subscribeToNewsletter
= false;String
_selectedCountry = 'USA'; @override Widget
build(BuildContext context) {return Scaffold( appBar: AppBar(
title: Text('Form Example'),
),
body: Padding( padding: EdgeInsets.all(20.0), child: Form(
key:
_formKe y,child:
Column( crossAxisAlignment:
CrossAxisAlignment.start,children:
<Widget>[ TextFormField(
_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('Subscribe to Newsletter'),
],
),
SizedBox(height:
20),Row(
children: <Widget>[ Text('Country: '), SizedBox(width: 20), DropdownButton<String>( value:
_selectedCountry, onChanged: (value) { setState(() {
_selectedCountry = value;
}); },
),
SizedBox(height:
20),
ElevatedButton( onPressed: () {
_formKey.currentState.save();
// Submit the form data print('Name:
$_name'); print('Email:
$_email');
print('Subscribe to Newsletter: $_subscribeToNewsletter'); print('Country: $_selectedCountry');
},
child: Text('Submit'),
),
34
lOMoAR cPSD| 37701387
],
),
),
),
);
}
}
Output:
.dart';void main() {
runApp(MyApp());
}
body:
SingleChildScrollVie w(padding:
EdgeInsets.all(16), child: FormWidget(),
),
),
);
}
35
lOMoAR cPSD| 37701387
String_name;
String_emai l; String_pass word; String_phon e; String_addr ess;
@override Widget
build(BuildContext context) {return Form( key:
_form Key, child:
Colum n(
crossAxisAlignment: CrossAxisAlignment.start,children:
<Widget>[ TextFormField(
decoration: InputDecoration(labelText: 'Name'),validator: (value) {
if (value.isEmpty) {
return 'Please enter your name';
}
return null;
},
onSaved: (value) => _name = value,
),
SizedBox(heig ht: 16),
TextFormField (
decoration: InputDecoration(labelText: 'Email'),keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value.isEmpty) {
return 'Please enter your email';
}
// Add more complex email validation logic if neededreturn null;
},
),
SizedBox(heig ht: 16),
TextFormField (
decoration: InputDecoration(labelText: 'Phone'),keyboardType: TextInputType.phone,
validator: (value) { if (value.isEmpty) {
return 'Please enter your phone number';
}
// Add more complex phone number validation logic if neededreturn null;
},
onSaved: (value) => _phone = value,
),
SizedBox(heig ht: 16),
TextFormField (
decoration: InputDecoration(labelText:
'Address'),maxLines: 3, validator: (value) {
if (value.isEmpty) {
return 'Please enter your address';
}
return null;
},
onSaved: (value) => _address = value,
),
SizedBox(height:
16),
ElevatedButton( onPressed:
_submitForm, child:
Text('Submit'),
),
],
),
);
}
void _submitForm() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
// Perform form submission with the saved form dataprint('Form submitted:'); print('Name:
$_name');
print('Email:
$_email'); print('Password:
$_password'); print('Phone:
$_phone'); print('Address:
$_address');
}
}
}
37
lOMoAR cPSD| 37701387
Output:
38
lOMoAR cPSD| 37701387
Lab Session 8:
@override void
initSt ate() { super. initSt ate();
_controller = AnimationController( duration:
Duration(seconds: 1), vsync: this,
);
_animation = Tween<double>(begin: 0, end: 300).animate(_controller)
..addListener(() {
setState(() {}); // Trigger rebuild when animation value changes
});
}
@override Widget
build(BuildContext
39
lOMoAR cPSD| 37701387
@override
void dispose() {
_controller
.dispose(); super.disp ose();
}
}
Output:
40
lOMoAR cPSD| 37701387
We define an Animation object with Tween to define the range of values for the animation.I
nside the initState() method, we initialize the animation controller and define the animation.We
use addListener() to trigger a rebuild when the animation value changes.
In the build method, we use the animated value _animation.value to control the size of the
Container, whichcontains the FlutterLogo.
The ElevatedButton toggles the animation between forward and reverse based on the status of the
animationcontroller.
You can customize the animation further by adjusting the duration, adding curves, or chaining
multipleanimations together.
void main()
{
runApp (MyAp p());
}
class MyApp extends StatelessWidget { @override
Widget build(BuildContext context) {return MaterialApp( home:
Scaffold( appBar:
AppBar(
title: Text('Fade Animation Example'),
),
body: FadeAnimation(),
),
);
}
}
class FadeAnimation extends StatefulWidget {
@override
_FadeAnimationState createState() => _FadeAnimationState();
}
@override void
initSt ate() { super. initSt ate();
_controller = AnimationController( vsync: this,
duration: Duration(seconds: 2),
);
_animation = Tween<double>( begin: 0.0,
41
lOMoAR cPSD| 37701387
end: 1.0,
).animate(_controller);
_controller.forward();
}
@override Widget
build(BuildContext context) {return Center( child:
FadeTransiti on(opacity:
_animation, child:
Container( width: 200,
height: 200,
color: Colors.blue,
),
),
);
}
@override
void dispose() {
_controller
.dispose(); super.disp ose();
}
}
Slide Animation:
import 'package:flutter/material.dart';
void main()
{
runApp (MyAp p());
}
@override Widget
build(BuildContext context) {return Center( child:
SlideTransiti on(position:
_animation, child:
Container( width: 200,
height: 200,
color: Colors.blue,
),
),
);
}
@override
void dispose() {
_controller
.dispose(); super.disp ose();
}
}
Scale Animation:
import 'package:flutter/material.dart';
void main()
{
runApp (MyAp p());
}
43
lOMoAR cPSD| 37701387
MaterialApp( home:
Scaffold( appBar:
AppBar(
title: Text('Scale Animation Example'),
),
body: ScaleAnimation(),
),
);
}
}
@override void
initSt ate() { super. initSt ate();
_controller = AnimationController( vsync: this,
duration: Duration(seconds: 2),
);
_animation = Tween<double>( begin: 0.0,
end: 1.0,
).animate(_controller);
_controller.forward();
}
44
lOMoAR cPSD| 37701387
Output:
45
lOMoAR cPSD| 37701387
Lab Session 9:
void main()
{
runApp (MyAp p());
}
if (response.statusCode
== 200) {setState(() {
_data = json.decode(response.body);
});
} else {
throw Exception('Failed to load data');
}
}
@override Widget
build(BuildContext context) {return Scaffold( appBar: AppBar(
46
lOMoAR cPSD| 37701387
void main()
{
runAp p(My App()
);
}
47
lOMoAR cPSD| 37701387
}
}
@override void
initSt ate() { super. initSt ate();
_fetchDataFromApi();
}
Future<void>
_fetchDataFromApi() async { setState(() {
_isLoading = true;
});
(response.statusCode == 200) {
setState(() {
_data = json.decode(response.body);
_isLoading = false;
});
} else {
throw Exception('Failed to load data');
}
}
@override
Widget build(BuildContext context) {return Scaffold( appBar: AppBar(
title: Text('API Data Example'),
),
body: _isLoading
? Center(
child: CircularProgressIndicator(),
)
: ListView.builder( itemCount:
_data.length, itemBuilder: (context, index) {return PostCard( title: _data[index]['title'], body:
_data[index]['body'],
);
},
),
48
lOMoAR cPSD| 37701387
);
}
}
@override Widget
build(BuildContext context) {return Card(
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),child: Padding(
padding:
EdgeInsets.all(16),
),
),
);
}
}
Output:
49
lOMoAR cPSD| 37701387
50
lOMoAR cPSD| 37701387
);
// Verify that the title and body are displayed correctly.expect(find.text('Test Title'),
findsOneWidget); expect(find.text('Test Body'), findsOneWidget);
});
// Verify that the text styles are applied correctly. final titleText =
tester.widget<Text>(find.text('Test Title'));expect(titleText.style.fontSize, 18);
expect(titleText.style.fontWeight, FontWeight.bold);
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 theirproperties match the expected values.
51
lOMoAR cPSD| 37701387
Make sure to replace your_app with the appropriate package name where your PostCard widget
resides.
Make sure to provide different test scenarios and edge cases to ensure comprehensive test
coverage for yourUI components.
void main()
{
runApp (MyAp p());
}
void _incrementCounter() {
_counter++;
}
@override Widget
build(BuildContext context) {return Scaffold( appBar: AppBar(
title: Text('Counter App'),
),
body:
Center ( child:
Colum n(
'Counter:',
style: TextStyle(fontSize: 24),
),
Text( '$_cou nter',
style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
),
],
),
),
floatingActionButton:
FloatingActionButton(onPressed:
_incrementCounter, tooltip:
'Increment', child:
Icon(Icons.ad d),
),
);
}
}
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/IntelliJIDEA 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 onPressedcallback 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('Incrementing counter');
_counter++;
}
53
lOMoAR cPSD| 37701387
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 onPressed callback of the
FloatingActionButton to ensure it's correctly wired to the _incrementCounter method.
54