Flutter Tutorial for Developers: Step-by-Step Guide to Building Apps
Flutter Tutorial for Developers: Step-by-Step Guide to Building Apps
In this article we discuss everything you need to get started creating applications with Flutter, including basic architecture, widgets, and testing.
Join the DZone community and get the full member experience.Join For Free
Since it's much-awaited launch, Flutter has caught a lot of attention, and we're excited about it too! I'm hoping that a massive chunk of non-game apps will transition to Flutter, and in anticipation, we are therefore training our team on it as well.
There are new, but few, resources scattered over the internet to learn Flutter. We've compiled our Flutter tutorial to get developers off their feet and start developing apps for Flutter.
In this Flutter guide for beginners, we will cover:
- Flutter: What, How, and Why?
- Setting up Flutter.
- Dart Basics.
- Flutter Basics.
- Interactive Widgets.
- Designing an app: Forms, Gestures, and Images.
- Lists and Navigation.
- JSON and Serialization.
- Dependency Management.
- State Management.
- Testing (Unit and Integration).
You may also like: Flutter: What All the Fuss Is About
Flutter: What, How, and Why?
What is Flutter, and how is it different? Just remember this, Flutter was built to work for any device with a screen and works with:
- iOS and Android.
- Web and Desktop (Mac, Windows, and Ubuntu) - Even support PWA.
- Raspberry Pi (POC stage).
Check out this video from Google; it's a great place to get a grasp - comparing Native Development, Hybrid App Development, React Native Development, and finally, Flutter App Development.
Setting Up Flutter
Flutter is relatively straightforward to set up and depending on what OS you're using; you can check out the steps in this official Flutter tutorial: https://flutter.dev/docs/get-started/install.
But in case, you do run into something, check out common issues with getting started on Flutter's Github.
The reason we ask that you set up Flutter before Dart is because when you install Flutter, you install Dart too. While you can separately install Dart, it would be an unnecessary step. Flutter will decide which Dart version will be used, so installing different a version of Dart will be unnecessary as well.
Once you've downloaded and unzipped Flutter, you should see something like this when you run the flutter command in your terminal:
If you're new to mobile development in general, you will need to download Xcode and Android Studio (and toolchain), as well. Once you've set up Flutter, scaffolding a new project can be done in just one command.
Flutter and Chrome use the same rendering engine, SKIA. Instead of interacting with native APIs, it controls every pixel on the screen, which gives it the much necessary freedom from the legacy baggage as well as the performance it has.
P.S. You can follow up with dart updates on their medium account.
If you want additional practice once you have an overview, head over to http://jpryan.me/dartbyexample/ and do all the examples religiously.
Practice, Practice, Practice!
Edit your code on DartPad for starters and get a better grip. I'm sure you'll be up and running in no time!
After, you're done, head over to exercism, and complete their Dart track. It's trendy, so in case it's full, you can do the practice track too.
Now that you're familiar with Dart, it's finally time to move on to Flutter
Let's start with the technical overview here.
And scaffold a new flutter app with:
flutter create app_name
And you should see something like this:
Open the project on Android Studio, download the emulator and an Android version if not done already, and run the project — and voila!
Understand as to how should you structure your project directory and understand which files are meant for which purpose.
Now that you've set up Flutter, it's time to do what all developers do, use other's code :) — what I meant is to set up the package file: pubspec, written in YAML.
Remember - Everything's a widget in Flutter
If you've not read the technical overview as we asked you before, go back and read it :). You will get a fair idea of what widgets are. Widgets come in two flavors: stateless and stateful.
Stateless Widgets are those whose state doesn't change, like a button or an image. As the name states, it doesn't change its state when an action is performed on the screen.
Check out the short video series, and its documentation by Google to explore them in-depth. (I'm attaching the first video in the series.)
When a widget needs to hold some state like a current page in PageView, the currently selected tab in a BottomNavigationBar, Stateful widgets are the right choice to make. StatefulWidgets can hold the current state of a Widget. Instead of a widget build method, a Stateful widget has a State build method, which gets called each time we explicitly call
Similarly, check out the documentation (it has the video inside) for the stateful widgets.
Flutter 1.9 was released at GDD China with a host of new features and a mark that the community is multiplying.
Layouts in Flutter
As we discussed earlier, everything is a widget in Flutter, including layout models. (Check out the documentation.)
Widgets, such as the rows, columns, and grids are layout widgets (which we don't see on screen) that help developers to arrange, constrain, and align other, visible widgets.
And, Some More Widgets!
If your app follows material design guidelines, Flutter has a lot to cover by default. Flutter provides several widgets that support Material Design. It includes widgets such as MaterialApp, AppBar, Scaffold, etc.
So far, we have seen Widgets that display information on-screen or arrange other widgets. For the real app, it is equally essential to make the app interactive and get user's input in various forms like gesture, taps, etc.
To achieve this, Flutter has numbers of StatefullWidgets, such as Checkbox, Radio, Slider, InkWell, Form, and TextField. These widgets are capable of maintaining their state (e.g., text we are entering in TextField, whether a CheckList is checked or not.)
Go and check out this example to add Favorites/Non-Favorites functionality to your app. Now, you must be curious about what are all widgets available in Flutter? Here is a Widget Catalog. Check all the Widgets that make Flutter development relaxed and fun.
And here we go, It's time to learn Flutter. I mean apps that have multiple screens, images, network dependencies, and all.
So, Let's begin.
Designing an App
Check the below app illustration.
This simple looking app has these features:
- Navigation Drawer: https://flutter.dev/docs/cookbook/design/drawer.
- SnackBar: https://flutter.dev/docs/cookbook/design/snackbars.
- Custom Fonts (A Text has its own Style): https://flutter.dev/docs/cookbook/design/package-fonts.
- A text-based on Orientation (Bigger fonts in Landscape): https://flutter.dev/docs/cookbook/design/orientation.
- And, multiple tabs: https://flutter.dev/docs/cookbook/design/tabs.
Note: OrientationBuilder is independent of the device's orientation. Instead, it calculates the current Orientation by comparing the width and height available to the parent widget. To determine the device's orientation you can refer to MediaQuery.of(context).orientation
Flutter has a Form widget that helps to build a form that efficiently manages the essential requirement of a Form, e.g., State of a Form, Validation, etc. Check out the complete guild in the documentation.
To get the user inputs and some time to make the app super interactive, we maximize the use of Gestures. Flutter has pre-built widgets to cover this.
- Adding Material Ripple Effect: https://flutter.dev/docs/cookbook/gestures/ripples.
- Handle Taps: https://flutter.dev/docs/cookbook/gestures/handling-taps.
- Swipe to Dismiss: https://flutter.dev/docs/cookbook/gestures/dismissible.
To make apps beautiful and engaging, we use images. Flutter provides an Image widget to display an image in the Flutter app from various sources.
1. Display Images from Network: https://flutter.dev/docs/cookbook/images/network-image.
2. Display Image with Placeholder and with Fade-in Animation: https://flutter.dev/docs/cookbook/images/fading-in-images.
3. Sometimes, it's handy to load images from the network and cache it in local storage to make it quickly available next time: https://flutter.dev/docs/cookbook/images/cached-images.
Showing More Data Using List
To accommodate more data, we use a list to show them. The list can be horizontally or linearly.
1. Create a grid list: https://flutter.dev/docs/cookbook/lists/grid-lists.
2. Create a list horizontally: https://flutter.dev/docs/cookbook/lists/horizontal-list.
3. The list can have different types of Item (e.g., a header and items to it). Check the following link to see how you can cover such cases in ListView: https://flutter.dev/docs/cookbook/lists/mixed-list
4. Floating app bar and Nested scrolling using SliverList: https://flutter.dev/docs/cookbook/lists/floating-app-bar
5. Sometimes, we have predefined arbitrary items to be placed in a List (e.g., Setting categories). In ListView, you can pass custom items (in the form of Widgets) to its children: https://flutter.dev/docs/cookbook/lists/basic-list.
6. Sometimes, a List has more items then the viewport of a screen. In such cases, it makes no sense to build all the items at once. Flutter has a
ListView.Builder that uses the lazy rendering approach to create list items efficiently: https://flutter.dev/docs/cookbook/lists/long-lists.
If you have more items in a list and looking to paginate them. Here is a good article that we've written: https://blog.solutelabs.com/paginate-your-data-in-flutter-7744995febd1
Navigating Between Screens (Routes)
Most apps contain multiple screens to display data in a well-organized manner. In Flutter, we can do navigation-related operations using Navigator.
Check the following diagram to understand how Flutter manages multiple routes. Later, we will discuss how to navigate up and forth between them.
1. Navigate to a new screen and back: https://flutter.dev/docs/cookbook/navigation/navigation-basics
2. Pass data to new screens and retrieve results.
So far, what we have seen is suitable for small projects. But when the project grows, we want to manage all routes at a single place. Also, we might need to address below questions
1. How many routes we have?
2. How to initialize each route?
3. What data is required by each route? etc..
3. To manage all this efficiently, Flutter has named routes: https://flutter.dev/docs/cookbook/navigation/named-routes.
4. Pass arguments in named routes: https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments.
And, what about this animation while navigating to a new screen?
Most apps we come across nowadays, are generally connected with a third party server and make requests to the server to fetch or post data.
In Flutter, we can use HTTP as a third party pub to do this: https://pub.dev/packages/http.
1. Fetch Data from a network: https://flutter.dev/docs/cookbook/networking/fetch-data.
2. Make authenticated requests: https://flutter.dev/docs/cookbook/networking/authenticated-requests.
3. Work with web sockets: https://flutter.dev/docs/cookbook/networking/web-sockets.
Flutter has a few more pubs available. Don't forget to take a look at the below pubs.
Using JSON and Serialization
In Flutter, we generally have two strategies for JSON serialization. Manual parsing and automated serialization using code generation.
Check out the full guide with both strategies here.
For manual parsing, don't forget to check out this online tool to auto-generate boilerplate for the model class: https://app.quicktype.io/.
Sometimes we need to persist data in local memory to quickly available whenever we need them.
1. If you have a relatively small amount of data to be stored in a key-value pair. Consider using shared-preferences. Here is a detailed guide to achieving the same using Flutter.
2. You can also read and write files on disk: https://flutter.dev/docs/cookbook/persistence/reading-writing-files
3. If an app needs to persist a large amount of data and also it requires to query them. It is advised to use an SQLite database
Flutter app can use the SQLite database via sqflite pub: https://flutter.dev/docs/cookbook/persistence/sqlite
For easy to use, reactive persistence, check out below pub. Moor is a wrapper around sqflite.
We use so many pubs in the app. It's a great way to work collectively and share code across apps without having to develop everything from scratch.
You can find all the useful packages from here: https://pub.dev/
With multiple pubs, you might faces issues like conflicts in the version resolving. You can find all the best practices here to be followed while using pubs: https://flutter.dev/docs/development/packages-and-plugins/using-packages
And, with all this, you now have completed Flutter cookbook! :)An Art of State Management
In a typical app, it is a common use-case that a change made at Point-A reflects some changes at Point-B. That is called State management. It can also be understood by the below illustration.
Flutter has multiple approaches that can efficiently manage the State of the app. Based on project size we can decide the appropriate techniques. Here, we will discuss a few of the possible techniques for State management:
2. Inherited Widget
Check out the following video to understand what Inherited Widgets are.
Also, check out the complete list of articles here: https://flutter.dev/docs/development/data-and-backend/state-mgmt/options.
Navigator.of(context); you used earlier? That is using the same Inherited Widget concept to access data down in the widget tree.
3. The Provider Package
The provider is a mixture of DI (dependency injection) and State management built with widgets for widgets. Official documentation of provider is too good to understand it in depth: https://pub.dev/documentation/provider/latest/.
4. BLoC Pattern
BLoC is a simple, lightweight, and highly testable, predictable state management library for Dart: https://bloclibrary.dev/.
I also found this good video series explaining BLoC pattern (with accompanying article series).
When the app grows, it becomes hard to test every feature. In such cases, automation testing is the way to go. It helps ensure that the app performs as expected before we release it. And so, we don’t fail in such situations ;).
Automation testing falls under three categories
- Unit tests test a single function, method, or class.
- A widget test (in other UI frameworks referred to as component test) tests a single widget.
- An integration test tests a complete app or a large part of an app.
Check out the introduction to testing in Flutter here: https://flutter.dev/docs/testing.
The goal of unit testing is to test a particular unit of code with stub/mock dependencies. Verify the code works as expected in different scenarios. A unit test is very fast and doesn’t require an actual device to execute.
While doing Unit tests, any dependent classes should be injectable, so that we can inject a mock or fake implementation of dependancy and verify if everything working as expected. Flutter has a mockito framework that helps to create a mock or fake implementation.
Widget Testing (in Flutter) is a UI testing technique. The goal of widget testing is to test if particular Widget UI looks as expected, and it’s interactive. Widget testing doesn’t require a physical device. We could also test the properties of Widget, like Color, Size, Font Family, etc.
We can also perform user events like tap, gestures, entering text, etc. Check out more details here: https://flutter.dev/docs/cookbook/testing/widget/introduction
Integration test work in a pair. The goal here is to test how multiple units work together. Integration testing happens on a real device or emulators. We can fire a series of User interaction events and expect UI rendering or unit codes to be executed properly.
Again, Check this Video series for detailed implementation of real App with TDD.
BDD: Behavior-driven development
TDD or Unit Tests helps when a stakeholder has strong technical skills. BDD is all about writing a test case from the end user’s perspective. This is written in a natural English language.
Testcases can be written in the below format:
Given: The initial context at the beginning of the scenario, in one or more clauses;
When: The event that triggers the scenario;
Then: The expected outcome, in one or more clauses.
Internally, a behavior test cases can be a Unit test, widget test, or a combination of both.
BDD helps to understand software functionality from an end-user perspective and becomes a sort of functional documentation.
Flutter has a that helps us writing Behaviour Test cases.
This guide covers all the basics that you would need to know to start with flutter and develop your apps! I hope this helps you on your journey to flutter.
Published at DZone with permission of Karan Shah . See the original article here.
Opinions expressed by DZone contributors are their own.