Unlocking the Power of Progress Indicators in Flutter
What are Asynchronous Applications?
Asynchronous applications are composed of tasks that run independently while the rest of the program continues to execute. To determine if your app needs asynchronous execution, identify tasks that can be executed independently and those that depend on the completion of other processes.
The Role of Progress Indicators
Progress indicators help communicate the status of a user’s request, such as downloading files, uploading files, submitting forms, or loading a page. Flutter provides an abstract ProgressIndicator
class, with two concrete subclasses: LinearProgressIndicator
and CircularProgressIndicator
.
Types of Progress Indicators
There are two types of progress indicators: determinate and indeterminate.
- Determinate indicators display the fraction or percentage of the task completed.
- Indeterminate indicators show that a task is processing without a definite duration.
Building a Determinate Progress Indicator
Let’s create an app that downloads a file from the internet and displays the progress using a circular progress indicator. We’ll use the path_provider
and http
dependencies to store the downloaded file and make the HTTP request.
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;
class DownloadFileScreen extends StatefulWidget {
@override
_DownloadFileScreenState createState() => _DownloadFileScreenState();
}
class _DownloadFileScreenState extends State<DownloadFileScreen> {
double _progress = 0.0;
Future _downloadFile() async {
final url = 'https://example.com/file.txt';
final response = await http.get(Uri.parse(url));
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/file.txt');
await file.writeAsBytes(response.bodyBytes);
setState(() {
_progress = 1.0;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Download File'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(
value: _progress,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _downloadFile,
child: Text('Download File'),
),
],
),
),
);
}
}
Building an Indeterminate Progress Indicator
Next, we’ll build an app that makes an HTTP request to a GitHub Rest API and renders some of the obtained data on the screen. Since we don’t know how long the request will take, we’ll implement an indeterminate progress indicator using the flutter_spinkit
package.
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
class GithubApiScreen extends StatefulWidget {
@override
_GithubApiScreenState createState() => _GithubApiScreenState();
}
class _GithubApiScreenState extends State<GithubApiScreen> {
bool _loading = false;
Future _fetchData() async {
setState(() {
_loading = true;
});
final response = await http.get(Uri.parse('undefined.github.com/users'));
// Process the response data
setState(() {
_loading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GitHub API'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_loading
? SpinKitCircle(
color: Colors.blue,
size: 50.0,
)
: Text('Data loaded'),
SizedBox(height: 20),
ElevatedButton(
onPressed: _fetchData,
child: Text('Fetch Data'),
),
],
),
),
);
}
}
Choosing the Right Progress Indicator
The user experience contributed by a progress indicator is invaluable. When choosing an indicator, consider whether you can measure the task’s progress. If you can, use a determinate indicator; otherwise, opt for an indeterminate one.
By following this guide, you’ll be able to choose and implement the right progress indicators for your apps, ensuring that your users are always informed about the status of their requests.