Aplicacions amb Flutter, Dart i Flame

Tutorial Flutter Flame Projectes   Recursos CITCEA
Exemples Dart Dades pràctiques     Inici

Creació del selector de tensió

Per mantenir el programa ben organitzat, els elements que aniran dins aquesta columna també estaran en carpetes. Per crear la carpeta per al selector de tensió, dins de la carpeta lib crearem una carpeta anomenada components, on guardarem els diferents blocs. Dins d'aquesta carpeta, crearem el fitxer selector_tens.dart; dins hi crearem un giny amb estat que anomenarem SelectorTens. Aquest element el cridarem des de dins de la columna:

...
class _PantPralState extends State<PantPral> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SelectorTens()
      ],
    );
  }
}

De moment, el fitxer de la pantalla principal ja està; després hi haurem d'afegir més elements.

Ara anem a definir el selector de tensió. Inicialment el contingut està així:

selector_tens.dart
import 'package:flutter/material.dart';
class SelectorTens extends StatefulWidget {
  const SelectorTens({super.key});

  @override
  State<SelectorTens> createState() => _SelectorTensState();
}

class _SelectorTensState extends State<SelectorTens> {
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

Hem de triar entre dues tensions possibles (3,3 i 5 V); per tant, una bona manera és tenir dos botons, un per a cada tensió, i que destaqui el que correspongui a la tensió seleccionada. Aquests dos botons els podem posar un al costat de l'altre i, per tant, el més raonable és posar una filera que tindrà dos elements de tex, un per a cada tensió.

...
class _SelectorTensState extends State<SelectorTens> {
  @override
  Widget build(BuildContext context) {
    return Row(children: [
      Text("3,3 V"),
      Text("5,0 V"),
    ],);
  }
}

Amb això, però, el text es veurà petit i amb un color que no destaca. Cal canviar l'estil d'aquests elements de text. Per estructurar bé l'aplicació, definirem tots els estils en un fitxer separat; així, si en algun moment els volem canviar, només els cal modificar en un únic lloc. Abans de res, dins de la carpeta core, crearem el fitxer estils.dart, on definirem els estils que intervindran en la nostra aplicació. Posarem una mida una mica grossa (per exemple, 30), en negreta i el color corresponent al text. De moment, el fitxer quedarà així:

estils.dart
import 'package:flutter/material.dart';
import 'package:resistled_app/core/colors.dart';
class Estils {
  static const TextStyle estilTextBotons = TextStyle(
    color: ColorsApp.text,
    fontSize: 30,
    fontWeight: FontWeight.bold,
  );
}

I ja podem aplicar aquest estil als textos.

...
    return Row(children: [
        Text("3,3 V", style: Estils.estilTextBotons),
        Text("5,0 V", style: Estils.estilTextBotons),
    ],);

Ara el text ja destaca però no té una forma que ens indiqui que s'hi pot fer clic. Caldrà definir dos colors, un per al component quan no està seleccionat i l'altre per quan sí ho està. Afegirem, doncs, dues línies al fitxer de colors.

...
  static const Color component = Color(0xFF006600);
  static const Color compSelec = Color(0xFF00AA00);
...

Per aplicar el color, tancarem cada text dins d'un contenidor, perquè és un element que permet definir una decoració i també ens permet centrar el contingut. També posarem un radi a la vora, per tal que ens quedin les vores arrodonides. El color dependrà de quina sigui la tensió seleccionada. De moment, posarem una opció a cada un.

...
    return Row(
      children: [
        Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            color: ColorsApp.compSelec,
            borderRadius: BorderRadius.circular(12),
          ),
          child: Text("3,3 V", style: Estils.estilTextBotons),
        ),
        Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            color: ColorsApp.component,
            borderRadius: BorderRadius.circular(12),
          ),
          child: Text("5,0 V", style: Estils.estilTextBotons),
        ),
      ],
    );
...

Ara els dos botons ja destaquen però tenen el text enganxat a la vora i estan arraconats a un costat. Per fer que els dos botons es reparteixin l'amplada, posarem els textos dins d'un bloc d'expandir.

...
    return Row(
      children: [
        Expanded(
          child: Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: ColorsApp.compSelec,
              borderRadius: BorderRadius.circular(12),
            ),
            child: Text("3,3 V", style: Estils.estilTextBotons),
          ),
        ),
        Expanded(
          child: Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: ColorsApp.component,
              borderRadius: BorderRadius.circular(12),
            ),
            child: Text("5,0 V", style: Estils.estilTextBotons),
          ),
        ),
      ],
    );
...

Per donar separació al text, podem posar-lo dins d'un bloc de farciment. El farciment pels costats és innecessari (l'amplada ja l'estableix el bloc d'expandir) però el més fàcil és posar el mateix valor per a tot.

...
    return Row(
      children: [
        Expanded(
          child: Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: ColorsApp.compSelec,
              borderRadius: BorderRadius.circular(12),
            ),
            child: Padding(
              padding: const EdgeInsets.all(20.0),
              child: Text("3,3 V", style: Estils.estilTextBotons),
            ),
          ),
        ),
        Expanded(
          child: Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: ColorsApp.component,
              borderRadius: BorderRadius.circular(12),
            ),
            child: Padding(
              padding: const EdgeInsets.all(20.0),
              child: Text("5,0 V", style: Estils.estilTextBotons),
            ),
          ),
        ),
      ],
    );
...

Ens falten els marges exteriors. Per aconseguir-ho, posarem els contenidors dins d'un altre bloc de farciment. No podem posar el farciment al bloc d'expandir, si ho féssim ens donaria un error. Si en el bloc de farciment posem tots els costats al mateix valor no es veurà bé perquè ens quedarà una separació entre botons el doble de la distància amb la vora de la pantalla. Tindrem millor resultat si controlem cada voltant per separat i posem la meitat del valor als que queden a la part central.

...
    return Row(
      children: [
        Expanded(
          child: Padding(
            padding: const EdgeInsets.only(top: 20, bottom: 20, left: 20, right: 10),
            child: Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: ColorsApp.compSelec,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Padding(
                padding: const EdgeInsets.all(20.0),
                child: Text("3,3 V", style: Estils.estilTextBotons),
              ),
            ),
          ),
        ),
        Expanded(
          child: Padding(
            padding: const EdgeInsets.only(top: 20, bottom: 20, left: 10, right: 20),
            child: Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: ColorsApp.component,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Padding(
                padding: const EdgeInsets.all(20.0),
                child: Text("5,0 V", style: Estils.estilTextBotons),
              ),
            ),
          ),
        ),
      ],
    );
...

Ja tenim el disseny del selector de tensió però, de moment, no es detecten els clics. Cal posar un detector d'accions. Per a cada opció, el posarem tant a fora com sigui possible. En el bloc d'expandir no és raonable però sí ho és en el bloc de farciment que té a dins. També ens cal definir una variable, que serà la que es modifiqui quan es faci clic. Com ens interessa fer servir un clic normal, farem servir l'opció onTap i posarem l'acció a realitzar dins d'un bloc setState.

class _SelectorTensState extends State<SelectorTens> {
  double tensio = 3.3;
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: GestureDetector(
            onTap: () {
              setState(() {
                tensio = 3.3;
              });
            },
            child: Padding(
              padding: const EdgeInsets.only(top: 20, bottom: 20, left: 20, right: 10),
              child: Container(
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  color: ColorsApp.compSelec,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(20.0),
                  child: Text("3,3 V", style: Estils.estilTextBotons),
                ),
              ),
            ),
          ),
        ),
        Expanded(
          child: GestureDetector(
            onTap: () {
              setState(() {
                tensio = 5.0;
              });
            },
            child: Padding(
              padding: const EdgeInsets.only(top: 20, bottom: 20, left: 10, right: 20),
              child: Container(
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  color: ColorsApp.component,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(20.0),
                  child: Text("5,0 V", style: Estils.estilTextBotons),
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

Ja només ens falta aconseguir que el color del botó indiqui quina és la tensió triada. Farem, doncs, que el color canviï segons el valor de la variable.

...
    return Row(
      children: [
        Expanded(
          child: GestureDetector(
            onTap: () {
              setState(() {
                tensio = 3.3;
              });
            },
            child: Padding(
              padding: const EdgeInsets.only(top: 20, bottom: 20, left: 20, right: 10),
              child: Container(
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  color: tensio == 3.3 ? ColorsApp.compSelec : ColorsApp.component,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(20.0),
                  child: Text("3,3 V", style: Estils.estilTextBotons),
                ),
              ),
            ),
          ),
        ),
        Expanded(
          child: GestureDetector(
            onTap: () {
              setState(() {
                tensio = 5.0;
              });
            },
            child: Padding(
              padding: const EdgeInsets.only(top: 20, bottom: 20, left: 10, right: 20),
              child: Container(
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  color: tensio == 5.0 ? ColorsApp.compSelec : ColorsApp.component,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(20.0),
                  child: Text("5,0 V", style: Estils.estilTextBotons),
                ),
              ),
            ),
          ),
        ),
      ],
    );
...

I amb això hauríem enllestit el selector de tensió. Bé, de fet no l'hem acabat; més endavant l'haurem de modificar.

 

 

 

 

 

 

 

 

 

 

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