Flutter Lab Week 7 to 10
Flutter Lab Week 7 to 10
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());
}
String _name;
String _email;
@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;
}); },
),
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:
void main() {
runApp(MyApp());
}
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: FormWidget(),
),
),
);
}
}
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;
},
void _submitForm() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print('Email: $_email');
print('Password: $_password');
print('Phone: $_phone');
print('Address: $_address');
}
}
}
Output:
Lab Session 8:
void main() {
runApp(MyApp());
}
@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:
void main() {
runApp(MyApp());
}
@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());
}
@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());
}
}
}
@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:
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());
}
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());
}
@override
void initState() {
super.initState();
_fetchDataFromApi();
}
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'],
);
},
),
);
}
}
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',
),
),
);
void main() {
runApp(MyApp());
}
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),
),
);
}
}