Flutter Shared Preferences And Settings Menu Demo

While Android/Java is super easy to use Shared Preferences, Flutter/Dart's Shared_Preferences is not that straightforward.

When I was learning Shared Preferences, I did a lot of Google searching. Most of what I found is talking about making separate class file or creating tons of setter/getter functions.  I was wondering if I can code it differently. So I tried my own simply way. 

Here is what I did.

First add dependency to file pubspec.yaml.

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.3 
  
  # TODO: Add dependency   
  shared_preferences: ^0.5.10       
 

And "Pub Get" it.

Shared Preferences Pub get


Then import package.

import 'package:flutter/material.dart';
//TODO: import package
import 'package:shared_preferences/shared_preferences.dart';
 

 

Three Steps To Use SharedPreferences In Flutter/Dart

1. Initialization

The key to use Flutter SharedPreferences is to initialize it in the async main() and declare a top-level variable before main(). So we can use it any time after.

SharedPreferences mSharedPreferences;

void main() async {
  WidgetsFlutterBinding.ensureInitialized(); //must include this line.
  mSharedPreferences = await SharedPreferences.getInstance();
  runApp(MyApp());
} 


In this demo, we'll display a temperature reading, in user preferred temperature unit, either Celsius or Fahrenheit, which is stored in Shared_Preferences. The data we got from API could be in C or F. A conversion must be done before we can display the information.

Then we have a settings menu, letting user choose between C and F. When you tap on a letter, C or F, its color changes to active yellow. The other one changes to grey. And the value is saved to Shared Preferences. Meanwhile the homepage temperature number and unit are also changed accordingly.

The demo runs like this. 

Flutter Shared Preferences Settings Menu
 

2. Get Value From Shared_Preferences

Every time we start the app, we check the value from SharedPreferrences. If not set(first time running), we set it to default, which is "C".

  var key1='MyUnit';
  var preferredUnit;
  
  @override
  void initState() {
    super.initState();
    preferredUnit = mSharedPreferences.getString(key1) ?? 'C';    
  }       
 

You can .getString() any KEY without declaring or initializing it. You can create multiple Shared_Preferences, such as 

var x = mSharedPreferences.getString(key2); 
var x = mSharedPreferences.getInt('key3'); 
var x = mSharedPreferences.getBool('AnyKey');       
 

You can check if the key-value pair exists by: 

  if (mSharedPreferences.getString('KEY')==null) {}
  if (mSharedPreferences.getInt('KEY')==null) {}      
 

Before its value is set, any SharedPreferences value is null.

 3. Save Value to Shared_Preferences

After user taps to change preferred unit, we need to save that value to SharedPreferences.

 //if user taps on 'F'
 mSharedPreferences.setString(key1, 'F');       
 
Just like the getter, you can save value to multiple Shared Preferences without declaring.
These operations are kind of "async" processes. They MIGHT take a while to finish. So if you want to use the value right away, don't get it from Shared Preferences. In stead, assign the value to a variable directly.
mSharedPreferences.setString(key1, 'F');
//Don't do this right after:
preferredUnit = mSharedPreferences.getString(key1);
//in stead, do this:
preferredUnit = 'F';
 

Flutter/Dart Settings Menu

Flutter/Dart doesn't have predefined Settings Menu. You can import some packages, such as https://pub.dev/packages/shared_preferences_settings.

Or you can just DIY, like what I did in this demo.

The complete main.dart file is listed below. Hope you enjoy it.

main.dart

import 'package:flutter/material.dart';
//TODO: import package
import 'package:shared_preferences/shared_preferences.dart';

SharedPreferences mSharedPreferences;

void main() async {
WidgetsFlutterBinding.ensureInitialized(); // must include this line
mSharedPreferences = await SharedPreferences.getInstance();
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
final key1 = 'MyUnit'; // KEY for Shared_Preferences
final apiTemperature = 20; // usually we get these data from API,
final apiUnit = 'C'; // unit could be C or F,
var preferredUnit; // so we have to convert it first to match user preferred unit.

@override
void initState() {
super.initState();
// This is how to initialize a Key-Value pair of SharedPreferences.
// it's value is always null before we set a value to it.
preferredUnit = mSharedPreferences.getString(key1) ?? 'C';
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
PopupMenuButton(
color: Colors.greenAccent,
icon: Icon(Icons.settings),
itemBuilder: (context) => [
PopupMenuItem(
value: 1,
child: StatefulBuilder(
//important: make MenuItem Stateful, so it can change color when tapped
builder: (BuildContext context, StateSetter setState) {
return Row(
children: <Widget>[
Column(
children: [
Text('Choose a unit'),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
InkWell(
onTap: () {
if (preferredUnit == 'F') {
//This is how we save a value to SharedPreferences,
//it's kind of async operation,
// MIGHT take a while to finish,
mSharedPreferences.setString(key1, 'C');
setState(() {
//so we assign the value directly without touching SharedPreferences
preferredUnit = 'C';
});
//the MenuItem is now inside StatefulBuilder
//we have to make anther setState inside MyHomePage
mySetState('C');
}
},
child: Container(
color: (preferredUnit == 'C')
? Colors.yellowAccent
: Colors.black12,
child: Text('°C'),
),
),
Container(
child: Text(' '),
),
InkWell(
onTap: () {
if (preferredUnit == 'C') {
mSharedPreferences.setString(key1, 'F');
setState(() {
preferredUnit = 'F';
});
mySetState('F');
}
},
child: Container(
color: (preferredUnit == 'C')
? Colors.black12
: Colors.yellowAccent,
child: Text('°F '),
),
),
],
),
],
),
],
);
}),
),
PopupMenuItem(
// a blank menu item
child: Text("About"),
value: 2,
),
],
onSelected: (result) {
if (result == 2) {}
},
),
],
title: Text('Flutter Demo'),
),
body: Center(
child: Row(
children: <Widget>[
Text(' Today\'s temperature: '),
Text(
CFConverter(apiTemperature, apiUnit).toString(),
style: TextStyle(fontSize: 40, color: Colors.redAccent),
),
Text(
'°' + preferredUnit,
style: TextStyle(fontSize: 40, color: Colors.deepOrangeAccent),
),
],
),
),
);
} //Widget builder end

void mySetState(String unit) {
setState(() {
preferredUnit = unit;
});
}

int CFConverter(int temperature, String unit) {
if (preferredUnit == apiUnit) {
return temperature;
} else if (apiUnit != '' && preferredUnit != apiUnit) {
if (apiUnit == 'C') {
return (temperature * 1.8 + 32).round();
} else if (apiUnit == 'F') {
return ((temperature - 32) / 1.8).round();
}
}
}
}


Comments

Popular posts from this blog

Android CameraX Picture And Video Capture Complete Code Tutorial

Flutter: call a method from another class / setState a page from outside that class with StreamController

How To Add AdMob To Flutter App Quick Tutorial