Entrada de usuario en Flutter

Esta sección explica cómo manejar la entrada de usuario en aplicaciones Flutter, incluyendo entrada de texto, clics en botones, manejo de formularios, etc.


TextField - Entrada de texto

TextField es el widget de entrada de texto más utilizado en Flutter.

Ejemplo: Uso básico de TextField

// El TextField más simple
TextField()

// TextField con decoración
TextField(
  decoration: const InputDecoration(
    labelText: 'Nombre de usuario',  // Etiqueta
    hintText: 'Ingrese el nombre de usuario',  // Texto de sugerencia
    prefixIcon: Icon(Icons.person),  // Icono prefijo
  ),
)

// TextField con borde
TextField(
  decoration: InputDecoration(
    border: OutlineInputBorder(  // Borde exterior
      borderRadius: BorderRadius.circular(8),
    ),
    labelText: 'Contraseña',
  ),
  obscureText: true,  // Ocultar contenido de entrada (escenario de contraseña)
)

// Entrada de texto multilínea
TextField(
  maxLines: 3,  // Número máximo de líneas
  decoration: const InputDecoration(
    hintText: 'Ingrese texto multilínea',
  ),
)

TextEditingController - Controlador de texto

Usando TextEditingController se puede leer y controlar el contenido de TextField.

< h2 class="example">Ejemplo: Uso de TextEditingController
class TextFieldExample extends StatefulWidget {
  const TextFieldExample({super.key});

  @override
  State<TextFieldExample> createState() => _TextFieldExampleState();
}

class _TextFieldExampleState extends State<TextFieldExample> {
  // Crear controlador
  final TextEditingController _controller = TextEditingController();
  String _displayText = '';

  @override
  void dispose() {
    // Destruir controlador
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          controller: _controller,  // Vincular controlador
          decoration: const InputDecoration(
            labelText: 'Ingresar texto',
          ),
          onChanged: (text) {
            // Escuchar cambios de texto
            print('Entrada actual: $text');
          },
        ),
        const SizedBox(height: 20),
        // Mostrar el texto ingresado
        Text('Has ingresado: $_displayText'),
        const SizedBox(height: 20),
        ElevatedButton(
          onPressed: () {
            // Leer texto
            setState(() {
              _displayText = _controller.text;
            });
          },
          child: const Text('Mostrar entrada'),
        ),
        ElevatedButton(
          onPressed: () {
            // Vaciar texto
            _controller.clear();
          },
          child: const Text('Vaciar'),
        ),
        ElevatedButton(
          onPressed: () {
            // Establecer texto
            _controller.text = 'Texto preestablecido';
          },
          child: const Text('Establecer texto'),
        ),
      ],
    );
  }
}

Control de foco

Usando FocusNode se puede controlar el foco del campo de entrada.

Ejemplo: Control de foco

class FocusExample extends StatefulWidget {
  const FocusExample({super.key});

  @override
  State<FocusExample> createState() => _FocusExampleState();
}

class _FocusExampleState extends State<FocusExample> {
  final FocusNode _focusNode1 = FocusNode();
  final FocusNode _focusNode2 = FocusNode();

  @override
  void dispose() {
    _focusNode1.dispose();
    _focusNode2.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          focusNode: _focusNode1,
          decoration: const InputDecoration(labelText: 'Campo de entrada 1'),
        ),
        const SizedBox(height: 10),
        TextField(
          focusNode: _focusNode2,
          decoration: const InputDecoration(labelText: 'Campo de entrada 2'),
        ),
        const SizedBox(height: 20),
        ElevatedButton(
          onPressed: () {
            // Enfocar el campo de entrada 1
            _focusNode1.requestFocus();
          },
          child: const Text('Enfocar campo de entrada 1'),
        ),
        ElevatedButton(
          onPressed: () {
            // Enfocar el campo de entrada 2
            _focusNode2.requestFocus();
          },
          child: const Text('Enfocar campo de entrada 2'),
        ),
        ElevatedButton(
          onPressed: () {
            // Quitar el foco
            _focusNode1.unfocus();
            _focusNode2.unfocus();
          },
          child: const Text('Quitar foco'),
        ),
      ],
    );
  }
}

Botones y eventos de clic

Flutter proporciona varios componentes de botón para manejar los clics del usuario.

Ejemplo: Varios botones

// TextButton - Botón de texto
TextButton(
  onPressed: () => print('Se hizo clic en el botón de texto'),
  child: const Text('Botón de texto'),
)

// ElevatedButton - Botón elevado
ElevatedButton(
  onPressed: () => print('Se hizo clic en el botón elevado'),
  child: const Text('Enviar'),
)

// OutlinedButton - Botón con contorno
OutlinedButton(
  onPressed: () => print('Se hizo clic en el botón con contorno'),
  child: const Text('Cancelar'),
)

// IconButton - Botón de icono
IconButton(
  icon: const Icon(Icons.favorite),
  onPressed: () => print('Se hizo clic en el botón de icono'),
)

// Botón con icono
ElevatedButton.icon(
  onPressed: () => print('Se hizo clic en el botón con icono'),
  icon: const Icon(Icons.save),
  label: const Text('Guardar'),
)

// CupertinoButton - Botón estilo iOS
CupertinoButton(
  child: const Text('Botón iOS'),
  onPressed: () {},
)

Switch、Checkbox、Radio

Ejemplo: Interruptor, casilla de verificación, botón de opción

class SwitchCheckboxExample extends StatefulWidget {
  const SwitchCheckboxExample({super.key});

  @override
  State<SwitchCheckboxExample> createState() => _SwitchCheckboxExampleState();
}

class _SwitchCheckboxExampleState extends State<SwitchCheckboxExample> {
  bool _switchValue = false;
  bool _checkboxValue = false;
  String _radioValue = 'A';

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Switch - Interruptor
        Switch(
          value: _switchValue,
          onChanged: (value) {
            setState(() {
              _switchValue = value;
            });
          },
        ),
        Text('Valor de Switch: $_switchValue'),

        // Checkbox - Casilla de verificación
        Checkbox(
          value: _checkboxValue,
          onChanged: (value) {
            setState(() {
              _checkboxValue = value ?? false;
            });
          },
        ),
        Text('Valor de Checkbox: $_checkboxValue'),

        // Radio - Botón de opción
        Row(
          children: [
            Radio<String>(
              value: 'A',
              groupValue: _radioValue,
              onChanged: (value) {
                setState(() {
                  _radioValue = value!;
                });
              },
            ),
            const Text('Opción A'),
            Radio<String>(
              value: 'B',
              groupValue: _radioValue,
              onChanged: (value) {
                setState(() {
                  _radioValue = value!;
                });
              },
            ),
            const Text('Opción B'),
          ],
        ),
        Text('Valor de Radio: $_radioValue'),
      ],
    );
  }
}

Slider - Control deslizante

Ejemplo: Uso de Slider

class SliderExample extends StatefulWidget {
  const SliderExample({super.key});

  @override
  State<SliderExample> createState() => _SliderExampleState();
}

class _SliderExampleState extends State<SliderExample> {
  double _sliderValue = 0.5;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Slider(
          value: _sliderValue,  // Valor actual (0.0-1.0)
          min: 0.0,
          max: 1.0,
          divisions: 10,  // Dividido en 10 marcas
          label: '${(_sliderValue * 100).round()}%',
          onChanged: (value) {
            setState(() {
              _sliderValue = value;
            });
          },
        ),
        Text('Valor actual: ${(_sliderValue * 100).round()}%'),

        // Control deslizante de rango
        RangeSlider(
          values: const RangeValues(0.3, 0.7),
          min: 0.0,
          max: 1.0,
          onChanged: (values) {
            print('Rango: ${values.start} - ${values.end}');
          },
        ),
      ],
    );
  }
}

Al manejar la entrada de usuario, recuerde usar setState para actualizar el estado de la interfaz, para que la interfaz responda a las acciones del usuario.

Otras extensiones