0% found this document useful (0 votes)
42 views20 pages

Week 11-20

The document provides a comprehensive guide on creating custom widgets in Flutter, including a 'GradientButton' and implementing themes and styles. It covers form creation, validation, and error handling, along with adding animations to UI elements. Additionally, it explains fetching data from a REST API and displaying it in the UI, using an example of an album data retrieval.

Uploaded by

pragna24spam
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)
42 views20 pages

Week 11-20

The document provides a comprehensive guide on creating custom widgets in Flutter, including a 'GradientButton' and implementing themes and styles. It covers form creation, validation, and error handling, along with adding animations to UI elements. Additionally, it explains fetching data from a REST API and displaying it in the UI, using an example of an album data retrieval.

Uploaded by

pragna24spam
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

11. Create custom widgets for specific UI elements.

Creating a Custom Widget:


Now that we understand the benefits, let’s dive into the process of creating a custom widget in Flutter.
In this example, we’ll create a custom “GradientButton” widget that displays a button with a gradient
background.

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

class GradientButton extends StatelessWidget {


final String text;
final List<Color> gradientColors;
final VoidCallback onPressed;

GradientButton({
required this.text,
required this.gradientColors,
required this.onPressed,
});

@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
primary: Colors.transparent,
),
child: Ink(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: gradientColors,
),
borderRadius: BorderRadius.circular(8),
),
child: Container(
alignment: Alignment.center,
child: Text(
text,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
);
}
}

Using the Custom Widget


Once the custom widget is defined, you can easily use it within your app. Import the file where the
GradientButton class is defined and include the widget in your UI tree:

dart
import 'package:flutter/material.dart';
import 'gradient_button.dart'; // Import the custom widget
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Gradient Button Example',
theme: ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
appBar: AppBar(title: Text('Gradient Button Example')),
body: Center(
child: GradientButton(
text: 'Get Started',
gradientColors: [Colors.blue, Colors.green],
onPressed: () {
print('Button pressed!');
},
),
),
),
);
}
}
In this example, we’ve imported the GradientButton widget and used it inside the Center widget in the
MyApp class. The button’s properties are set through the constructor, and the onPressed callback is
defined.
12. Apply styling using themes and custom styles.

Themes
Let us understand how to use ThemeData in Flutter application through the below example.
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
// Define the default brightness and colors.
brightness: Brightness.dark,
primaryColor: Colors.lightBlue,
accentColor: Colors.green,

// Define the default font family.


fontFamily: 'Monotype Coursiva',

// Define the TextTheme that specifies the default


// text styling for headlines, titles, bodies of text, and more.
textTheme: TextTheme(
headline: TextStyle(fontSize: 32.0, fontStyle: FontStyle.italic, fontFamily: 'Hind')
),
),
home: MyThemePage(),
);
}
}

class MyThemePage extends StatelessWidget {


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Theme Example'),
),
body: Center(
child: Container(
color: Theme.of(context).accentColor,
child: Text(
'Themes contains the graphical appearances that makes the user interface more attractive.',
style: Theme.of(context).textTheme.headline,
),
),
),
floatingActionButton: Theme(
data: Theme.of(context).copyWith(
colorScheme:
Theme.of(context).colorScheme.copyWith(secondary: Colors.blue),
),
child: FloatingActionButton(
onPressed: null,
child: Icon(Icons.person),
),
),
);
}
}

Output:

When we run the app in the device or emulator, we will see the UI similar to the below screenshot.

Custom styles

Row(
children: [
Container(
height: 100,
width: 100,
color: Colors.yellow,
padding: EdgeInsets.symmetric(horizontal: 20,vertical: 20),
margin: EdgeInsets.symmetric(horizontal: 50),
child: Text("Styling 1st container"),
),

Container(
height: 100,
width: 100,
color: Colors.red,
padding: EdgeInsets.symmetric(horizontal: 20,vertical: 20),
margin: EdgeInsets.symmetric(horizontal: 10),
child: Text("Styling 2nd container"),
),
],
)
13. Design a form with various input fields.

Flutter provides a Form widget to create a form. The form widget acts as a container, which allows us
to group and validate the multiple form fields. When you create a form, it is necessary to provide
the GlobalKey. This key uniquely identifies the form and allows you to do any validation in the form
fields.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
final appTitle = 'Flutter Form Demo';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: MyCustomForm(),
),
);
}
}
// Create a Form widget.
class MyCustomForm extends StatefulWidget {
@override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
// Create a corresponding State class. This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
final _formKey = GlobalKey<FormState>();

@override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.person),
hintText: 'Enter your name',
labelText: 'Name',
),
),
TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.phone),
hintText: 'Enter a phone number',
labelText: 'Phone',
),
),
TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.calendar_today),
hintText: 'Enter your date of birth',
labelText: 'Dob',
),
),
new Container(
padding: const EdgeInsets.only(left: 150.0, top: 40.0),
child: new RaisedButton(
child: const Text('Submit'),
onPressed: null,
)),
],
),
);
}
}

Output
Now, run the app, you can see the following screen in your Android Emulator. This form contains
three field name, phone number, date of birth, and submit button.
14. Implement form validation and error handling.

Validation is a method, which allows us to correct or confirms a certain standard. It ensures the
authentication of the entered data.

Validating forms is a common practice in all digital interactions. To validate a form in a flutter, we need
to implement mainly three steps.

Step 1: Use the Form widget with a global key.

Step 2: Use TextFormField to give the input field with validator property.

Step 3: Create a button to validate form fields and display validation errors.
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
final appTitle = 'Flutter Form Demo';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: MyCustomForm(),
),
);
}
}
// Create a Form widget.
class MyCustomForm extends StatefulWidget {
@override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
// Create a corresponding State class, which holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
final _formKey = GlobalKey<FormState>();

@override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.person),
hintText: 'Enter your full name',
labelText: 'Name',
),
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.phone),
hintText: 'Enter a phone number',
labelText: 'Phone',
),
validator: (value) {
if (value.isEmpty) {
return 'Please enter valid phone number';
}
return null;
},
),
TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.calendar_today),
hintText: 'Enter your date of birth',
labelText: 'Dob',
),
validator: (value) {
if (value.isEmpty) {
return 'Please enter valid date';
}
return null;
},
),
new Container(
padding: const EdgeInsets.only(left: 150.0, top: 40.0),
child: new RaisedButton(
child: const Text('Submit'),
onPressed: () {
// It returns true if the form is valid, otherwise returns false
if (_formKey.currentState.validate()) {
// If the form is valid, display a Snackbar.
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text('Data is in processing.')));
}
},
)),
],
),
);
}
}
15 Add animations to UI elements using Flutter's animation framework.

Let us see a simple animation example, which uses an animation class and animation controller. The
following example shows the tween animation that gives the start and endpoint of animation. Open
the project and replace the following code in the main.dart file.

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {


// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Animation',
theme: ThemeData(
// This is the theme of your application.
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 2500));
animation = Tween<double>(begin: 0.0, end: 1.0).animate(animationController);
animation.addListener((){
setState((){
print (animation.value.toString());
});
});
animation.addStatusListener((status){
if(status == AnimationStatus.completed){
animationController.reverse();
} else if(status == AnimationStatus.dismissed) {
animationController.forward();
}
});
animationController.forward();
}
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedLogo(
animation: animation,
)
);
}
}
class AnimatedLogo extends AnimatedWidget {
final Tween<double> _sizeAnimation = Tween<double> (begin: 0.0, end: 500.0);
AnimatedLogo({Key key, Animation animation}):super(key: key, listenable: animation);
@override
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Transform.scale(
scale: _sizeAnimation.evaluate(animation),
child: FlutterLogo(),
);
}
}

16. Experiment with different types of animations (fade, slide, etc.).

The following code implements the FadeTransition using the Flutter logo:

import 'package:flutter/material.dart';

/// Flutter code sample for [FadeTransition].

void main() => runApp(const FadeTransitionExampleApp());

class FadeTransitionExampleApp extends StatelessWidget {


const FadeTransitionExampleApp({super.key});

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

class FadeTransitionExample extends StatefulWidget {


const FadeTransitionExample({super.key});

@override
State<FadeTransitionExample> createState() => _FadeTransitionExampleState();
}

/// [AnimationController]s can be created with `vsync: this` because of


/// [TickerProviderStateMixin].
class _FadeTransitionExampleState extends State<FadeTransitionExample>
with TickerProviderStateMixin {
late final AnimationController _controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
late final Animation<double> _animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
);

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

@override
Widget build(BuildContext context) {
return ColoredBox(
color: Colors.white,
child: FadeTransition(
opacity: _animation,
child: const Padding(padding: EdgeInsets.all(8), child: FlutterLogo()),
),
);
}
}

The following code implements the SlideTransition as seen in the video above:

import 'package:flutter/material.dart';

/// Flutter code sample for [SlideTransition].

void main() => runApp(const SlideTransitionExampleApp());

class SlideTransitionExampleApp extends StatelessWidget {


const SlideTransitionExampleApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('SlideTransition Sample')),
body: const Center(
child: SlideTransitionExample(),
),
),
);
}
}

class SlideTransitionExample extends StatefulWidget {


const SlideTransitionExample({super.key});

@override
State<SlideTransitionExample> createState() => _SlideTransitionExampleState();
}

class _SlideTransitionExampleState extends State<SlideTransitionExample>


with SingleTickerProviderStateMixin {
late final AnimationController _controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
late final Animation<Offset> _offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.5, 0.0),
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.elasticIn,
));

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

@override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: FlutterLogo(size: 150.0),
),
);
}
}

17. Fetch data from a REST API.


18. Display the fetched data in a meaningful way in the UI.

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Album> fetchAlbum() async {


final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));

if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}

class Album {
final int userId;
final int id;
final String title;

const Album({
required this.userId,
required this.id,
required this.title,
});

factory Album.fromJson(Map<String, dynamic> json) {


return switch (json) {
{
'userId': int userId,
'id': int id,
'title': String title,
} =>
Album(
userId: userId,
id: id,
title: title,
),
_ => throw const FormatException('Failed to load album.'),
};
}
}

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {


const MyApp({super.key});

@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;

@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}

// By default, show a loading spinner.


return const CircularProgressIndicator();
},
),
),
),
);
}
}
19.Write unit tests for UI components.

Testing is an activity, which is used for verifying and validating a software or application that is bug-
free and meets the user requirements. It ensures that the actual result matches the expected result. It also
helps to improve the software or application in terms of efficiency, usability, and accuracy.

Testing is one of the most important phases in the application development life cycle to ensure the
application is of high quality. It is the most consuming phase in the application or software development.

open the widget_test.dart file and replace the following code:

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

void main() {
testWidgets(The widget contains a title and message', (WidgetTester tester) async {
// Create the widget by telling the tester to build it.
await tester.pumpWidget(MyWidget(title: 'Ti', message: 'Msg'));

// Create the Finders.


final titleFinder = find.text('Ti');
final messageFinder = find.text('Msg');

expect(titleFinder, findsOneWidget);
expect(messageFinder, findsOneWidget);
});
}

class MyAppWidget extends StatelessWidget {


final String title;
final String message;

const MyAppWidget({
Key key,
@required this.title,
@required this.message,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Testing Demo',
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text(message),
),
),
);
}
}

To perform testing, go to the Run menu and select the "test in widget_test.dart" option. It will run the
test and give the result as the following screen:

20. Use Flutter's debugging tools to identify and fix issues.

When you open the debugger tab, you should see the source for the main entry-point for your app
loaded in the debugger.

In order to browse around more of your application sources, click Libraries (top right) or
press Ctrl / Cmd + P. This opens the libraries window and allows you to search for other source
files.
Setting breakpoints
To set a breakpoint, click the left margin (the line number ruler) in the source area. Clicking once sets
a breakpoint, which should also show up in the Breakpoints area on the left. Clicking again removes
the breakpoint.

The call stack and variable areas


When your application encounters a breakpoint, it pauses there, and the DevTools debugger shows the
paused execution location in the source area. In addition, the Call stack and Variables areas
populate with the current call stack for the paused isolate, and the local variables for the selected
frame. Selecting other frames in the Call stack area changes the contents of the variables.

Within the Variables area, you can inspect individual objects by toggling them open to see their
fields. Hovering over an object in the Variables area calls toString() for that object and
displays the result.

Stepping through source code


When paused, the three stepping buttons become active.

• Use Step in to step into a method invocation, stopping at the first executable line in that
invoked method.
• Use Step over to step over a method invocation; this steps through source lines in the current
method.
• Use Step out to step out of the current method, without stopping at any intermediary lines.

In addition, the Resume button continues regular execution of the application.

You might also like