In this tutorial, we’ll dive into implementing shared preferences in a Flutter app to persist user data across sessions. Shared preferences are essential for storing small amounts of data like user settings, login information, and other preferences that need to be retained between app launches. In this guide, we’ll walk you through creating a BMI (Body Mass Index) calculator that remembers the last entered height and weight, as well as keeps a history of calculated BMIs.
If you prefer watching a video tutorial here is a link to that.
Setting Up Your Flutter Project
Before diving into the code, ensure you have a Flutter environment set up. Begin by creating a new Flutter project and setting up the basic structure.
flutter create flutter_shared_preferences_tutorial
Adding Required Dependencies
First, add the necessary dependencies to your pubspec.yaml
file:
shared_preferences:
The shared_preferences
package allows Flutter developers to store simple data types like strings, integers, and booleans locally on a device. This is ideal for saving user preferences and settings that persist across app sessions. To get the dependency click here.
input_quantity:
The input_quantity
package provides a user-friendly widget for inputting numerical values, complete with increment and decrement buttons. It’s perfect for applications that require precise control over quantity inputs, such as a BMI calculator. To get the dependency click here.
dependencies:
flutter:
sdk: flutter
shared_preferences: ^2.3.2
input_quantity: ^2.4.0
These libraries will help manage shared preferences and provide user-friendly input fields.
Creating the Main Application Structure
Start by creating the entry point of your Flutter application in main.dart
:
import 'package:flutter/material.dart';
import 'package:flutter_shared_prefrences_tutorial/pages/home_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: HomePage(),
);
}
}
Creating the Home Page
The heart of our application lies in the HomePage
. This widget is stateful, allowing us to manage user input and display results dynamically.
Setting Up Shared Preferences
Shared Preferences allow us to persist data. Initialize them in the initState()
method:
class _HomePageState extends State<HomePage> {
SharedPreferences? _prefs;
num _height = 0, _weight = 0, _bmi = 0;
List<String> _bmiHistory = <String>[];
@override
void initState() {
super.initState();
SharedPreferences.getInstance().then((value) {
setState(() {
_prefs = value;
_bmiHistory = _prefs!.getStringList("bmi_history") ?? [];
_height = _prefs!.getDouble("last_input_height")?.toDouble() ?? 0;
_weight = _prefs!.getDouble("last_input_weight")?.toDouble() ?? 0;
});
});
}
}
Building the User Interface
Next, construct the user interface by combining several widgets:
@override
Widget build(BuildContext context) {
return Scaffold(
body: _buildUI(),
);
}
Widget _buildUI() {
if (_prefs == null) {
return Center(child: CircularProgressIndicator());
}
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height * 0.05,
child: Center(
child: Text(
"${_bmiHistory.lastOrNull ?? 0.00} BMI",
style: TextStyle(fontSize: 25),
),
),
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_weightInput(),
_heightInput(),
],
),
_calculateBMIButton(),
_bmiHistoryList(),
],
),
);
}
Handling User Input: Weight and Height
We use InputQty
widgets for collecting height and weight data from the user. These inputs are automatically saved to shared preferences when changed.
Weight Input
Widget _weightInput() {
return Column(
children: [
const Text("Weight"),
InputQty(
maxVal: double.infinity,
initVal: _weight,
minVal: 0,
steps: 1,
onQtyChanged: (value) {
setState(() {
_weight = value;
_prefs!.setDouble("last_input_weight", _weight.toDouble());
});
},
)
],
);
}
Height Input
Widget _heightInput() {
return Column(
children: [
const Text("Height"),
InputQty(
maxVal: double.infinity,
initVal: _height,
minVal: 0,
steps: 1,
onQtyChanged: (value) {
setState(() {
_height = value;
_prefs!.setDouble("last_input_height", _height.toDouble());
});
},
)
],
);
}
Calculating and Displaying BMI
After collecting the user’s height and weight, the BMI is calculated and displayed along with a history of previous results.
Widget _calculateBMIButton() {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: MaterialButton(
onPressed: () {
double calculatedBmi = _weight / pow(_height, 2);
setState(() {
_bmiHistory.add(calculatedBmi.toStringAsFixed(2));
_prefs!.setStringList("bmi_history", _bmiHistory);
});
},
color: Colors.purple,
child: const Text("Calculate", style: TextStyle(color: Colors.white)),
),
);
}
Displaying BMI History
Finally, display a list of the calculated BMIs so users can keep track of their progress.
Widget _bmiHistoryList() {
return Expanded(
child: ListView.builder(
itemCount: _bmiHistory.length,
itemBuilder: (context, index) {
return ListTile(
leading: Text(index.toString(), style: const TextStyle(fontSize: 15)),
title: Text(_bmiHistory[index]),
onLongPress: () {
setState(() {
_bmiHistory.removeAt(index);
_prefs!.setStringList("bmi_history", _bmiHistory);
});
},
);
},
),
);
}
Get Source Code for free:
Conclusion
By following this tutorial, you have successfully implemented a Flutter app that uses shared preferences to store and retrieve user input data. This approach ensures that your app retains user preferences across sessions, enhancing the user experience. Shared preferences are a powerful tool for managing user-specific settings and small amounts of data in Flutter applications.
Happy Coding…!!!
Leave a Reply