Flutter: The Big Picture

Chathuranga Edirisinghe
Ascentic Technology
27 min readJun 24, 2022

In short, Flutter is a framework to build apps from a single code base. With the current version of Flutter, you can build apps for mobile, web, desktop, and even embedded devices with the same code base.

It has several points of strength

  • Flutter increases productivity. Not only can you use the same code base for Android, iOS, web, and desktop, but you can also leverage the hot reload feature, meaning that you can change your code while debugging and see the changes immediately without manually recompiling your code.
  • It’s fast as it uses. Skia for rendering, which is the same rendering library used by Chrome browser and Chrome OS, among others.
  • It uses ahead‑of‑time compilation to increase the speed while executing.
  • It’s a free and open source. It’s developed by Google and open to the community. It’s been created with the ease of developers and designers in mind, and there are many details that make it easy and pleasant to learn and use.
  • Flutter has pixel‑perfect replications of the iOS UI with the Cupertino widgets and Android’s UI with Material widgets. So, it’s easy for developers and designers bring a device‑specific experience to the users.

There are several great apps out there that were made with Flutter. For some apps, you’ll also find interesting stories about the projects and the development process, the challenges and solutions they found. One app in particular made by Alibaba is used by more than 50 million people. Google Ads run on Flutter, and you’ll find financial services, streaming services, productivity apps, and of course games.

But, more important is that whoever you talk to that has developed an app with Flutter will tell you that it took less time and was more straightforward doing it with Flutter, and that certainly includes me, and hopefully one day you as well. Okay, let’s have a look at what you need to start building apps with Flutter.

In order to start your Flutter adventure, you need a few tools

  • A PC or a Mac with a recent Windows, macOS, Linux or Chrome OS machine. To target iOS devices, you will need a Mac unless you use a third‑party service. For desktop devices, you need to use the same system you are targeting. If you want to create a Windows app, you’ll need Windows. If you want to create a macOS app, you’ll need a Mac. And the same for Linux or Chrome OS.
  • The Flutter SDK, you can download it at the flutter developers page. There all instructions they gave you how to setup in your environment.
  • If you want to develop for mobile, you will need to set up your environment. To try out your code, you should also have an Android or iOS device. Alternatively, you can install an emulator or simulator. They tend to take system resources, so if you are working on a slow machine, the physical device may be a better option.
  • The editor of your choice, the supported editors are Android Studio or IntelliJ IDEA, Visual Studio Code, and Emacs. Actually, you could use any text editor combined with the Flutter command line tools, but your life will be much easier if you use the plugins that are available for Visual Studio Code, Android Studio or IntelliJ IDEA as you get code completion and debug features and several other advantages.

When you develop for Flutter, you use a language called Dart. It’s now at version 2. It’s a strongly typed, object‑oriented programming language developed by Google. If you don’t know Dart, don’t worry. If you are familiar with C# or Java or Kotlin or Swift or TypeScript or even JavaScript, you’ll have no problems at all with Dart. You’ll see that it’s intuitive and easy to learn.

After having installed everything, the end result is that in your editor you have the Flutter project templates available. This is Visual Studio Code. In order to create a new Flutter app from the command palette, you can just type new flutter project, and after choosing a name and selecting the location.

The project with all the required files and templates will be created for you with a Hello World app ready to be tried and used. You can try it out immediately on an emulator or a physical device and see whether it’s working as expected. The code for this app is almost entirely contained in the main.dart file in the lib folder.

Something went wrong, you can use the flutter doctor command from the command line or from your editor. This will give you useful information about the state of your Flutter installation.

The complete setup starting from an empty machine might take roughly an hour, but this may vary drastically depending on the speed of your machine and your internet connection.

Overview of the architecture of a Flutter app

  • In particular, we’ll talk about widgets, which are the main building block of an app user interface in Flutter, and you’ll see a few examples of widgets.
  • We’ll introduce state, which will allow you to make apps interactive.
  • Next, you’ll see these concepts in action with two very basic examples of a Hello World app.
  • Finally, we’ll talk about the BLoC pattern, which may let you create reusable code by making clean and scalable apps.

Let’s get started

One of the concepts you’ll often hear when dealing with Flutter is that in Flutter, everything is a widget.

So, what is a widget?

A widget is the basic building block of the user interface in a Flutter app.

More precisely, each widget is an immutable declaration of part of the user interface. So, a text, a button or an image are widgets, but a font or a color scheme are also widgets, styles like padding that you use to create space between elements and theme are also widgets, layout elements like columns, rows, tables are widgets. Even MaterialApp, which is the container that you’ll most likely use for creating Material Design apps is a widget itself.

By the way, Material Design is a design language that, Google developed in 2014 based on materials like paper and ink, but with an implementation even more advanced than physical materials.

If you want to learn more about that, have a look at the material.io website. This is a rich website aimed at designers and developers full of examples and ideas that can be used for the web, iOS, Android, and of course your next great app in Flutter.

Flutter in particular has a library called material.dart that contains widgets that implement the material design principles. We’ll talk more about developing interfaces for iOS and Android later. But to sum it up, it’s absolutely okay to use Material Design on iOS devices and not only Android.

Let’s get back to the widget definition for a moment. The immutable part in the definition might be confusing at first, even misleading. If widgets are immutable, how can you interact with them? Well, not all widgets are created equal, and one of the first questions you’ll need to ask yourself when designing a widget is will this widget be static or dynamic?

Let’s say you want to put some text into your app. Will the text change or not? If the text is supposed to change, like in a text field asking your users some data and making some, action over it, you’ll create a stateful widget.

If the text never changes, like in the title of your app, you’ll create a stateless widget. Another example of a stateless widget may be an image containing your logo on the screen.

The only data the image needs is configured when the widget is created, and it will never change during its lifetime, so it may well be a stateless widget. To sum it up, you use a stateless widget when the part of the user interface you are describing does not depend on anything other than the configuration information of the object. What really changes in a stateful widget is not the widget itself, which by definition is immutable, but its state.

To put it simply, the state is the information attached to a widget that can change during the widget’s lifecycle. You may be used in other frameworks that completely separate layouts from the logic of the app. With a completely different language, like maybe XML, Flutter has a consistent, unified object model, the widget, and you write widgets in Dart like the business logic of your app.

So, there are no layout files in Flutter. This may be counterintuitive at first, but with time it becomes a consistent and friendly way of dealing with your layouts. The main advantage of this approach is that you can customize your widgets however you like far more easily than in other languages.

In Flutter, you build a custom widget by composing smaller widgets instead of extending them. If you need to create a button with a label, an icon, and an animation, you create your own widget that contains all of them. You can also add custom logic to your new component and reuse it easily in other apps. On the flip side, you do not have any drag‑and‑drop design in Android Studio or Visual Studio Code. At this time, you have to write the code of the layout yourself, even if the editors help you with that.

Actually, it’s now probably worth mentioning the Flutter Studio project.

It’s a web application accessible at the link you see on the screen. Its flutterstudio.app, Here, you can design your UI using drag and drop.

So for example, you could design a textbox, change its properties, and then copy the generated code to your favorite editor. If you’re a designer and don’t care much about coding or if you want to create a prototype very quickly, this could be an invaluable tool.

You can also try it on different devices, both iOS and Android, and you can even try your layout with different orientations.

It really is a very interesting project, and hopefully it will be maintained and developed further in the future.

Widgets

There are, of course, all kinds of widgets in Flutter.

Let’s see three of them

  • Layout widgets
  • Gestures
  • Animations.

Layout widgets generally contain other widgets. So you don’t really see them, but they have properties and features that you can use when dealing with their content. For a full list of them, have a look at the official documentation. As you can see, there are several layout widgets, but here introduce you to four layout widgets that you’ll probably use in most of your apps.

  • Row
  • Column
  • Stack
  • ListView

The row layout is a list of child widgets placed horizontally, and the column is a list of child widgets placed vertically. These are probably the simplest layout widgets, you’ll use in your apps.

When there are many widgets you want to show, more than fit the screen, you’ll want to use a ListView. When you use a ListView, the children will scroll automatically, and you can use it both horizontally and vertically.

A stack is a layout widget that positions its children relative to the edges of its box. So this is ideal when you want to overlay widgets on top of each other, but also when you want to decide exactly how to position an element inside another element.

There are widgets that put elements on your screen, like a button, or a text, or an image. There are widgets that deal with the layout, like rows, columns, ListView, and stacks. An important feature your mobile app will certainly have is dealing with gestures, and there’s one widget called GestureDetector.

As the name implies, a GestureDetector is a widget that detects gestures. Inside the GestureDetector, you can insert any other widget. It works like this. In the body of your layout, you insert a GestureDetector. This widget has properties that respond to gestures of your user.

In the document you can see a few examples of that

  • onTap
  • onDoubleTap
  • onLongPress

There are, of course, several others including vertical and horizontal drags. Inside each of those gesture properties, you can add your code to react to the event. It’s incredibly flexible and easy to implement.

Another of the defining features of Flutter is probably how fast you can create great animations.

In Flutter, you can use two kinds of animations

  • Tween animations
  • Physics-based animations.

Tween is the short for in betweening. In a tween animation, you define the beginning and ending points, the timeline, and the curve the defines the timing and speed of the transition.

Flutter will calculate automatically how to transition from the beginning to the end of your animation. And this is the easiest way of creating an animation.

In physics-based animation, motion is modeled to resemble real-world behavior. An example of this can be flipping a coin, or making an object fall down to the ground. Its speed will depend on its weight and the distance from the ground. Physics-based animations are governed by physics laws and forces. This is an extremely powerful tool that was added to Flutter to create realistic compelling advanced animations.

To sum up what we’ve seen so far, from an architectural point of view, every UI element in Flutter is a widget. You compose widgets to create rich and complex UIs, and this is called the widget tree.

All widgets are immutable, so if you have to make changes to the information attached to the UI, you interact with the state of a widget. When the state changes, the widget is rebuilt.

There is a useful tool called Widget Inspector that shows the widget tree of your user interface. It also has a great feature. When you select any widget from your device, the inspector will automatically recognize it, showing its properties, ancestors, and descendants. So, as you might guess from these concepts, the actual code that you write for your Flutter apps to make them interactive and, well, useful, your business logic in other words, is dealing with the state.

Of course, you can create your own classes that have nothing to do with the UI, for example a class that reads and writes data from a database or from a web service. But at some point you’ll need to present the results of your logic to the user interface, and so at some point you’ll need to interact with the state of your widgets. So, you’ve seen that you design the UI through widgets in Flutter and make widgets interactive with state. Let’s see how you can do all.

We have introduced several concepts so far, so let’s have a look at some code to make it a bit clearer.

So here we won’t go into many details with the code. It’s to give you an example of the concepts we’ve discussed so far. The examples will be extremely basic.

I’ve created an app in Flutter, following the process we have seen in the previous , using Visual Studio Code and an iOS emulator, but of course, you can use any other configuration we’ve discussed.

In the main.dart file, I have changed the content with the code you see on the attached screen shot. This is probably the simplest Flutter app we can make right now.

Let’s have a look at the result first on an iOS emulator, and then we’ll get to the code.

So, we have a white screen and in the center there’s a text, Hello. Very creative of course. Then there’s an app bar that contains another text, App Bar Title.

Okay, as simple as it is, it still looks like an app, right? So let’s get to the code.

import 'package:flutter/material.dart';

The first line imports the material.dart library that we mentioned previously. You might remember that this contains several widgets that follow the Material Design pattern.

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

Then we have the entry point of every Flutter app, which is the main method. In here, we are calling a class called MyApp, which we define here. This is a StatelessWidget. Every stateless widget has a build method that returns a widget. Here, we are returning a MaterialApp, which is what you’ll likely do for most, if not all, your apps.

Remember, MaterialApp is also a widget. This widget has some properties, for example, title, which is the title of the app.

return Scaffold(appBar: AppBar(title: const Text("Hello"),),body: const Center(child: Text("Hello"),),);

Here we call another widget called Scaffold. The Scaffold has an AppBar widget, the blue bar we see on our app, and the AppBar has a title property that contains a Text widget whose content is App Bar Title.

The Scaffold also has a body property that contains a layout widget called Center that centers its content, both horizontally and vertically, and as its child property, it has another text widget whose content is Hello.

So you see, composing the widgets in a hierarchical order makes the UI of your app.

Now showing off the hot reload feature. Let’s change the text in the center widget to HOT RELOAD, and you see that the app responds immediately.

Now, we’ve seen before that this is a StatelessWidget, so we cannot change anything here after the first configuration.

Let’s have a look at something a bit more interactive. Here we’ll use the state that, as you remember, is the information attached to a widget that can change during the widget lifecycle.

So in this second version of the Hello World app, there’s a text field. Here, you can write something, your name for instance, and below the text field widget there’s some text. In the text, this incredibly useless app will say Hello, then concatenate your name transformed into uppercase, and then it will even put an exclamation mark after your name. As you can guess, the interesting part is not the app itself, but the fact that the text changes.

And as all widgets are immutable, the only explanation is that we are dealing with a state of the widgets here.

Let’s briefly see how with the code. The app is the same as before, but in the body of the Scaffold, instead of putting the text, we are now calling a HelloText object.

class HelloText extends StatefulWidget {const HelloText({Key? key}) : super(key: key);@overrideState<HelloText> createState() => _HelloTextState();}class _HelloTextState extends State<HelloText> {String helloText = "";@overrideWidget build(BuildContext context) {return Column(children: [TextField(onChanged: (text) => sayHello(text),controller: myController,),Text(helloText)],);}void sayHello(String text) {setState(() {helloText = "Hello " + text.toUpperCase() + "!";});}final myController = TextEditingController();}

HelloText is a class that extends a StatefulWidget. StatefulWidgets have the state, and here we are calling the createState method to return HelloState, which is defined below. HelloState extends a state of HelloText, and as a UI, we are building a column that contains the TextField, and below it, the text.

Note that in the HelloState class, we have define a helloText string that will contain the information that changes during the lifetime of the HelloText widget.

void sayHello(String text) {setState(() {helloText = "Hello " + text.toUpperCase() + "!";});}

Now, here comes the interesting part. When you type something in the TextField, this is the onChanged property, we call a function that’s called sayHello, and we pass the text to the function. This function, sayHello, then changes the state, calling the setState method and concatenating hello and the text that was passed and an exclamation mark.

The widget then gets rethrown. So to sum this up, HelloText is a stateful widget that has a state called HelloState.

return Column(children: [TextField(onChanged: (text) => sayHello(text),controller: myController,),Text(helloText)],);

In the HelloState class, we build the layout that is a column that contains two children widgets, the TextField and the Text. When the content of the TextField changes, the setState method is called to update the UI. So, this is the first method to write your logic. In this case, the sayHello method in Flutter, and this is done in the same class as the UI. While this is a simple and effective approach, I recommend you only use it with small apps and prototypes because it has some pitfalls. Let’s see what they are and a possible approach to solve them.

You’ve seen that using the setState method makes your apps interactive, but this is not necessarily the best approach unless your apps are very simple.

There are a few reasons for that.

First, and most important, you would put at least part of the logic of your app in the same class as your layout. And, generally speaking, it is never a good idea to mix layout and code, both for the risk of writing spaghetti code and because it makes it difficult to maintain and reuse the same code in different apps.

Second, if you have data that changes in your app and you need to update several widgets in different places, you also risk unnecessarily duplicating your code.

You have several other ways to write your business logic in Flutter.

The one that mention here is the BLoC pattern that stands for business logic component. That’s because it’s officially supported by Google.

BLoCs are based on streams, stream controllers, and sinks. Okay, a lot of concepts here. Let’s see what all this means. The main building part of a BLoC, or business logic component, is a stream.

You could think of a stream as a pipe. The pipe has two ends, one allows you to insert data into it and the other one is where data gets out. It’s a one‑way pipe.

When you insert something into the pipe, it flows inside the pipe and goes out by the other end. In Flutter, the pipe is called a stream.

To control the stream, you use a StreamController.

The way in into the stream is the sink property of the StreamController.

The way out of the stream is the stream property of the StreamController.

In order to use the stream and be notified when something gets out of it, you need to listen to the stream, which in this case is not music, but data. So you define a listener with a StreamSubscription object.

The StreamSubscription gets notified every time an event related to the stream is triggered, for example whenever some data flows out of the stream or when there is an error. You can also transform the data inside the stream through an object called *StreamTransformer, for example to filter or modify the data.

Okay, now we have enough elements to talk about the BLoC pattern.

This was introduced in January 2018 at the Dart Conference.

In short, the business logic of your app should be moved to BLoCs, and therefore be removed from the UI.

It should rely on the use of streams for input with sink and output with stream. It should remain platform and environment independent. To sum this up, BLoCs are components that contain the business logic of your app.

Use sinks to take events from widgets and streams to output the results to the widgets. What happens inside the BLoC is independent from the UI. Ideally with this pattern, you can scale your Flutter apps, reuse code and test them more easily.

If you have some experience in programming, you are already familiar with null exceptions in your code.

These are tricky errors because they only happen at runtime and only when specific conditions are met. Another way Flutter makes developers more productive is by enforcing null safety.

In a nutshell, null safety means that by default variables cannot be assigned a null value. And the same is true for function parameters or class fields.

Let me show you an example of that. you see DartPad attached image.

It is a tool that lets you play with Dart in your browser, and it’s perfect when you want to try out some Dart syntax without creating a new project or edit the code in an existing one. You can find it at dartpad.dev.

int doubleNumber(int oldNumber) => oldNumber*2;

In the example you see on the screen, there is a method called doubleNumber that takes an integer as a parameter and multiplies it by 2. In the main method, we declare an integer called myNumber and then we call the doubleNumber method, passing myNumber. I guess you already see the problem here, don’t you? Wen we run this code as expected we get a type error because you cannot multiply a null value.

And as you can see, now the code won’t even run as DartPad tells us that we must give a value to myNumber before using it.

So, let’s give it a value of 21 and then let’s run the code again.

Now, our code works and we get 42 as a result. You see how much time you can save enforcing little safety. If your code is not null safe, it won’t even compile. In this way, Dart and Flutter help you write cleaner and safer code in your apps.

Basic Flutter Tools

Here , I’ll be using Visual Studio Code on a mac machine, but everything you’ll see is almost identical on a Windows or on a Linux machine.

Let’s begin with a basic Flutter app.

We’ll just create a new Flutter app.

And after everything is set up, we’ll be able to see it on an emulator that’s been already started.

This is the basic app we’ve already seen in a previous slides. There’s not much to debug here, but let’s see the process anyway.

Probably the single most important tool to debug an app is being able to step into the code you have written, and to do that, you use breakpoints. In order to put a breakpoint, you can click at the left of the line where you want to interrupt your code.

And now, when we press the plus button in our app, the execution stops at the breakpoint we set.

This is extremely useful as you can check what’s happening during the execution of your app.

In the Variables pane, you can see the values of all the variables that are in scope.

So for example, you can see that the _counter variable now equals to 0.

Here you have the option to step into the selected line and see what happens after we step over the counter++ instruction where our _counter variable is now equal to 1.

A feature I love is the ability to change the code and see the results in real time during debug.

For example, let’s change the _counter increment command to _counter+=2. So, we can press the Hot Reload button and remove the breakpoint, and now each time we press the plus button, the number increment will be two instead of one.

Okay, let’s say we want to add a few widgets. You’ve seen in previous modules that you can just type the code and add widgets to the screen, but there’s a faster way called snippets.

For example, if you want to create a stateless widget, you can just type “stles”, and as you can see, the editor creates all the structure and the code of a stateless widget.

You can create stateless widgets, stateful widgets, and animations.

Another great tool you can use on Visual Studio Code are assists.

Let’s see an example. Let’s say that we want to put a widget into a center widget. In order to do that, we can just put the cursor on the widget we want to modify.

A light bulb appears, and if you click on that, the assist will show up. Now you can see that there are a number of actions you can choose from. If you want to include this widget into a Center widget, you can just choose the action to do so.

An alternative to call the assist instead of clicking on the light bulb is pressing Ctrl+period or Command+period on a Mac. Very similar to assists are quick fixes.

They work exactly in the same way, but they are used when there is an error into your code, and the editor helps you fix your errors.

And by the way, if you want to view all your code problems, you can just select View, Problems, or Ctrl+Shift+M, or Command+Shift+M on a Mac.

An issue that can be seen while developing is shown in the Problems pane.

There are also other advanced debugging techniques that you can use for your more complex apps. If you want to learn more about those, have a look at the flutter documentation.

The last tool I’d like to show you is automatic formatting. To format the code in the current code window, you can just right-click and select Format Document.

It is also possible to automatically format the code whenever you save a file. In order to do that, we can change the Visual Studio Code settings by adding the Editor: Format On Save property and setting it to true.

Great! Now that you have an idea on how Visual Studio Code helps you with Flutter.

let’s see how to use packages in a Flutter app.

We don’t always need to reinvent the wheel, and what may influence the decision to use one framework over another is how many tools and libraries are available for the most common and also some uncommon features your software will build upon.

The approach the Flutter developers chose to make the language complete are packages.

According to the official Flutter website, Flutter supports using shared packages contributed by other developers to the Flutter and Dart ecosystems.

Basically, packages are libraries you can import into your own projects to speed some of the features you want to include in your app.

There are packages to deal with the device pictures, like image picker, packages for network recasts, like HTTP, packages for databases, like SQLite, to play videos, like video player, to control the camera of your device, like camera.

The list could go on and on, but you get the idea. This is a very flexible approach. Actually, you could be the author of the next great package in Flutter.

There’s a website called pub.dev that contains an extensive list of packages that can be searched and ordered. What’s also great is that these packages are checked, analysed, and rated for factors like health, popularity, and maintenance.

Let’s say, for example, that you want to include a database into your app. In the pub.dev website.

If you search database, you get a list of results with a number of likes, the pub points, which is a rating system where the highest score is 130, and the popularity.

You can also check which platforms are supported by the package.

And other useful information you find is whether the package supports null safety.

If you click on one of the packages, let’s say sembast, you get to the main package page.

Here, you can find a lot of information, examples, use cases, and documentation.

In the Installing page, you have information on how to include this package into your project.

The process is basically the same for every package, and it is rather straightforward. So once you follow the required steps for one package, you’ll be able to do it for any other. In the Versions page, you get the list of the updates of the library.

To sum it up, packages are another tool that can make working with Flutter a real pleasure. And there’s one package particularly useful if you want to support languages other than English. Let’s talk about internationalizations, next.

By default, Flutter only provides US English localisation, but you might want to add other languages and locales for dates, currency or measures. Fortunately, there’s a package called Flutter_localizations that, at the time of this recording, supports 78 languages.

But let’s have a look at the main steps required to internationalise your app.

There’s a Locale class used to identify the user’s language. When you build your app, you can choose which locales you want to support. When you build an internationalised app, your app will respond by displaying values that are locale‑specific.

For example, if you have an internationalised text widget, an English user might see Hello on the screen, but an Italian user would see Ciao, and a Spanish one, Hola.

The main steps to achieve these results are shown below.

First, you add the localisation dependencies. In particular, you need to add the Flutter_localizations package to the pubspec.yaml configuration file in your project.

Then, you create the app Localization class that will have all the localization helpers to use in the whole app.

Then, you create the string translations. The translations are made using application resource bundle files, which have an .arb extension. Each ARB file contains a single JSON table that maps from resource IDs to localized values.

To finalize the localization, we have to say to our app to use the AppLocalizationsDelegate class as the app Localization class.

You can see an example of two ARB files, one for English and one for Italian. As you can see, they are just JSON files. When you need to support other languages, you just need to add the new language in your configuration and add the ARB file to your project. This is an extremely flexible way of adding support to different languages into your app.

While most Flutter apps target mobile platforms, it’s also very easy to create and publish web and desktop apps.

For this example, I’ll be using the default app that you get when you create a new Flutter project.

Let’s begin with the web. You can target the web through the command line interface or from your editor. So, from your terminal, you can just type flutter build web.

This will make your code compile to JavaScript. It will also be minified for use in production. You’ll find an index.html file in the build\web folder of your project once you build the web.

You can run it immediately to see how it looks. Using flutter run -d chrome command

I’ll do it with Visual Studio Code, but you can also run it from any other editor or from the command line.

And here it is. The demo app is working perfectly on a browser.

Most Flutter developers recommend using Flutter for the web when you want to build single‑page applications or progressive web applications or when you need to port mobile apps to the web.

I would not recommend Flutter for static, text‑based HTML content, but, of course, Flutter fully supports this scenario as well. Once you build your Flutter app for the web, you can deploy it to any web server. The procedure is quite similar for desktop apps.

Before running your app on a desktop, you have to enable your platform first. Here, I’m using macos, but, of course, you can deploy an app for a Windows or Linux as well.

From the terminal, you can type

flutter config ‑‑enable‑macos‑desktop

Once the platform is enabled, you may need to restart your editor, then you can run the app targeting your desktop system. So, let’s select macos as target and run the app or you can run.

flutter run -d macos

And as you can see, you have a fully functional desktop app. That’s the power of Flutter.

Conclusion

As you can see, Flutter is one of the most innovative mobile technologies on the market right now. For businesses looking to create applications on both iOS and Android, Flutter is a great option. If you are seeking apps with amazing UI and high performance — Flutter is the best option as well.

--

--