Los widgets básicos que debes conocer para programar con Flutter


Avatar de Pedro Cortez

Aunque existen cientos de widgets en Flutter, es probable que utilices algunos mucho más frecuentemente que otros. En esta sección, te presento los widgets que debes saber usar prioritariamente para construir una aplicación básica.


flutter widgets base

Widgets para construir tu página

Al igual que en un sitio web, una aplicación móvil se presenta en forma de «páginas» a través de las cuales el usuario puede navegar. La primera tarea es crear un widget de tipo MaterialApp(), que contendrá un Scaffold() (estructura), el cual servirá como esqueleto de la aplicación. Dentro de este Scaffold, colocaremos el body() (cuerpo) de nuestra app, así como una posible AppBar() o una BottomAppBar().

Scaffold

El Scaffold es el widget que se coloca en el parámetro home de tu MaterialApp(). Si la MaterialApp() actúa como un lienzo en blanco, el Scaffold es más bien el esqueleto de tu app, que permite construir los elementos visuales. Este se compone de tres parámetros opcionales, pero importantes:

  • appBar, que toma como argumento un widget de tipo AppBar().
  • body, que puede tomar como argumento un Container, Center(), una columna, etc.
  • bottomNavigationBar, que toma como argumento un widget de tipo BottomAppBar().

Con estos tres elementos, podrás comenzar a construir el aspecto visual de tu aplicación.

Puedes utilizar este código para empezar a practicar y entender cómo los widgets se «anidan» unos dentro de otros:

void main() => runApp(const MonExempleDeScaffold());

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ExempleScaffold(),
    );
  }
}

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

  @override
  State<ExempleScaffold> createState() => _ExempleScaffoldState();
}

class _ExempleScaffoldState extends State<ExempleScaffold> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blueGrey.shade200,
        title: const Text('AppBar de ejemplo'),
      ),
      body: Center(child: Text('Aquí está el cuerpo de mi aplicación')),
      backgroundColor: Colors.white,
    );
  }
}

Aquí, mi función runApp() lanza mi MaterialApp(), sobre la cual descansa mi Scaffold() que contiene todos los elementos visuales de mi página.

Puedes aprender más sobre el Scaffold, su utilidad y los diferentes parámetros que incluye consultando esta guía de la documentación oficial de Flutter.

AppBar

El widget AppBar() se refiere a una banda en la parte superior de la pantalla donde puedes insertar otros widgets, como texto, íconos o botones. Por ejemplo, puedes usarlo para crear un menú en la parte superior de tu página o para reservar un espacio para que el contenido de la aplicación no sea ocultado por la cámara del teléfono.

Puedes aprender más sobre la AppBar, su utilidad y los parámetros que incluye consultando esta guía de la documentación oficial de Flutter.

BottomAppBar

El BottomAppBar() funciona de manera similar a la AppBar, pero en la parte inferior de tu teléfono. Un uso común es crear un menú de íconos que permita navegar por las secciones de tu aplicación. Por ejemplo, aquí tienes un menú que creé utilizando este widget, donde coloqué una TabBar().

Te comparto el código que puedes reutilizar y personalizar según tus necesidades.

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

  @override
  State<PantallaInicio> createState() => _PantallaInicioState();
}

class _PantallaInicioState extends State<PantallaInicio> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        extendBody: true,
        backgroundColor: Colors.white,
        bottomNavigationBar: BottomAppBar(
          color: Colors.transparent,
          elevation: 0,
          child: menu(),
        ),
        body: const TabBarView(
          children: [
            Pagina1(),
            Pagina2(),
            /*
		Aquí es donde debes colocar tus diferentes páginas, cuyo número debe ser igual al de las pestañas (Tabs). Añade o quita pestañas según tus necesidades.
		*/
          ],
        ));
  }

  Widget menu() {
    return Container(
      margin: EdgeInsets.only(right: 25, left: 25),
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(40),
          border: Border.all(
            width: 0.05,
            color: Color.fromARGB(255, 24, 83, 79),
          ),
          color: Colors.white.withOpacity(0.9),
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.2),
              spreadRadius: 2,
              blurRadius: 5,
              offset: Offset(0, 5),
            ),
          ]),
      child: TabBar(
        labelPadding: EdgeInsets.all(5),
        labelColor: Color.fromARGB(255, 33, 46, 83),
        dividerColor: Colors.transparent,
        unselectedLabelColor: Color.fromARGB(255, 33, 46, 83).withOpacity(0.4),
        indicatorSize: TabBarIndicatorSize.label,
        indicatorPadding: EdgeInsets.only(bottom: 5.0),
        indicatorColor: Color.fromARGB(255, 206, 106, 107),
        tabs: const [
          Tab(
            icon: Icon(
              Ionicons.home,
              size: 27,
            ),
          ),
          Tab(
            icon: Icon(
              Ionicons.school,
              size: 27,
            ),
          ),
        ],
      ),
    );
  }
}

Widgets de filas y columnas

Una vez que hayas creado tu página, podrás agregar botones, imágenes, áreas de texto, etc. Sin embargo, supongo que querrás posicionarlos en un lugar exacto de tu aplicación y no de manera aleatoria. Es aquí donde los widgets Row() (fila) y Column() (columna) te serán útiles.

Estos dos widgets, como sus nombres lo indican, te permiten apilar varios widgets ya sea en sentido vertical (columna) o en sentido horizontal (fila). Son especialmente importantes porque un simple Container() solo puede contener un widget en su parámetro child. Esto significa que, por ejemplo, solo podrías colocar un texto en un Container(). Los widgets Row() y Column() solucionan este problema al permitirte agregar tantos widgets como desees en su parámetro children.

Un contenedor solo puede tener un widget hijo, pero este puede ser una fila o una columna, que a su vez puede contener tantos widgets hijos como necesites. Por ejemplo, puedes construir una página de tu aplicación usando un Container() que ocupe toda la pantalla, y dentro de este, incluir un widget de tipo Column(), el cual contendría todos los elementos de la página.

Aquí tienes un ejemplo simple del uso de los widgets Row() y Column():

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

  @override
  State<EjemploFilaColumna> createState() => _EjemploFilaColumnaState();
}

class _EjemploFilaColumnaState extends State<EjemploFilaColumna> {
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          Container(
              color: Colors.purple,
              height: MediaQuery.of(context).size.height * 0.08,
              width: MediaQuery.of(context).size.width * 0.3,
              child: TextButton(
                  onPressed: () {
                  },
                  child: const Text(
                    "Conexión",
                    style: TextStyle(color: Colors.white),
                  ))),

          Container(
              color: Colors.red,
              height: MediaQuery.of(context).size.height * 0.08,
              width: MediaQuery.of(context).size.width * 0.3,
              child: TextButton(
                  onPressed: () {
                  },
                  child: const Text(
                    "Desconexión",
                    style: TextStyle(color: Colors.white),
                  ))),
        ],
      ),
    );
  }
}

Widgets para añadir contenido

Ya has construido tu página y sabes cómo organizar el contenido en ella. Ahora es el momento de añadir tus diferentes elementos visuales.

Container

El widget Container() te permite crear un área rectangular. Puedes darle un alto, un ancho, un color, márgenes, bordes, etc. Lo más importante es que puedes colocar un widget hijo dentro de él, que llenará el espacio. El Container() es, por lo tanto, una buena manera de delimitar un área en la que colocarás un elemento visual de tu aplicación, como una zona de texto, una imagen, un botón, etc.

Text

El widget Text(), como su nombre lo indica, te permite agregar elementos textuales a tu aplicación. Este widget viene con diferentes parámetros que te permiten definir el estilo de tu texto, como su color, tamaño, grosor, etc.

Existen muchos paquetes que enriquecen las posibilidades de personalización de tus textos, como el paquete Google Fonts o AutosizedText.

Image

Añadir imágenes es también algo importante cuando creas una aplicación, por ejemplo, para una página de perfil. Flutter facilita la integración de elementos visuales con su widget Image(), que puedes utilizar de las siguientes maneras:

  • .asset() -> Permite integrar imágenes o GIFs almacenados en las carpetas de tu aplicación y añadidos en tu archivo pubspec.yaml;
  • .network() -> Permite integrar imágenes o GIFs accesibles en línea mediante su URL.

Icon

Al igual que las imágenes, los íconos son elementos visuales importantes para construir una aplicación, especialmente para crear botones. El widget Icon() te permite agregar un ícono a tu aplicación y modificar su estilo, como el color, tamaño, etc.

Existen muchos paquetes que te permiten acceder a recursos de íconos gratuitos en línea. Para más información, te invito a leer mi guía sobre los paquetes de íconos en Flutter.

ElevatedButton

Para permitir que tus usuarios interactúen con tu aplicación, necesitarás agregar botones. La forma más simple de hacerlo es usando el widget ElevatedButton. Este widget te permite crear casi cualquier tipo de botón, ya sea a partir de una forma, un texto o un ícono, e integrarle una función. Por ejemplo:

Container(
  height: MediaQuery.of(context).size.height * 0.06,
  width: MediaQuery.of(context).size.width * 0.5,
  child: ElevatedButton(
        onPressed: () {
	print("Mi botón funciona");
        },
  style: ElevatedButton.styleFrom(
    surfaceTintColor: Colors.white,
    shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.all(Radius.circular(30))),
    side: const BorderSide(
         color: Colors.black, width: 1)),
         child: const Text("Botón de prueba",
          style: TextStyle(color: Colors.black))))

Conclusión

Estos widgets son la base de cualquier aplicación y son un buen punto de partida para construir la tuya. Aprende a usarlos jugando con sus diferentes propiedades e intenta reproducir los elementos visuales de otras aplicaciones. Si quieres aprender más, he escrito una guía para cada uno de ellos:

  • Guía completa Flutter: el widget Scaffold;
  • Guía completa Flutter: el widget Container;
  • Guía completa Flutter: el widget Column;
  • Guía completa Flutter: el widget Row;
  • Guía completa Flutter: el widget Text;
  • Guía completa Flutter: el widget Icon;
  • Guía completa Flutter: el widget Image;
  • Guía completa Flutter: el widget ElevatedButton.

Una vez que domines la creación de la interfaz de tu aplicación, será hora de enfocarte en el backend. ¿Cómo almacenarás los datos y los transmitirás a tus usuarios? ¿Cómo gestionarás las cuentas de usuario y la autenticación? Te doy la respuesta en el siguiente artículo:

Avatar de Pedro Cortez