Flutter Widgets: Understanding a suite of powerful basic widgets

FlutterGuide - Flutter Widgets

In this article, we are going to learn the concept of a widget, how to create it, and the different types of widgets available in the Flutter framework. For Understanding the basic widget that is used in a flutter, first of all, we should know what is a widget in a flutter.

Also read: Insights on Flutter Widgets.

We learned that everything in Flutter is a widget. In fact, A widget is a building block for our user interface. It is a blueprint for displaying our app state. Therefore, whenever you are going to code for building anything in Flutter, it will be inside a widget. The central purpose is to build the app out of widgets. It describes how your app view should look with their current configuration and state. When you made any alteration in the code, the widget rebuilds its description by calculating the difference between the previous and current widget to determine the minimal changes for rendering in the UI of the app.

Flutter comes with a suite of powerful basic widgets, of which the following are commonly used:

  1. Text
  2. Rows
  3. Container
  4. Column
  5. Stack
  6. List View

1. Text Widget

The text widget lets us create a run of styled text within our application. In short, A Text is a Flutter Widget that allows us to display a string of text with a single line in our application. Depending on the layout constraints, we can break the string across multiple lines or might all be displayed on the same line. If we do not specify any styling to the text widget, it will use the closest DefaultTextStyle class style. Otherwise, this class does not have any explicit style.

In this article, we are going to learn how to use a Text widget and how to style it in our application.

Let’s take a basic example of how to use a text widget in our application

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({ Key? key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: TextScreen(),
    );
  }
}
class TextScreen extends StatelessWidget {
  const TextScreen({ Key? key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Text Widget'),
        centerTitle: true,
        backgroundColor: Colors.teal,
      ),
      body: const Center(
        child: Text('Welcome to Yellow Nepal'),
      ),
    );
  }
}

In the above code, we have used a MaterialApp widget that calls the home screen using the TextScreen() class. This class contains the scaffold widget, which has appBar and body where we have used the Text widget to display the title and body, respectively. It is a simple scenario of Text widget where we have to pass the string that we want to display on our page.

Meanwhile, when we run this application in the emulator or device, we should get the UI similar to the below screenshot:

The Different Constructor used in Text Widget are summarized below in the Table

TextAlignused to specify how our text is aligned horizontally & controls the text location
TextDirectionused to determine how text-align values control the layout of our text, & we write text from left to right, but we can change it using this parameter.
Overflowused to determine when the text will not fit in the available space
TextScaleFactorused to determine the scaling to the text displayed by the Text widget.
SoftWrapused to determine whether or not to show all text widget content when there is not enough space available
MaxLinesused to determine the maximum number of lines displayed in the text widget
TextWidthBasisused to control how the text width is defined
TextHeightBehaviorused to control how the paragraph appears between the first line and descent of the last line.
Styleallows us to styling their text. It can do styling by specifying the foreground and background color, font size, font weight, letter and word spacing, locale, shadows, etc
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

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

class TextScreen extends StatelessWidget {
  const TextScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Text Widget'),
        centerTitle: true,
        backgroundColor: Colors.teal,
      ),
      body: const Center(
        child: Text(
          'Welcome to Yellow Nepal',
          style: TextStyle(
            fontSize: 35,
            color: Colors.purple,
            fontWeight: FontWeight.w700,
            fontStyle: FontStyle.italic,
          ),
          textAlign: TextAlign.justify,
          textDirection: TextDirection.ltr,
          maxLines: 20,
        ),
      ),
    );
  }
}

Subsequently, after including some properties in the above Text Widget. The Output will be.

2. Row Widget

This Flutter widget arranges its children in a horizontal direction on the screen. In other words, it will expect child widgets in a horizontal array. If the child widgets need to fill the available horizontal space, we must wrap the children’s widgets in an Expanded widget. The Row widget does not scroll. If you have a line of widgets and want them to be able to scroll if there is insufficient room, consider using a ListView Class. We can control a row widget aligns its children based on our choice using the property crossAxisAlignment and mainAxisAlignment. The row’s cross-axis will run vertically, and the main axis will run horizontally.

We can see the below visual representation in order to understand it more clearly.

The Different Properties of Row Widget are summarized in below table:

childrentakes in List<Widget>, that is a list of widgets to display inside the Row widget
crossAxisAlignmenttakes in CrossAxisAlignment enum as the object to how the children’s widgets should be placed in crossAxisAlignment. For Row it is vertical.
mainAxisAlignmenttakes in MainAxisAlignment enum as the object to decide how the children widgets should be placed in main axis alignment. For Row it is horizontal.
mainAxisSizedecides the size of the main-axis by taking in MainAxisSize enum as the object
textBaselineresponsible for the alignment of the text in the Row widget with respect to a baseline
textDirectioncontrols the text direction of the Row widget, which can either be from left-to-right (by default) or right-to-left
verticalDirectiontakes in VerticalDirection enum as the object to determine the order in which the children should be layered

Furthermore, We can align the content by using the following properties.

startPlace the children from the starting of the row
endPlace the children at the end of the row
centerPlace the children at the center of the row
spaceBetweenPlace the space evenly between the children
spaceAroundPlace the space evenly between the children and also half of that space before and after the first and last child.
spaceEvenlyPlace the space evenly between the children and also before and after the first and last child
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

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

class TextScreen extends StatelessWidget {
  const TextScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Text Widget'),
        centerTitle: true,
        backgroundColor: Colors.teal,
      ),
      body: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Container(
            margin: const EdgeInsets.all(08),
            padding: const EdgeInsets.symmetric(
              horizontal: 08,
              vertical: 05,
            ),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(06),
              color: Colors.green,
            ),
            child: const Text('Flutter'),
          ),
          Container(
            margin: const EdgeInsets.all(08),
            padding: const EdgeInsets.symmetric(
              horizontal: 08,
              vertical: 05,
            ),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(06),
              color: Colors.red,
            ),
            child: const Text('Firebase'),
          ),
          Container(
            margin: const EdgeInsets.all(08),
            padding: const EdgeInsets.symmetric(
              horizontal: 08,
              vertical: 05,
            ),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(06),
              color: Colors.amber,
            ),
            child: const Text('Dart'),
          ),
        ],
      ),
    );
  }
}

when we run these app on the physical device or emulator we get the following output which is shown below

3. Column Widget

This is the Flutter widget that help us to arranges its children in a vertical direction on the screen. In other words, it will expect a vertical array of children widgets. If the child widgets need to fill the available vertical space, we must wrap the children widgets in an Expanded widget. The Column widget does not scroll. If you have a line of widgets and want them to be able to scroll if there is insufficient room, consider using a ListView Class.

We can also control how a column widget aligns its children using the property mainAxisAlignment and crossAxisAlignment. The column’s cross-axis will run horizontally, and the main axis will run vertically. We can see the below visual representation in order to understand it clearly.

The Different Properties of Column Widget are summarized in below table:

children takes in List<Widget>, that is a list of widgets to display inside the Column widget
crossAxisAlignmentHow the children should be placed along the cross axis.Defaultsto CrossAxisAlignment.center
mainAxisAlignmentHow the children should be placed along the main axis. Defaults to MainAxisAlignment.start
mainAxisSizeHow much space should be occupied in the main axis.. Defaults to MainAxisSize.max
textBaselinehe baseline to use if aligning items using their baseline. Defaults tO TextBaseLine.alphabetic
textDirectionused to set the order to lay children out horizontally and how start and end should be interpreted in the horizontal direction.
keyThe widget’s key.
verticalDirectionused to set the order to lay children out vertically and how start and end should be interpreted in the vertical direction. Defaults to VerticalDirection.down
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

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

class TextScreen extends StatelessWidget {
  const TextScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Column Widget'),
        centerTitle: true,
        backgroundColor: Colors.teal,
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Container(
            margin: const EdgeInsets.all(08),
            padding: const EdgeInsets.symmetric(
              horizontal: 08,
              vertical: 05,
            ),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(06),
              color: Colors.green,
            ),
            child: const Text('Flutter'),
          ),
          Container(
            margin: const EdgeInsets.all(08),
            padding: const EdgeInsets.symmetric(
              horizontal: 08,
              vertical: 05,
            ),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(06),
              color: Colors.red,
            ),
            child: const Text('Firebase'),
          ),
          Container(
            margin: const EdgeInsets.all(08),
            padding: const EdgeInsets.symmetric(
              horizontal: 08,
              vertical: 05,
            ),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(06),
              color: Colors.amber,
            ),
            child: const Text('Dart'),
          ),
        ],
      ),
    );
  }
}

when we run these app on the physical device or emulator we get the following output which is shown below

4. Container Widget

The container is a parent Flutter widget that can contain multiple child widgets and manage them efficiently through width, height, padding, background color, etc. In order word It is a widget that combines common painting, positioning, and sizing of the child widgets. It helps us to store one or more widgets and position them on the screen according to our needs. It allows many attributes to the user for decorating its child widgets, such as using margin, which separates the container with other contents.

A container widget is same as <div> tag in html. If this widget does not contain any child widget, it will fill the whole area on the screen automatically. Otherwise, it will wrap the child widget according to the specified height & width.

Properties of Container Class:

childstores its children. The child class can be any widget.
colorsets the background color of the entire container.
height and widthset the height and width of the container.By default, It takes the space that is required by the child.
marginused to create an empty space around the container.
paddingused to give space form the border of the container form its children.
alignmentused to position the child within the container in different ways: bottom, bottom center, left, right, etc.
decorationused to decorate the box(e.g. give a border).
transformhelps us to rotate the container in any axis.
constraintsgive additional constraints to the child.
clipBehaviour takes in Clip enum as the object & decides whether the content inside the container will be clipped or not.
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

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

class TextScreen extends StatelessWidget {
  const TextScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Container Widget'),
        centerTitle: true,
        backgroundColor: Colors.teal,
      ),
      body: Container(
        height: 250,
        width: double.infinity,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(15),
          color: Colors.purple,
        ),
        alignment: Alignment.center,
        margin: const EdgeInsets.all(30),
        padding: const EdgeInsets.all(30),
        transform: Matrix4.rotationZ(0.05),
        child: const Text("Hello! welcome to flutter guide!",
            style: TextStyle(
              fontSize: 20,
              color: Colors.white,
            )),
      ),
    );
  }
}

when we run these app on the physical device or emulator we get the following output which is shown below

5. Stack Widget

It is a built-in Flutter widget in flutter SDK which allows us to make a layer of widgets by putting them on top of each other.In other words, it allows us to overlap multiple widgets into a single screen and renders them from bottom to top. Such that, the first widget is the bottommost item, and the last widget is the topmost item.By default, the first widget of each stack has the maximum size compared to other widgets.

for example, we might want to show some text over an image, so to tackle such a situation we have Stack widget.The Stack widget has two types of child one is positioned which are wrapped in the Positioned widget and the other one is nonpositionedwhich is not wrapped in the Positioned widget.

Properties of Stack Widget:

alignmenttakes a parameter of Alignment Geometry, and controls how a child widget which is non-positioned or partially-positioned will be aligned in the Stack.
clipBehaviourdecided whether the content will be clipped or not.
fitdecided how the non-positioned children in the Stack will fill the space available to it.
overflowcontrols whether the overflow part of the content will be visible or not.
textDirectionchoose the text direction from right to left. or left to right.
children takes in List<Widget>, that is a list of widgets to display inside the Stack widget
keyThe widget Key
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

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

class TextScreen extends StatelessWidget {
  const TextScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Stack Widget'),
        centerTitle: true,
        backgroundColor: Colors.teal,
      ),
      body: Column(
        children: [
          Stack(
            fit: StackFit.loose,
            children: [
              Container(
                margin: const EdgeInsets.all(20),
                height: 300,
                width: 300,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(10),
                  color: Colors.green,
                ),
              ),
              Positioned(
                top: 10,
                right: 15,
                child: Container(
                  alignment: Alignment.center,
                  margin: const EdgeInsets.all(20),
                  height: 150,
                  width: 250,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(10),
                    color: Colors.red,
                  ),
                  child: const Text(
                    'Welcome to Flutter Guide',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 20,
                    ),
                  ),
                ),
              ),
              Positioned(
                bottom: 10,
                left: 05,
                child: Container(
                  alignment: Alignment.center,
                  margin: const EdgeInsets.all(20),
                  height: 100,
                  width: 250,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(10),
                    color: Colors.amber,
                  ),
                  child: const Text(
                    'Welcome to Flutter',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 20,
                    ),
                  ),
                ),
              ),
            ],
          ),
          const Text(
            'Stack Widget',
            style: TextStyle(
              color: Colors.red,
              fontSize: 20,
            ),
          )
        ],
      ),
    );
  }
}

when we run these app on the physical device or emulator we get the following output which is shown below

6. ListView Widget

A ListView in Flutter is a linear list of scrollable items which helps us to make a list of items scrollable or make a list of repeating items.It displays its children one after another in the scroll direction i.e, vertical or horizontal.

There are different types of ListViews :

  1. ListView
  2. ListView.builder
  3. ListView.separated
  4. ListView.custom

6.1 ListView

This is the default constructor of the ListView class. It simply takes a list of widgets and makes it scrollable.

Some Widely used Properties of ListView Widgets:

childrenDelegateakes SliverChildDelegate as the object. It serves as a delegate that provided the children for the ListView.
clipBehaviourholds Clip enum (final) as the object & controls whether the content in the ListView will be clipped or not.
itemExtenttakes in a double value as the object to controls the scrollable area in the ListView.
paddingholds EdgeInsetsGeometryI as the object to give space between the Listview and its children.
scrollDirectiontakes in Axis enum as the object to decide the direction of the scroll on the ListView.
shrinkWraptakes in a boolean value as the object to decide whether the size of the scrollable area will be determined by the contents inside the ListView.
children takes in List<Widget>, that is a list of widgets to display inside the ListViewwidget
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

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

class TextScreen extends StatelessWidget {
  const TextScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ListView Widget'),
        centerTitle: true,
        backgroundColor: Colors.teal,
      ),
      body: ListView(
        children: const [
          SizedBox(
            height: 20,
          ),
          CircleAvatar(
            maxRadius: 50,
            backgroundColor: Colors.black,
            child: Icon(Icons.person, color: Colors.white, size: 50),
          ),
          Center(
            child: Text(
              'Flutter Guide',
              style: TextStyle(
                fontSize: 50,
              ),
            ),
          ),
          Padding(
            padding: EdgeInsets.all(8.0),
            child: Text(
              "Dart is an open-source, general-purpose, object-oriented programming language with C-style syntax developed by Google in 2011. The purpose of Dart programming is to create a frontend user interfaces for the web and mobile apps. It is under active development, compiled to native machine code for building mobile apps, inspired by other programming languages such as Java, JavaScript, C#, and is Strongly Typed. Since Dart is a compiled language so you cannot execute your code directly; instead, the compiler parses it and transfer it into machine code.It supports most of the common concepts of programming languages like classes, interfaces, functions, unlike other programming languages. Dart language does not support arrays directly. It supports collection, which is used to replicate the data structure such as arrays, generics, and optional typing.Dart is a Strongly Typed programming language. It means, each value you use in your programming language has a type either string or number and must be known when the code is compiled. Here, we are going to discuss the most common basic data types used in the Dart programming language.",
              style: TextStyle(
                fontSize: 20,
              ),
              textAlign: TextAlign.justify,
            ),
          ),
        ],
      ),
    );
  }
}

when we run these app on the physical device or emulator we get the following output which is shown below

6.2 ListView.builder()

The builder() constructor constructs a repeating list of Flutter widgets. It take mainly two main parameters:  

  • An itemCount for the number of repetitions for the widget to be constructed (not compulsory).
  • An itemBuilder for constructing the widget which will be generated ‘itemCount‘ times (compulsory).

If the itemCount is not specified, infinite widgets will be constructed by default. 

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

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

class TextScreen extends StatelessWidget {
  const TextScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('ListView Builder Widget'),
          centerTitle: true,
          backgroundColor: Colors.teal,
        ),
        body: ListView.builder(
            itemCount: 20,
            itemBuilder: (context, index) {
              return Container(
                  alignment: Alignment.center,
                  margin: const EdgeInsets.all(10),
                  height: 60,
                  width: double.infinity,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(20),
                    color: Colors.black,
                  ),
                  child: Text(
                    "$index",
                    style: const TextStyle(
                      fontSize: 20,
                      color: Colors.white,
                    ),
                  ));
            }));
  }
}

when we run these app on the physical device or emulator we get the following output which is shown below

6.3 ListView.separated ()

The ListView.separated() constructor is used to generate a list of widgets, but in addition, a separator widget can also be generated to separate the widgets. In short, these are two intertwined list of Flutter widgets: the main list and the separator list.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

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

class TextScreen extends StatelessWidget {
  const TextScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('ListView Builder Widget'),
          centerTitle: true,
          backgroundColor: Colors.teal,
        ),
        body: ListView.separated(
            separatorBuilder: (context, index) {
              return const SizedBox();
            },
            itemCount: 20,
            itemBuilder: (context, index) {
              return Container(
                  alignment: Alignment.center,
                  margin: const EdgeInsets.all(10),
                  height: 60,
                  width: double.infinity,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(20),
                    color: Colors.black,
                  ),
                  child: Text(
                    "$index",
                    style: const TextStyle(
                      fontSize: 20,
                      color: Colors.white,
                    ),
                  ));
            }));
  }
}

The output will be the same as above in the Listview.builder.Here it take separatorBuilder as an extra parameter that we return an empty sizedbox. we can also return here widget too.

6.4 ListView.custom()

It lets us to build ListViews with custom functionality for the children of the list to built. The main parameter of this constructor is a SliverChildDelegate which builds the items. 

 The types of SliverChildDelegates are :  

  • SliverChildListDelegate
  • SliverChildBuilderDelegate

The SliverChildListDelegate accepts a list of children widgets. whereas the SliverChildBuilderDelegate accepts an IndexedWidgetBuilder, simply a builder() function. The default ListView() constructor is a ListView.custom with a SliverChildListDelegate.

Also read: How To Add And Remove Item From List Array In Flutter