Ja hem vist com fer perquè l'usuari pugui triar si vol veure les dades en format text o en format gràfic; però cada cop que obri l'aplicació les veurà, per defecte, en format text. Podem fer que l'opció triada es guardi en forma permanent i es torni a carregar cada cop que s'inicia l'aplicació.
La biblioteca SharedPreferences ens permet guardar dades de diversos tipus en forma permanent a la memòria del dispositiu i tornar-les a carregar quan ens convingui. Per fer servir aquesta biblioteca, cal anar al fitxer pubspec.yaml per dir-li que la volem fer servir. Ho hem de posar a dependencies, indicant quina és la versió que volem. És recomanable indicar la darrera versió; que podem veure a la pàgina corresponent. Quan vam escriure aquest text era la 2.5.3.
dependencies:
flutter:
sdk: flutter
shared_preferences: ^2.5.3
Un cop afegit, cal picar al botó per baixar el paquet (
).
Pot succeir que la nostra versió de NDK per a Android no sigui l'adequada, en aquest cas és probable que ens doni un error; si és així, ens indicarà quina és la versió de NDK que cal tenir. Caldrà modificar el fitxer build.gradle.kts (que es troba a la carpeta app dins de la carpeta android), posant o editant la línia dins de l'element android:
android {
ndkVersion = "27.0.12077973"
Malgrat només tenim una dada a guardar, creem una classe, que anomenem ClausOpcions on posarem la clau que farem servir. Així es podrà modificar, sempre que calgui, en un únic lloc. Per tant, creem el fitxer claus_opcions.dart dins de la carpeta lib.
class ClausOpcions{
static const grafic = "Grafic";
}
A la pantalla principal, a més de carregar els dos fitxers necessaris, hem d'afegir les funcions per llegir i guardar les dades, la crida a la funció de llegir-les a l'inici i la crida a la funció de guardar-les cada cop que s'acciona l'interruptor. En aquest cas, les funcions de llegir i guardar són molt senzilles; atès que només hi ha una dada per guardar.
pant_principal.dart
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:sheets/claus_opcions.dart'; import 'package:sheets/core/colors.dart'; import 'package:sheets/data/crida_dades.dart'; import 'package:sheets/data/dades_rebudes.dart';
class PantPrincipal extends StatefulWidget {
const PantPrincipal({super.key});
@override
State<PantPrincipal> createState() => _PantPrincipalState();
}
class _PantPrincipalState extends State<PantPrincipal> {
Future<DadesRebudes?>? _rebut;
bool _grafic = false;
CridaDades cridaDades = CridaDades();
@override
void initState() {
super.initState();
_rebut = cridaDades.llegirDades();
_agafaOpcions();
}
_guardaOpcions(String clau, dynamic valor) async{
final opcions = await SharedPreferences.getInstance();
await opcions.setBool(clau, valor);
}
_agafaOpcions() async{
final opcions = await SharedPreferences.getInstance();
setState(() {
_grafic = opcions.getBool(ClausOpcions.grafic) ?? false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Valors actuals"),),
body: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8),
child: TextButton(
onPressed: () {
setState(() {
_rebut = cridaDades.llegirDades();
});
},
child: Text("Recarrega"),
),
),
Spacer(),
Text("Gràfic"),
Padding(
padding: const EdgeInsets.all(12.0),
child: Switch(
value: _grafic,
onChanged:(value) {
setState(() => _grafic = value);
_guardaOpcions(ClausOpcions.grafic, _grafic);
},
),
)
],
),
FutureBuilder(future: _rebut, builder: (context, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return CircularProgressIndicator();
} else if(snapshot.hasError){
return Text("Error: ${snapshot.error}");
} else if(snapshot.hasData){
if(_grafic){
return mostraBarres(snapshot.data);
} else {
return escriuResultats(snapshot.data);
}
} else {
return Text("No s'han trobat resultats");
}
})
],
),
);
}
}
Widget escriuResultats(DadesRebudes? dades){
if(dades != null){
if(dades.nom.length >=5){
List<Widget> esquerra = [];
List<Widget> dreta = [];
Widget element;
for(int i = 0; i < dades.nom.length; i++){
element = Text("${dades.nom[i]}: ");
esquerra.add(element);
element = Text("${dades.darrer[i].replaceAll('.', ',')} ${dades.unitats[i]}");
dreta.add(element);
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: esquerra,
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: dreta,
),
]
),
);
}
}
return Text("Dades incompletes");
}
Widget mostraBarres(DadesRebudes? dades){
if(dades != null){
if(dades.nom.length >=5){
ColorsApp colorsApp = ColorsApp();
List<Widget> barres = [];
Widget element;
double llarg;
for(int i = 0; i < dades.nom.length; i++){
llarg = double.parse(dades.darrer[i]) * 250 / double.parse(dades.maxim[i]);
element = Row(
children: [
SizedBox(
width: 30,
child: Text(
dades.titol[i],
style: TextStyle(
fontSize: 20,
color: colorsApp.colorsColumnes[i],
fontWeight: FontWeight.bold
)
),
),
Container(
height: 40,
width: llarg,
color: colorsApp.colorsColumnes[i],
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
"${dades.darrer[i].replaceAll('.', ',')} ${dades.unitats[i]}",
style: TextStyle(
fontSize: 14,
color: colorsApp.colorsColumnes[i],
)
),
),
],
);
barres.add(element);
}
return Padding(
padding: const EdgeInsets.all(12),
child: SizedBox(
width: double.infinity,
height: 300,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: barres,
),
),
);
}
}
return Text("Dades incompletes");
}
Nota: Aquest apartat està parcialment basat en l'aplicació Settings App creada per AristiDevs.

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.