How to make an input text field reusable multiple times in the same page in flutter?

230 views Asked by At

I created an extensible input text field with a words counter. I wanted to use this widget two times in the same screen, but for different fields (book title and book abstract). So I want them to behave on their own, the book title will have its own text and its own text length, reflected in its counter, and the same to the book abstract field. However, I don't know how to use the same widget in the same page, because they overlap in their behaviours.

This is my widget: text field + words counter:

var buildInicial = true;
bool txtMultilineaHaSufridoCambios = false;

//Widget para el input de Descripción
class InputTxtMultilineaExtensible extends StatefulWidget {
  InputTxtMultilineaExtensible({
    super.key,
    required this.esModoOscuro,
    required this.anchuraCajaTexto,
    required this.maxCaracteres,
    required this.labelFormField,
    required this.iconoTxtMultilinea,
    this.hintTextFormField = "",
    this.textoAsignado = "",
  });
  
  final bool esModoOscuro;
  final double anchuraCajaTexto;
  final int maxCaracteres;
  final String labelFormField;
  final IconData iconoTxtMultilinea;
  String hintTextFormField;
  String textoAsignado;

  @override
  State<InputTxtMultilineaExtensible> createState() => _InputTxtMultilineaExtensibleState();
}

class _InputTxtMultilineaExtensibleState extends State<InputTxtMultilineaExtensible> {

  final controladorTxtMultilineaExtensible = TextEditingController();

  @override
  void dispose() {
    // Limpia el controlador cuando el Widget se descarte
    controladorTxtMultilineaExtensible.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    
    if(buildInicial){
      controladorTxtMultilineaExtensible.text = widget.textoAsignado;
      txtTxtMultilineaExtensible = controladorTxtMultilineaExtensible.text;
      longitudTxtTxtMultilineaExtensible = txtTxtMultilineaExtensible.length;
      buildInicial = false;
     }
     

    return Container(
      width: widget.anchuraCajaTexto,
      child: Column(
        children: [
          TextFormField(
            onChanged: (value) {
              txtMultilineaHaSufridoCambios = true;
              txtTxtMultilineaExtensible = controladorTxtMultilineaExtensible.text;
              setState(() {
                longitudTxtTxtMultilineaExtensible = txtTxtMultilineaExtensible.length;
                if(longitudTxtTxtMultilineaExtensible == widget.maxCaracteres){
                  seSolicitaOtroColorParaContador = true;
                }
                else {
                  seSolicitaOtroColorParaContador = false;
                }
              });
            },
            inputFormatters: [
              LengthLimitingTextInputFormatter(widget.maxCaracteres),
            ],
            controller: controladorTxtMultilineaExtensible,
            minLines: 1,
            maxLines: (widget.maxCaracteres / caracteresAproximadosPorLinea).round(),
            textAlignVertical: TextAlignVertical.top,                      
            decoration: InputDecoration(
              border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(20),
                  borderSide: const BorderSide(color: Colors.white)),
              focusedBorder: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(20),
                  borderSide: const BorderSide(color: Colors.white)),
              labelText: widget.labelFormField,
              hintText: widget.hintTextFormField,
              prefixIcon: Icon(
                widget.iconoTxtMultilinea,
                color: colorMasClaro,
              ),
            ),
            style: TextStyle(
              color: widget.esModoOscuro ? Colors.white : Colors.black,
            ),
          ),
          EspacioVerticalMin(),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              TituloCuaternario(txtTitulo: '$longitudTxtTxtMultilineaExtensible / ${widget.maxCaracteres}', esModoOscuro: esModoOscuro, alineacionTexto: TextAlign.right, esCursiva: false, colorSolicitado: Colors.red, seSolicitaOtroColor:  seSolicitaOtroColorParaContador,),
            ],
          )
        ],
      ),
    );
  }
}



//Método que devuelve el texto escrito en el input Descripción en el momento en que queramos cogerlo
String getTxtMultilineaExtensible(){
  return txtTxtMultilineaExtensible;
}

void setVarBuildInicialTrue(){
  buildInicial = true;
}

bool txtMultilineaModificado(){
  return txtMultilineaHaSufridoCambios;
}

void restaurarEstadoModificacionTxtMult(){
  txtMultilineaHaSufridoCambios = false;
}

//----------------------------------------------------------------------

To reuse it two times, I created an intermediate page where I created two classes, one for the book title and one for the book abstract. I wasn't sure if it was going to work (it didn't), but I really had not any more ideas:

import 'package:flutter/material.dart';
import '../common_widgets/inputs_perfil.dart';
import '../constantes.dart';
import '../themes/paddings.dart';


//Variables de la clase
String tituloLibro = '';
String sinopsisAudiolibro = '';
int maxCaracteresTitulo = 50;
int maxCaracteresSinopsis = 1000;



//----------------------------------->>
//SECCIÓN PARA EL TÍTULO
//----------------------------------->>

class TituloAudioLibro extends StatefulWidget {
  const TituloAudioLibro({
    super.key,
    this.txtTitulo = '',
  });

   final String txtTitulo;

  @override
  State<TituloAudioLibro> createState() => _TituloAudioLibroState();

  
  String getTextoTitulo(){
    tituloLibro = getTxtMultilineaExtensible();
    return tituloLibro;
  }

  bool getSeHaModificadoTitulo(){
    bool txtTituloModificado = txtMultilineaModificado();
    return txtTituloModificado;
  }

  void restaurarEstadoModificacionTitulo(){
    restaurarEstadoModificacionTxtMult();
  }
}

class _TituloAudioLibroState extends State<TituloAudioLibro> {
  @override
  Widget build(BuildContext context) {
    double anchuraCosas = MediaQuery.of(context).size.width - devolverValorNumPaddingPaginaGeneral();
    return InputTxtMultilineaExtensible(esModoOscuro: esModoOscuro, anchuraCajaTexto: anchuraCosas, maxCaracteres: maxCaracteresTitulo, labelFormField: labelTxtTituloAudiolibro, iconoTxtMultilinea: iconoTxtTituloAudiolibro, hintTextFormField: hintTxtTitulo, textoAsignado: widget.txtTitulo,);
  }

}



//----------------------------------->>
//SECCIÓN PARA LA SINOPSIS
//----------------------------------->>

class SinopsisAudiolibro extends StatefulWidget {
  const SinopsisAudiolibro({
    super.key,
    this.txtSinopsis = '',
  });

   final String txtSinopsis;

  @override
  State<SinopsisAudiolibro> createState() => _SinopsisAudiolibroState();

  
  String getSinopsisAudiolibro(){
    sinopsisAudiolibro = getTxtMultilineaExtensible();
    return sinopsisAudiolibro;
  }

  bool getSeHaModificadoSinopsis(){
    bool txtSinopsisModificado = txtMultilineaModificado();
    return txtSinopsisModificado;
  }

  void restaurarEstadoModificacionSinopsis(){
    restaurarEstadoModificacionTxtMult();
  }
}

class _SinopsisAudiolibroState extends State<SinopsisAudiolibro> {
  @override
  Widget build(BuildContext context) {
    double anchuraCosas = MediaQuery.of(context).size.width - devolverValorNumPaddingPaginaGeneral();
    return InputTxtMultilineaExtensible(esModoOscuro: esModoOscuro, anchuraCajaTexto: anchuraCosas, maxCaracteres: maxCaracteresSinopsis, labelFormField: labelTxtSinopsisAudiolibro, iconoTxtMultilinea: iconoTxtSinopsisAudiolibro, hintTextFormField: hintTxtSinopsisAudiolibro, textoAsignado: widget.txtSinopsis,);
  }

}

In this two classes, I called the same widget: InputTxtMultilineaExtensible(), but I created specific methods for these classes to access to the information of the common widget. I thought that, maybe, although the text field was a common widget, to duplicate it in different classes would separate their behaviours. However, it didn't work, the behaviour of the text and the words counter overlap. See this image, for example:

Example of the overlap

I don't have any word written on the second text field, but its counter says I have 50, as the first one, and both counters are in color red, although it's just the first text field which arrived to the words limit.

I don't know if it's possible to reuse a widget like this. I mean, every reusable widget I find in videos are buttons or simple widgets that don't have much information to interact with. The easy way is to duplicate the code, of course, but I wanted to make it cleaner.

Does anyone know how to solve this?

0

There are 0 answers