A Guide to Flutter Widgets
Story by Mila Klimkowicz
16 min read
In our previous blog post, we gave a brief introduction to Flutter explaining in a nutshell what it is and how it works. If you're new to Flutter, we suggest checking it out. But if you're already somewhat familiar with Flutter, then this blog post may be of interest to you, as we'll be diving into one of Flutter’s defining features aka its use of widgets.
We'll explore the 14 categories of widgets presented on Flutter's documentation website. For each category, we'll provide an example of a widget to help illustrate its use. Without any further delay, let’s jump right in!
Introduction to widgets
When we hear the word "widget" we may associate it with the small interactive components that we find on smartphones, which typically offer a limited set of information from an application. Similarly, in the context of WordPress, widgets can display a portion of content from another website and can be embedded on web pages. Sometimes widgets can get confused with plugins or extensions. A plugin or an add-on usually expands the features of a browser, while an extension enhances the functionality of a particular platform.
In Flutter, the term "widget" has a different meaning. In this context, a widget is more like a "code snippet" or "component" that speeds up the process of developing an app's interface. They not only define the app's structure but, interestingly enough, are also used to “tell” other widgets what they should look like and how they should behave. In other words, widgets are responsible for describing the styling and interactions within your app. So essentially - everything in Flutter is a widget!
Types of widgets
When building a Flutter application, developers can use either a StatelessWidget or a StatefulWidget. StatelessWidget is a type of widget that does not change its state once it has been created. Examples of these widgets include Text and IconButton. On the other hand, a StatefulWidget is a type of widget whose state can change during its lifetime. An example of a StatefulWidget is the CheckBox widget.
Before we start discussing the different categories of widgets in Flutter, it's essential to understand that widgets are organized into a tree hierarchy known as the "widget tree." The layout of the app that appears on the screen is the widget tree, which includes parent widgets and child widgets (and these child widgets can also have their own child widgets).
Flutter Widgets Categories:
- Animation and Motion
- Assets, Images, and Icons
- Cupertino (iOS-style widgets)
- Interaction Models
- Material Components
- Painting and effects
Listed above are the 14 categories in the Widget Catalog displayed on the Flutter documentation website. We will go through each of those categories, explain its use and give an overview of a widget from that category. However, if you are interested in a given category and want to explore its widgets be sure to check out Flutter's website.
As Flutter states on its website - these widgets are designed to “make your app accessible”. It is essential to ensure that your app is accessible to all users, including those with disabilities. If you would like to educate yourself a bit more on this subject we have a blog post about the Web Content Accessibility Guidelines (WCAG) - a set of guidelines and principles that should be followed to ensure that your product is accessible to users with various disabilities.
One of the widgets from this category is Semantics - a widget that annotates the widget tree with a description of the meaning of the widgets. In other words, it is a widget that describes what a piece of UI means.
In certain cases, some pieces of information displayed in your app may hold more significance than others. This is particularly important for tools such as screen readers or search engines. You can indicate that information by marking each widget with Semantics. With nearly 50 available properties, Semantics can be used to provide additional meaning for your UI.
source: Flutter documentation
Animation and Motion
By adding these widgets, you can introduce animation into other widgets within your app. Flutter offers a wide variety of animation widgets for both explicit and implicit animations. Implicit animations involve modifying a widget property's value, and Flutter handles animating it from the current value to the new value. On the other hand, explicit animations use a set of controls to instruct Flutter on how to quickly rebuild the widget tree while adjusting widget properties to produce animation effects. This method allows you to generate effects that are not possible using implicit animations.
AnimatedContainer is one of the widgets used to create implicit animations. It is the animated version of Container that gradually changes its values over a period of time. When building the widget you specify a particular attribute, like color. Then, when you rebuild it with a different value, the AnimatedContainer automatically animates the transition between the old and new values of properties. And of course, it's not just limited to colors. You can animate things like borders, border radii, background images, gradients, shadows, and more. The animation's length and effects can be adjusted using the curve and duration parameters.
Check out the interactive example provided by Flutter to see how the animation works when using this widget.
Assets, Images, and Icons
As you may have guessed, these widgets are responsible for handling assets such as display images and icon graphics. Flutter offers multiple ways to display images through the Image widget. The image can come from:
- Assets bundled with the app - to display the asset image with the appropriate pixel density for the device, use Image.asset and specify the asset's name. Image.asset automatically selects the suitable version of the image file based on the device's pixel density. You only need to include the different versions of the image and list them in pubspec.yaml.
- The network - Use Image.network and provide a URL. Flutter will download the image file, cache it and show it. It's important to note that network images may not load as quickly as asset images and also require the user to have an internet connection for the initial image retrieval.
- The user’s device - by using Image.file
- From memory - by using Image.memory
Regardless of the image source, you can customize its display properties, such as width and height. You can also specify how the image should fill the available space on the screen by selecting the appropriate fit, such as "contain", "cover", or "fill". Additionally, you can apply various color effects to the image using color and colorBlendMode. It’s good practice to provide a semanticLabel to your images to improve the accessibility of your app.
Flutter supports the following image formats: JPEG, PNG, GIF, Animated GIF, WebP, Animated WebP, BMP, and WBMP.
Async widgets provide asynchronous functionality within a Flutter application. One of them is StreamBuilder, a widget that builds itself based on the latest snapshot of interaction with a Stream (a way of receiving a sequence of events). The StreamBuilder widget listens to events flowing from a stream. Whenever a new event is received, it rebuilds the sentence, providing it with the latest event data to work with.
To use the StreamBuilder widget, you first need to specify the stream it will listen to. After that, you write the builder and give it a snapshot (declare what this part of your app should look like). You can provide initial data to display while waiting for the first event. If the snapshot doesn't contain any data yet, you can show a loading indicator. StreamBuilder can be used with various data sources, such as information retrieved from Firebase, sensor events, or network connection status updates.
These are the widgets that are necessary for building any Flutter application. We have already covered one of them - the Images widget. Another widget that belongs to this category is the Container widget. This widget is basically a “box” that you can put another widget into. In case you require a widget that demands some styling, such as size constraints or a background color, the Container widget comes in handy. Once you've “wrapped” your widget in a container widget you will be able to position and decorate it. If you don't specify any parameters for the widget, its appearance will remain unchanged. However, if, for example, you add a color parameter, the background color of the child widget will change to that color. The Container widget also comes with other properties that you can use, such as padding and margin (for adjusting the spacing), decoration (for changing the shape), and alignment (for aligning the child widget). Furthermore, you can implement transforms to your Container widget, such as rotation.
source: Flutter documentation
Cupertino (iOS-style widgets)
Cupertino is a set of widgets that are designed in accordance with the iOS design language. This collection includes a diverse selection of widgets, but in this example, we'll demonstrate the CupertinoAlertDialog widget, which essentially is an iOS-style alert dialog.
In certain situations, users may need to make important decisions when using your application. It may be necessary to notify a user about something or to request their input by using an alert dialog. This is where the CupertinoAlertDialog widget becomes useful. A basic dialog is a pop-up that includes some content and buttons. Positioned at the top of the dialog is a title. Below that there is content (typically text) and some buttons which prompt the users to take appropriate actions. With CupertinoAlertDialog, all these elements receive styling that matches the standard iOS design. To display a CupertinoAlertDialog, you can use the showCupertinoDialog helper method, which also provides an option for allowing users to dismiss the dialog by tapping outside of it.
source: Flutter Documentation
As the name of this category implies, input widgets are designed to obtain user input within your application. An example of an input widget is the Autocomplete widget. In cases where users need to write something in a text field, it may be more convenient for them to have a list of options to choose from instead of typing out the complete text. The Autocomplete widget helps with achieving that, leading to a more efficient and user-friendly experience in your application. Simply replace a text input widget with the Autocomplete widget and supply an optionsBuilder. Text entered by the user is received using the fieldViewBuilder parameter, and the options to be shown are generated using the optionsBuilder (which takes the latest text editing value property) and rendered using the optionsViewBuilder callback.
source: Flutter documentation
These are widgets that respond to touch events and navigate users to different views. Let’s say you would like to have a drag-and-drop functionality in your app, such as moving items from one location to another. You can use the Draggable widget to accomplish this. The Draggable widget shows a feedback widget when a drag gesture is detected. This feedback widget tracks the user's finger as they move it across the screen. When the user releases their finger while over a DragTarget widget, that widget is given the option to accept the data being carried by the Draggable widget. When the Draggable widget is “waiting”, you can specify its appearance using the child property. You have the possibility to use a childWhenDragging property to customize the widget’s appearance when it’s being dragged.
Once the Draggable widget is released and lands on a DragTarget widget, there are three ways that the target widget can handle the data:
- onWillAccept (called to determine whether the Draggable's data will be accepted by the DragTarget)
- onAccept (called when a valid Draggable widget is dropped on the DragTarget)
- onLeave (called when a Draggable widget is dragged over the DragTarget and then leaves)
As you may have noticed, Flutter offers a huge selection of widgets that are at your disposal when building an app. However, it is crucial to arrange these widgets properly on the screen to ensure a clean and tidy appearance. This is where Layout widgets come into play. One of the widgets that belong to this category is the Container widget, which we've previously discussed in this post. Another widget in this category is the Align widget.
In case you want to center a child widget within a parent widget, using the Center widget can be the best approach. However, if you intend to position it in a specific location, such as the upper left corner, you can use the Align widget to accomplish that. You can specify the location by using the alignment property - for example, you can set it to topLeft or even specify the exact alignment values for both axes, which range from -1 to 1. The Align widget can also be used to position widgets within a stack.
This is a set of widgets (including buttons, navigation, dialogs, and more) that follow the Material Design guidelines. Scaffold is the widget that implements the fundamental visual layout structure of Material Design. It provides APIs for displaying widgets like Drawers and BottomSheets.
A Drawer widget is a navigation panel that slides in horizontally from the edge of a Scaffold.
To use the Drawer widget you need to pass it as an argument to the Scaffold.drawer parameter. If the Scaffold includes an appBar, an IconButton that opens the drawer will automatically appear. The drawer will slide out from the left side of the screen. However, it is also possible to display a drawer on the right side by using the endDrawer parameter. Most commonly, a Drawer contains a ListView with a header and ListTiles, although it is possible to include any widget inside of this one. Closing an open drawer can be done by, for example, a swipe-to-close gesture or by using the Navigator.pop function.
source: Flutter documentation
Painting and effects
You can use this set of widgets if you want to add visual effects to their children without altering their layout, size, or position. As mentioned previously, Flutter allows you to incorporate images into your app, both as assets and through the network. However, what you may not be aware of is that Flutter also offers a widget that lets you modify these images by applying effects such as blurring or rotation. That widget is the BackdropFilter widget, which uses the ImageFilter and a child as parameters. To start out, choose the filter that you want to apply, such as "blur" or "matrix", and then provide a child widget. It's essential to keep in mind that only the widgets rendered beneath the child widget will be impacted by the filter; the child widget itself will not be affected. It is also possible to use this widget to apply a filter to only a section of an image.
These are a group of widgets that enable other widgets to be scrolled through. Given that we have already introduced the ListView widget when discussing the Drawer widget, we can delve deeper into this subject here, especially since ListView is the most commonly used scrolling widget. So what exactly does this widget allow you to do? In simple terms, it allows you to arrange a list of items into a scrollable list. Once you pass a list of items you have the option to make different adjustments. For instance, you can change the scrolling direction to horizontal or reverse the order or you even have the option to disable the scrolling of the list altogether.
By using this group of widgets, you can control the theme of your application, make it responsive to different screen sizes, and use padding. This not only enhances the visual appeal of your application but also results in an improved user experience.
Suppose your application contains many widgets placed beside each other, in that case, it becomes crucial to provide enough space between those elements. By making using the Padding widget, you can add some space around the sides of its child widgets, thereby providing the necessary breathing room. All you need to do is simply take the widget for which you want to create space and set it as the child of the Padding widget. After that use the padding property to specify the amount of space that you want to give it - EdgeInsets defines the space along the four cardinal directions - left, top, right, and bottom. EdgeInsets.all will put the same amount of padding around all of the sides of the child widget.
These are the widgets that let you display and style the text in your app. With the Text widget in Flutter, you can show a string of text in a single style. The RichText widget, on the other hand, allows you to present text that uses multiple styles. Simply provide it with a tree of TextSpans, and you can assign a separate style to each node within the text string. Apart from that, you also have the possibility to include tappable links by attaching gesture recognizers to TextSpans.
In this blog post, we shared some examples of different widgets that can be used when building an app in Flutter. However, this is only a fraction of the widgets that Flutter offers. There is a long list of widgets available, and we encourage you to discover them on your own to find the ones that best suit your project's needs. Are you interested in learning more about Flutter? Perhaps you're seeking an experienced team to help bring your idea to life? Whatever your requirements may be, feel free to reach out to us for assistance, and we'll do our best to answer any questions you may have.