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

Flutter Lab Week 7 to 10

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

Flutter Lab Week 7 to 10

Copyright
© © All Rights Reserved
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