0% found this document useful (0 votes)
25 views

Flutter Lab Week 7 to 10

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)
25 views

Flutter Lab Week 7 to 10

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/ 18

Lab Session 7:

a) Design a form with various input fields

form with various input fields such as text fields, checkboxes, radio buttons, and a dropdown menu
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Form Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FormPage(),
);
}
}

class FormPage extends StatefulWidget {


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

class _FormPageState extends State<FormPage> {


final _formKey = GlobalKey<FormState>();

String _name;
String _email;

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: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Name'),
onSaved: (value) {
_name = value;
},
),
SizedBox(height: 20),
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
onSaved: (value) {
_email = value;
},
),
SizedBox(height: 20),
Row(
children: <Widget>[
Checkbox(
value: _subscribeToNewsletter,
onChanged: (value) {
setState(() {
_subscribeToNewsletter = value;
});
},
),
Text('Subscribe to Newsletter'),
],
),
SizedBox(height: 20),
Row(
children: <Widget>[
Text('Country: '),
SizedBox(width: 20),
DropdownButton<String>(
value: _selectedCountry,
onChanged: (value) {
setState(() {
_selectedCountry = value;
}); },

items: <String>['USA', 'Canada', 'UK', 'Australia']


.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
],

),
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'),
),
],
),
),
),
);
}
}Output:

b) Implement form validation and error handling


import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Form Example'),
),

body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: FormWidget(),
),
),
);
}
}

class FormWidget extends StatefulWidget {


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

class _FormWidgetState extends State<FormWidg5e6t> {


final _formKey = GlobalKey<FormState>();

String _name;
String _email;
String _password;
String _phone;
String _address;

@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
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(height: 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 needed
return null;
},

onSaved: (value) => _email = value,


),
SizedBox(height: 16),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: (value) {
if (value.isEmpty) {

return 'Please enter a password';


}
// Add more complex password validation logic if needed
return null;
},
onSaved: (value) => _password = value,
),
SizedBox(height: 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 needed
return null;
},
onSaved: (value) => _phone = value,
),
SizedBox(height: 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 data


print('Form submitted:');
print('Name: $_name');

print('Email: $_email');
print('Password: $_password');
print('Phone: $_phone');
print('Address: $_address');
}
}
}

Output:
Lab Session 8:

a) Add animations to UI elements using flutter's animation framework


import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Animation Example'),
),
body: AnimationWidget(),
),
);
}
}

class AnimationWidget extends StatefulWidget {


@override
_AnimationWidgetState createState() => _AnimationWidgetState();
}
class _AnimationWidgetState extends State<AnimationWidget>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;

@override
void initState() {
super.initState();
_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 context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ Container(
width: _animation.value,
height: _animation.value,
color: Colors.blue,
child: FlutterLogo(size: 100),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_controller.status == AnimationStatus.completed) {
_controller.reverse();
} else {
_controller.forward();
}
},
child: Text(
_controller.status == AnimationStatus.completed
? 'Reverse Animation'
: 'Start Animation',
),
),
],
),
);
}

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

b) Experiment with different types of animations like fade,slide,etc.


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

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

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();
}

class _FadeAnimationState extends State<FadeAnimation>


with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;

@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
);
_animation = Tween<double>(
begin: 0.0,1.0,
).animate(_controller);

_controller.forward();
}

@override
Widget build(BuildContext context) {
return Center(
child: FadeTransition(
opacity: _animation,
child: Container(
width: 200,
height: 200,
color: Colors.blue,
),
),
);
}

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

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

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Slide Animation Example'),
),
body: SlideAnimation(),
),
);
}
}

class SlideAnimation extends StatefulWidget {


@override
_SlideAnimationState createState() => _SlideAnimationState();
}
class _SlideAnimationState extends State<SlideAnimation>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
);
_animation = Tween<Offset>(
begin: Offset(-1.0, 0.0),
end: Offset(0.0, 0.0),
).animate(_controller);
_controller.forward();
}

@override
Widget build(BuildContext context) {
return Center(
child: SlideTransition(
position: _animation,
child: Container(
width: 200,
height: 200,
color: Colors.blue,
),
),
);
}

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

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

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Scale Animation Example'),
), 64
body: ScaleAnimation(),
),
);

}
}

class ScaleAnimation extends StatefulWidget {


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

class _ScaleAnimationState extends State<ScaleAnimation>


with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;

@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
);
_animation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(_controller);
_controller.forward();
}

@override
Widget build(BuildContext context) {
return Center(
child: ScaleTransition(
scale: _animation,
child: Container(
width: 200,
height: 200,
color: Colors.blue,
),
),
);
}

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

Lab Session 9:

a) Fetch data from REST API


add dependancy in pubspec.yaml:
dependencies:
flutter:
sdk: flutter
http: ^0.13.3

enable internet permissions in your AndroidManifest.xml file for Android apps like below.
<uses-permission android:name="android.permission.INTERNET"

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

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

class MyApp extends StatelessWidget {


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

class HomePage extends StatefulWidget {


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

class _HomePageState extends State<HomePage> {


List<dynamic> _data = [];
@override
void initState() {
super.initState();
_fetchDataFromApi();
}

Future<void> _fetchDataFromApi() async {


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

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(
title: Text('API Data Example'),
),
body: ListView.builder(
itemCount: _data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_data[index]['title']),
subtitle: Text(_data[index]['body']),
);
},
),
);
}Output:
b) Display the fetched data in a meaningful way in the UI
display the fetched data in a meaningful way in the UI, we can use a more structured layout rather than just
displaying the data in a list. We'll create a custom widget to represent each post fetched from the API, and
display them in a scrollable list.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

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

class MyApp extends StatelessWidget {


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

class HomePage extends StatefulWidget {


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

class _HomePageState extends State<HomePage> {


List<dynamic> _data = [];
bool _isLoading = false;

@override
void initState() {
super.initState();
_fetchDataFromApi();
}

Future<void> _fetchDataFromApi() async {


setState(() {
_isLoading = true;
});

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

if (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'],
);
},
),
);
}
}

class PostCard extends StatelessWidget {


final String title;
final String body;

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

@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding(

padding: EdgeInsets.all(16),

child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
title,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text(
body, 70
style: TextStyle(fontSize: 16),
),
],

),
),
);
}
}

Output:

We've added a loading indicator (CircularProgressIndicator) to indicate when data is being fetched.
The fetched data is displayed as a list of PostCard widgets, each representing a post from the API.
The PostCard widget displays the title and body of each post in a structured manner using a Card layout.
Lab Session 10:
a) Write unit tests for UI components
Unit tests for UI components in Flutter typically involves using the flutter_test package along with the test
package for writing tests.
Here's how we can write unit tests for the PostCard widget:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:your_app/post_card.dart'; // Import your widget file

void main() {
testWidgets('PostCard displays title and body', (WidgetTester tester) async {
// Build our widget and trigger a frame.
await tester.pumpWidget(
MaterialApp(
home: PostCard(
title: 'Test Title',
body: 'Test Body',
),
),
);

// Verify that the title and body are displayed correctly.


expect(find.text('Test Title'), findsOneWidget);
expect(find.text('Test Body'), findsOneWidget);
});

testWidgets('PostCard widget has correct styling', (WidgetTester tester) async {


// Build our widget and trigger a frame.
await tester.pumpWidget(
MaterialApp(
home: PostCard(
title: 'Test Title',
body: 'Test Body',
),
),
);

// 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);

final bodyText = tester.widget<Text>(find.text('Test Body'));


expect(bodyText.style.fontSize, 16);
});
}

b) Use flutter's debugging tools to identify and fix issues?


demonstrate the use of Flutter's debugging tools, let's consider a scenario where we have a simple counter
app, but there's a bug where the counter is not incrementing when the "+" button is pressed. We'll use
Flutter's debugging tools to identify and fix this issue.
Here's the code for the counter app:
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


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

class CounterApp extends StatefulWidget {


@override
_CounterAppState createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
int _counter = 0;

void _incrementCounter() {
_counter++;
}

@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),
),
);
}
}

You might also like