Flutter — Widgets básicos


La Interfaz de Usuario en Flutter, está compuesta de Widgets. Los Widgets en Flutter se construyen utilizando un Framework moderno inspirado en React. Casi todo en Flutter está compuesto de Widgets. Los Widgets describen como sería su vista dado una configuración y estado actual. Cuando el estado cambia, el Widget se reconstruye.


Inicio de Flutter

Como ya vimos anteriormente en Flutter — Estructura de proyecto, el archivo /lib/main.dart, es donde inicia la aplicación de Flutter. Todo inicia desde el método main() que dentro ejecuta un método runApp(), es un método sin retorno y recibe como parámetro un Widget, que sería el Widget padre o la raíz del árbol de Widgets.

import 'package:flutter/material.dart';

void main() {
  runApp(
    const Center(
      child: Text(
        '¡Hola Mundo!',
        textDirection: TextDirection.ltr,
      ),
    ),
  );
}

Los Widgets son subclases de StatelessWidget o StatefulWidget. Todo depende de si se quiere guardar el estado o no del widget. Todos los widgets deben implementar la función build(), dentro de este se va armando la estructura necesaria para el widget requerido. El StatelessWidget se utiliza cuando no es necesario conservar el estado del widget, para guardar el estado o alguna otra característica de un widget es recomendable usar StatefulWidget o algún manejador de estados.

Widgets básicos

Hay una serie de Widgets que se utilizan constantemente en las aplicaciones de Flutter. La idea es poder ver de forma general cómo se utiliza cada uno.

Text

Es un widget que permite crear textos con estilos personalizados.

Para crear un widget Text personalizado, podemos hacerlo de la siguiente manera:

import 'package:flutter/material.dart';

class CustomText extends StatelessWidget {
  const CustomText({super.key});

  @override
  Widget build(BuildContext context) {
    return const Text('Esto es un Text Widget');
  }
}

el const que va antes de los widget es importante para el rendimiento de la aplicación de Flutter, ya que lo que hace es que cuando hay un renderizado o el widget raíz es reconstruido, todos los que estén marcados con const no se van a reconstruir, lo cual ayuda mucho a mejorar el rendimiento de la aplicación.

También es posible enviar la propiedad del texto que vamos a mostrar como parámetro al CustomText para que sea más dinámico el widget, incluso las demás propiedades que necesitemos.

import 'package:flutter/material.dart';

class CustomText extends StatelessWidget {
  // agregamos la propiedad con nombre y la palabra required
  // para que sea obligatoria
  const CustomText({super.key, required this.text});

  final String text;

  @override
  Widget build(BuildContext context) {
    return Text(text);
  }
}

// en la clase main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app_test/widgets/text_widget.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const Center(
      child: CustomText(text: 'Esto es un Text Widget'),
    );
  }
}

Vemos que el const ya no se puede usar porque el valor de text es dinámico.

Row 

Es un widget que permite tener un diseño flexible y tener widgets hijos en un conjunto horizontal (Fila).

import 'package:flutter/material.dart';

class CustomRow extends StatelessWidget {
  const CustomRow({super.key, required this.children});

  final List<Widget> children;

  @override
  Widget build(BuildContext context) {
    return Row(
      // con MaterialApp no es necesario el TextDirection
      textDirection: TextDirection.ltr,
      children: children,
    );
  }
}

// en el main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app_test/widgets/custom_row.dart';
import 'package:flutter_app_test/widgets/custom_text.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: CustomRow(children: [
        CustomText(text: 'Widget 1 '),
        CustomText(text: 'Widget 2 '),
        CustomText(text: 'Widget 3 ')
      ]),
    );
  }
}

Column

Es un widget al igual que el Row, es de diseño flexible y permite tener widgets hijos en un conjunto vertical (Columna).

import 'package:flutter/material.dart';

class CustomColumn extends StatelessWidget {
  const CustomColumn({super.key, required this.children});

  final List<Widget> children;

  @override
  Widget build(BuildContext context) {
    return Column(
    // es como se van a acomodar a los hijos del Column
    // en el eje de arriba - abajo.
      mainAxisAlignment: MainAxisAlignment.center,
      textDirection: TextDirection.ltr,
      children: children,
    );
  }
}

// en el main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app_test/widgets/custom_column.dart';
import 'package:flutter_app_test/widgets/custom_text.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: CustomColumn(children: [
        CustomText(text: 'Widget 1 '),
        CustomText(text: 'Widget 2 '),
        CustomText(text: 'Widget 3 ')
      ]),
    );
  }
}

Se utiliza la propiedad mainAxisAlignment, que lo que hace es colocar los widgets hijos en determinada posición del eje principal que es la columna, es decir, de arriba hacia abajo.

Stack

El widget Stack permite colocar widgets uno encima de otro. Es un widget que posiciona a sus hijos en relación con los bordes de su caja. Aquí se puede utilizar otro widget Positioned que se encarga de controlar en dónde se van a ubicar los hijos de Stack.

import 'package:flutter/material.dart';

class CustomStack extends StatelessWidget {
  const CustomStack({super.key, required this.children});

  final List<Widget> children;

  @override
  Widget build(BuildContext context) {
    return Stack(
      textDirection: TextDirection.ltr,
      children: children,
    );
  }
}

// en el main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app_test/widgets/custom_stack.dart';
import 'package:flutter_app_test/widgets/custom_text.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const CustomStack(children: [
        Positioned(
          top: 300,
          right: 10,
          child: CustomText(
            text: '####################',
            color: Colors.red,
         ),
      ),
      Positioned(
        left: 100,
        top: 200,
        child: CustomText(
          text: '####################',
          color: Colors.blue,
        ),
      ),
      Positioned(
        top: 100,
        child: CustomText(
          text: '####################',
          color: Colors.yellow,
        ),
      )
    ]);
  }
}

De Positioned se utilizaron las propiedades:

  • top: que define la cantidad de pixeles que va a tener el widget hijo desde la parte superior de la pantalla.
  • left: define los pixeles desde izquierda a derecha de la pantalla.
  • right: define los pixeles de derecha a izquierda de la pantalla.
  • bottom: define los pixeles desde la parte inferior de la pantalla a la superior.

Container

El widget Container permite crear un elemento rectangular, el cual se puede decorar con estilos, el fondo, sombras y formas con otro widget BoxDecoration. El widget BoxDecoration básicamente es un widget que nos permite pintar o dibujar una caja en blanco a nuestra necesidad.

import 'package:flutter/material.dart';

class CustomContainer extends StatelessWidget {
  const CustomContainer({super.key, required this.color, required this.radius});

  final Color color;
  final double radius;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100, // alto
      width: 100, // ancho
      margin: const EdgeInsets.all(8), // margen
      decoration: BoxDecoration(
        color: color, // color del fondo
        borderRadius: BorderRadius.circular(radius), // radio de las esquinas
      ),
    );
  }
}

// en main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app_test/widgets/custom_column.dart';
import 'package:flutter_app_test/widgets/custom_container.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const CustomColumn(
      children: [
        CustomContainer(color: Colors.yellow, radius: 1),
        CustomContainer(color: Colors.blue, radius: 50),
        CustomContainer(color: Colors.red, radius: 25),
      ],
    );
  }
}

Agrega algunas de las propiedades que tiene el widget Container, como:

  • height: para darle un alto específico al contenedor.
  • width: para darle un ancho específico al contenedor.
  • margin: La propiedad EdgeInsets.all aplica los cambios a todos los lados por igual. Esto con el fin de que no queden pegados los contenedores.
  • decoration: Aquí se usa el widget BoxDecoration y usamos 2 de sus propiedades: el color y el radio de los bordes del rectángulo.

Conclusión

Realizamos un breve paso muy general por los widgets básicos de Flutter que son bastante utilizados en el desarrollo de aplicaciones móviles con Flutter, como lo son: Text, Row, Column, Stack y Container.

Siguientes pasos

Veremos cómo Material facilita la creación de una app Flutter.

Código fuente

GitHub – jaimetellezb/flutter-basic-widgets: Widgets básicos de Flutter.

Referencias

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *