Inicialment cal crear el botó que serveix per demanar que es calculi el resultat. Serà un botó similar als del selector de tensió que anirà de banda a banda però respectant els marges de l'aplicació.
Començarem creant el fitxer boto_calc.dart dins de la carpeta components i li posarem un giny amb estat, que anomenarem BotoCalc. Com vam fer en el selector de tensió, posarem un text dins d'un farciment, per tal que el text no s'enganxi a les vores del botó. Aquest farciment el posarem dins d'un contenidor per tal de poder-hi posar el color i la decoració desitjats. Finalment, tancarem el contenidor dins d'un altre farciment, que ens permetrà deixar els marges al seu voltant.
De moment, ens quedarà així:
boto_calc.dart
import 'package:flutter/material.dart'; import 'package:resistled_app/core/colors.dart'; import 'package:resistled_app/core/estils.dart';
class BotoCalc extends StatefulWidget {
const BotoCalc({super.key});
@override
State<BotoCalc> createState() => _BotoCalcState();
}
class _BotoCalcState extends State<BotoCalc> {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(20),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: ColorsApp.primari,
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Text("Calcula...", style: Estils.estilTextBotons),
),
),
);
}
}
També hem de crear un altre element on es mostraran els resultats. Començarem creant el fitxer req_result.dart dins de la carpeta components i li posarem un giny amb estat, que anomenarem ReqResult. Posem un text que contingui el valor de la resistència i li donem format. Per evitar que el text quedi enganxat a les vores, posem un farciment al seu voltant. Volem que el text tingui un aspecte similar als altres elements de la pantalla i, per tant, el posem dins d'un contenidor amb la decoració apropiada i posarem aquest dins d'un altre farciment per deixar el marge apropiat respecte les vores i el botó. Ho podríem deixar així, però atès que a la pantalla ja no hi ha d'anar res més, ens ha semblat més adequat posar el conjunt dins d'un bloc d'expandir; així el bloc arriba fins al final de la pantalla.
Caldrà passar una variable a aquest giny; però no serà necessària cap funció, atès que el giny no té cap acció. La variable la mostrarem amb un nombre concret de decimals i substituirem el punt decimal per una coma, tal com està normalitzat.
req_result.dart
import 'package:flutter/material.dart'; import 'package:resistled_app/core/colors.dart'; import 'package:resistled_app/core/estils.dart';
class ReqResult extends StatefulWidget {
final double resistencia;
const ReqResult({super.key, required this.resistencia});
@override
State<ReqResult> createState() => _ReqResultState();
}
class _ReqResultState extends State<ReqResult> {
@override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 40),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: ColorsApp.component,
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Text(
"La resistència adequada és de: \n${widget.resistencia.toStringAsFixed(2).replaceAll('.', ',')} Ω",
style: Estils.estilTextResultat,
),
),
),
),
);
}
}
I ara podem cridar aquests element des de la pantalla principal, on haurem declarat la variable resisten. Aquesta variable l'hem inicialitzat a -1 perquè així ens permetrà diferenciar, més endavant, si la resistència ja s'ha calculat o encara té el valor per defecte.
...
class _PantPralState extends State<PantPral> {
double tensAlim = 3.3; // V
double caigudaTens = 1.6; // V
double correntNom = 10; // mA
double resisten = -1;
String txt = "";
final double maxCaig = 3.3;
final double minCaig = 0.4;
final double maxCorr = 50.0;
final double minCorr = 1.0;
@override
Widget build(BuildContext context) {
return Column(
children: [
SelectorTens(
tensioAlim: tensAlim,
canviTens: (double novaTensio) {
setState(() {
tensAlim = novaTensio;
});
},
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
children: [
Expanded(
child: EntraNum(
titol: "Caiguda de tensió",
valor: caigudaTens.toStringAsFixed(1).replaceAll('.', ','),
incrementar: () {
setState(() {
if (caigudaTens < maxCaig) {
caigudaTens += 0.1;
}
});
},
decrementar: () {
setState(() {
if (caigudaTens > minCaig) {
caigudaTens -= 0.1;
}
});
},
),
),
SizedBox(width: 20),
Expanded(
child: EntraNum(
titol: "Corrent nominal",
valor: correntNom.toStringAsFixed(0),
incrementar: () {
setState(() {
if (correntNom < maxCorr) {
correntNom++;
}
});
},
decrementar: () {
setState(() {
if (correntNom > minCorr) {
correntNom--;
}
});
},
),
),
],
),
),
BotoCalc(),
ReqResult(resistencia: resisten),
],
);
}
}
De moment, però, el botó no fa res, caldria que calculés el valor de la resistència, per tal que es pugui mostrar al requadre corresponent.
El càlcul és senzill, cal restar el valor de la caiguda de tensió de la tensió d'alimentació i dividir el resultat pel corrent. Cal tenir en compte, però, que el corrent està en mil·líampers i, per tant, s'haurà de dividir per mil.
Al botó li hem d'afegir la funció de càlcul com a paràmetre i posar-li un detector d'accions perquè executi la funció quan sigui premut.
class BotoCalc extends StatefulWidget {
final Function() calcRes;
const BotoCalc({super.key, required this.calcRes});
@override
State<BotoCalc> createState() => _BotoCalcState();
}
class _BotoCalcState extends State<BotoCalc> {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(20),
child: GestureDetector(
onTap: () {
setState(() {
widget.calcRes();
});
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: ColorsApp.primari,
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Text("Calcula la resistència", style: Estils.estilTextBotons),
),
),
),
);
}
}
A la pantalla principal, afegirem el càlcul en la crida al botó:
...
BotoCalc(
calcRes: () {
setState(() {
resisten = (tensAlim - caigudaTens) / (correntNom / 1000);
});
},
),
...
Podríem donar l'aplicació per acabada, però ens trobem que el requadre de resultats mostra el valor anterior de la resistència, fins que es prem el valor de calcular; en el moment d'obrir l'aplicació es mostra el valor per defecte. Atès que al valor per defecte li hem posat un valor impossible, podem fer que el requadre es mostri buit quan la resistència té aquest valor. Cal fer uns petits canvis al requadre de resultats:
...
class _ReqResultState extends State<ReqResult> {
@override
Widget build(BuildContext context) {
String txt = widget.resistencia >= 0
? "La resistència adequada és de: \n${widget.resistencia.toStringAsFixed(2).replaceAll('.', ',')} Ω"
: "";
return Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 40),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: ColorsApp.component,
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Text(txt, style: Estils.estilTextResultat),
),
),
),
);
}
}
És força senzill fer que el resultat es deixi de mostrar cada cop que es modifiqui un dels tres paràmetres, així el resultat visible sempre es correspondrà amb els valors mostrats. Només s'han d'afegir unes poques línies a la pantalla principal.
...
Widget build(BuildContext context) {
return Column(
children: [
SelectorTens(
tensioAlim: tensAlim,
canviTens: (double novaTensio) {
setState(() {
tensAlim = novaTensio;
resisten = -1;
});
},
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
children: [
Expanded(
child: EntraNum(
titol: "Caiguda de tensió",
valor: caigudaTens.toStringAsFixed(1).replaceAll('.', ','),
incrementar: () {
setState(() {
if (caigudaTens < maxCaig) {
caigudaTens += 0.1;
resisten = -1;
}
});
},
decrementar: () {
setState(() {
if (caigudaTens > minCaig) {
caigudaTens -= 0.1;
resisten = -1;
}
});
},
),
),
SizedBox(width: 20),
Expanded(
child: EntraNum(
titol: "Corrent nominal",
valor: correntNom.toStringAsFixed(0).replaceAll('.', ','),
incrementar: () {
setState(() {
if (correntNom < maxCorr) {
correntNom++;
resisten = -1;
}
});
},
decrementar: () {
setState(() {
if (correntNom > minCorr) {
correntNom--;
resisten = -1;
}
});
},
),
),
],
),
),
BotoCalc(
calcRes: () {
setState(() {
resisten = (tensAlim - caigudaTens) / (correntNom / 1000);
});
},
),
ReqResult(resistencia: resisten),
],
);
}
}

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