Chapter 1. Meet Flutter

This chapter covers

  • What is Flutter?
  • What is Dart?
  • Why does Flutter use Dart?
  • When is Flutter the right tool (or the wrong tool)?
  • A brief intro to how Flutter works

Flutter is a mobile SDK, built and open sourced by Google; and at its core, it’s about empowering everyone to build beautiful mobile apps. Whether you come from the world of web development or native mobile development, Flutter makes it easier than ever to create mobile apps in a familiar, simplified way. Flutter is special in that it makes it truly possible to “write once, and deploy everywhere.” As of this writing, Flutter apps will deploy to Android, iOS, and ChromeOS. In the near future, Flutter apps will also run as web apps and desktop apps on all major operating systems.

In short, Flutter is a truly complete SDK for creating applications. It’s a platform that provides everything you need to build applications: rendering engine, UI components, testing frameworks, tooling, router, and many more features. The consequence is that you get to focus on the interesting problems in your app. You can focus specifically on the domain functionality, and everything else is taken care of. The value that Flutter provides is astonishing.

In fact, that’s how I found myself here, writing this book. I had to learn Flutter because of my job, and I loved it from the moment I started. I effectively became a mobile developer overnight, because Flutter felt so familiar to my web development background. (The Flutter team has said that they were influenced by ReactJS.)

Flutter isn’t only about being easy, though. It’s also about control. You can build exceptional mobile apps using Flutter with a shallow knowledge of the framework. But you can also create incredible and unique features, if you so choose, because Flutter exposes everything to the developer.

This is a book about writing a (relatively) small amount of code and getting back a fully featured mobile app that works on iOS and Android. In the grand scheme, mobile app development is new. It can be a pain point for developers and companies alike. But I believe Flutter has changed that (and that’s a hill I’m willing to die on).

This books has one goal: to turn you into a (happy) Flutter (and Dart) developer.

1.1. Why does Flutter use Dart?

Flutter apps are written in the programming language called Dart. I’ll describe Dart in depth throughout the book, but for now, just know that all the code you write in a Flutter app is Dart code. In fact, to us, the mobile developers, Flutter appears to be nothing more than a Dart library.

Dart is also owned and maintained by Google. This may give you pause. There are reasons to be skeptical of this choice: it’s not one of the hot languages of today, few companies use it in production, and the community must be small. What gives? Is Google just using it because it’s Google’s language? I imagine that played a role, but there are practical reasons, too:

  • Dart supports both just-in-time (JIT) compiling and ahead-of-time (AOT) compiling:

    • The AOT compiler changes Dart into efficient native code. This makes Flutter fast (a win for the user and the developer), but it also means that (nearly) the entire framework is written in Dart. For you, the developer, that means you can customize almost everything.
    • Dart’s optional JIT compiling allows hot reloading to exist. Fast development and iteration is a key to the joy of using Flutter.
  • Dart is object-oriented. This makes it easy to write visual user experiences with Dart, with no need for a markup language.
  • Dart is a productive, predictable language. It’s easy to learn, and it feels familiar. Whether you come from a dynamic language or a static language, you can get up and running with ease.

And I think Google owning Dart is an advantage. In the last few years, Dart has made great strides to be a nice language specifically for writing modern UIs. The type system and object orientation make it easy to reason about writing reusable components for the UI. And Dart includes a few functional programming features that make it easier to turn your data into pieces of UI. Finally, asynchronous, stream-based programming features are first-class citizens in Dart. These features are used heavily in reactive programming, which is the paradigm of today.

Lastly, Dart excels at being a language that’s easy to learn. As a coworker of mine said about hiring, “We don’t have to find Dart people, only smart people.”

1.2. On Dart

Besides explaining Flutter in depth, I will also introduce the basics of Dart. Dart is a programming language. And programming languages can be, as it turns out, hard to learn. The fundamentals of Dart are similar to all higher-level languages. You’ll find familiarity in Dart syntax if you’re coming from JavaScript, Java, or any other C-like language. You’ll feel comfortable with Dart’s object-oriented design if you’re coming from Ruby or Python.

Like all languages, though, the devil is in the details (and, as they say, doubly in the bubbly). The joys of Dart and the complexity of writing good Dart code lie not in the syntax, but in the pragmatics.

There’s good news, though. Dart excels at being a “safe” language to learn. Google didn’t set out to create anything innovative with Dart. Google wanted to make a language that was simple and productive and that could be compiled into JavaScript. What Google came up with works well for writing UIs.

The fact that Flutter can compile to JavaScript is less relevant for Flutter development, but it has had interesting consequences for the language. Originally, Dart was created as a language for web development. The stretch goal was to include a Dart runtime in the browser, as an alternative to JavaScript. Eventually, though, Google decided to write a compiler instead. This means nearly every feature in Dart must fit inside JavaScript semantically.

JavaScript is a unique language, and it isn’t necessarily feature-rich. It accomplishes what it needs to accomplish, without any extraneous bells and whistles (which is a plus, in my opinion). So, in the past, Dart has been limited by what JavaScript can do. The result is a language that feels more like Java but is less cumbersome to write. (I like to jokingly call it “Java Lite,” which is a compliment.)

There is nothing particularly exciting about its syntax, and no special operators will throw you for a loop. In Dart (unlike JavaScript), there is one way to say true: true. There is one way to say false: false. If (3) { would make Dart blow up, but it’s coerced to true in JavaScript.

In Dart, there are no modules (like C# and the like), and there is really only one dynamic in which people write Dart code: object-oriented. Types are used in Dart, which can be a hurdle if you’re coming from Ruby, Python, or JavaScript, but the type system is not as strict as in many typed languages.

All this is to say that Dart is a relatively easy language to learn, but you should take the time you need to learn it. Writing an app in Flutter is writing Dart. Flutter is, underneath it all, a library of Dart classes. There is no markup language involved or JSX-style hybrid language. It’ll be much easier to be a productive Flutter developer if you’re comfortable writing effective Dart code. I’ll cover Dart in depth in chapter 2.

1.3. Who uses Flutter?

At the time of writing, Flutter is used in production by big and small companies alike. I’ve been lucky enough to use Flutter at work since September 2017, when the technology was still in its alpha stage. By the time you read this, Flutter will be in (at least) version 1.9.0, and my previous company will have migrated all of our clients off of our native apps and onto our Flutter app.

While this isn’t a book about me, I am going to tell you a bit about what I do, because I want you to know that I’m confident in the future of Flutter. The company that I previously worked for is in the enterprise space. Its product is used by some big companies like Stanford University, Wayfair, and Taylor Parts. The core product is a BYOD (bring your own database) platform that lets customers plug in a few options and press a few buttons, and it spits out mobile and web apps to manage work flows and business-related enterprise issues. The mobile app supports offline usage, Esri maps, and real-time feedback. We did all this with Flutter (on mobile) and Dart on the server side. The point is this: don’t be afraid of the limitations of this cross-platform tool.

We weren’t the only ones using Flutter in production. As of this writing, Google AdWords and Alibaba are both using Flutter in production. You can see more examples of who’s using Flutter (including an app I worked on for two years) on Flutter’s website on the showcase page.[1]

1

You can find the showcase at https://flutter.dev/showcase.

1.4. Who should be using Flutter?

Regardless of your role at your company, or even if you’re building apps for fun, everyone should consider Dart for their next project.

1.4.1. Teams, project leads, and CTOs

Flutter has proved, in front of my own eyes, that it increases productivity and collaboration by orders of magnitude. Before Flutter, each time a new feature was introduced to a product at my former company, it had to be written and maintained three times by three different teams—three different teams that could hardly collaborate because they had different skill sets.

Flutter solved that problem. Our three teams (web, iOS, and Android) became one unified clients team. We all had the same skill set, and we could all collaborate and lend helping hands.

At my current job, we’re rewriting a native iOS client in Flutter for the same reason. It allows us to be flexible and productive while offering users both iOS and Android apps. After a failed attempt at a different, unnamed cross-platform solution, Flutter has proven to be the ideal tool.

1.4.2. Individual developers

As developers, we often get starry-eyed and want to start a new project that will change everything. The key to success with this sort of work is busting out the project quickly. I can’t count how many times I was ready to start a new project and quit before I began because of JavaScript build tools and setup. If you need to build an MVP fast, and iterate quickly, Flutter just works.

1.4.3. Code school students and recent CS grads

Code schools are quite popular, and unfortunately for the graduates, that means there are many grads fighting for the same junior-level jobs. My advice to anyone looking for their first job is to build a portfolio that sets you apart. Having a published mobile app with actual users will do that, and it’s easier than ever to achieve with Flutter.

1.4.4. Open source developers

Flutter is open source. Dart is open source. The tools and the libraries are open source.

1.4.5. People who value speed

Flutter is for people who want to build an app quickly that doesn’t sacrifice performance. By speed, I mean the speed at which you can write code and iterate, and the speed at which Flutter builds. Thanks to hot reloading, Flutter rebuilds your application in sub-second time as you’re developing.

I would also argue that Dart makes you more productive, adding more speed. Dart is strictly typed and fully featured. Dart will save you from having to solve problems that are already solved, and the syntax and tooling make debugging a breeze.

1.4.6. People who are lazy

I’m a lazy developer. If a problem is solved, I don’t want to waste time solving it again. Flutter comes with a massive library of Material Design widgets that are beautiful and ready to use out of the box. I don’t have to worry myself with designing and building complicated pieces of a mobile app (such as a navigation drawer). I want to focus on the business logic that makes my app unique.

1.4.7. People who value control

Although I’m lazy, I do want to know that if I need to, I can change anything about my app. Flutter exposes every layer of the framework to the developer. If you need to write some custom rendering logic, you can do that. You can take control of animations between frames. Every high-level widget in Flutter is a string that can be unspooled and followed to the inner workings of the framework.

1.5. Who this book is for

This book assumes that you’ve developed an application before. That could be a web app, a native mobile app, Xamarin, or something I don’t even know about. The important thing for you to understand is how a modern application works. I don’t expect you to know how to write code across the whole stack, only that you know what a modern stack consists of. This book will focus on writing a mobile application in Flutter, and I will throw around common terms like state, store, services, and so on.

If you meet those criteria, I can assume that you’re familiar with the common threads across all programming languages. You don’t need to know Dart, but you do need to know about basic data structures (Map, lists, and so on) and features of all high-level languages (control flow, loops, and so on).

Finally, this book assumes that you know some high-level information about software engineering in general. For example, Dart and Flutter operate completely in the camp of the object-oriented paradigm.

This book is perfectly suitable for you if you’re a junior developer, a senior developer, or anywhere in between. The prerequisites are simply that you’ve worked on large code bases before and you’re interested in learning Flutter.

1.6. Other mobile development options

Before I offer up unsolicited opinions on your other options, I want to make this crystal clear: good developers think critically about which tools and technologies should be used in every different situation. And Flutter is not the answer 100% of the time. (But I will try hard to convince you otherwise.)

1.6.1. Native development (iOS and Android)

Your first choice is to write native apps for iOS and Android. This gives you maximum control, debugging tools, and (potentially) the best performance. At a company, this likely means you have to write everything twice: once for each platform. You probably need different developers on different teams with different skill sets, and those developers can’t easily help each other.

1.6.2. Cross-platform JavaScript options

Your second option: cross-platform, JavaScript-based tools such as web views and React Native. These aren’t bad options, either. The problems you experience with native development disappear. Every frontend web developer on your team can chip in and help; all they need are some modern JavaScript skills. This is precisely why large companies such as Airbnb, Facebook, and Twitter have used React Native on core products.

Of course, there are some drawbacks. (You knew there would be drawbacks.) The biggest is called the JavaScript bridge.

The first “mobile apps” to be built cross-platform were simply web views that ran on WebKit (a browser rendering engine). These were literally embedded web pages. The problem with this is basically that manipulating the DOM is very expensive and doesn’t perform well enough to make a great mobile experience.

Some platforms have solved this problem by building the JavaScript bridge, which lets JavaScript talk directly to native code. This is much more performant than the web views, because it eliminates the DOM from the equation, but it’s still not ideal. Every time your app needs to talk directly to the rendering engine, it has to be compiled to native code to “cross the bridge.” In a single interaction, the bridge must be crossed twice: once from platform to app, and then back from app to platform, as shown in figure 1.1.

Figure 1.1. The JavaScript bridge is a major bottleneck to mobile frameworks in JavaScript. The JavaScript isn’t compiled to native code and therefore must compile on the fly while the app is running.

Flutter compiles directly to ARM code when it’s built for production. (ARM is the processor used in modern mobile devices, wearables, internet of things [IoT] devices, and so on.) And Flutter ships with its own rendering engine. Rendering engines are outside the scope of this book (and my knowledge, for that matter). Simply, though, these two factors mean that your app is running natively and doesn’t need to cross any bridge. It talks directly to native events and controls every pixel on the screen directly. Compare the JavaScript bridge to figure 1.2, which represents a Flutter app.

Figure 1.2. The Flutter platform, in the context of the JavaScript bridge

The JavaScript bridge is a marvel of modern programming, to be sure, but it presents two big problems. First, debugging is hard. When there’s an error in the runtime compiler, that error has to be traced back across the JavaScript bridge and found in the JavaScript code. The second issue is performance. The JavaScript bridge is expensive: each time a button in the app is tapped, that event must be sent across the bridge to your JavaScript app. The result, for lack of better term, is jank.

Many of these cross-platform problems are solved with Flutter. Later in this chapter, I’ll show you how.

1.7. The immediate benefits of Flutter

I’m going to make an assumption about you. Since you’re reading this book (and this section), it follows that you’re curious about Flutter. It’s also likely that you’re skeptical.

The reasons you have for being skeptical are fair. It’s a new technology, and that means breaking changes in the API. It means missing support for important features. It seems possible that Google could abandon it altogether one day. Not to mention the fact that Dart isn’t widely used, and many third-party libraries that you want may not exist.

Now that I’ve pinned you, let me change your mind. The API likely will not change, as the the company that’s developing Flutter and Dart uses Dart internally on major revenue-generating apps such Google AdWords.

Dart has recently moved into version 2.5, which means it will be a long time until it changes much. In the near future, there likely won’t be many breaking changes.

Finally, features are indeed missing, but Flutter gives you the complete control to add your own native plugins. In fact, many of the most important operating system plugins already exist, such as a Google Maps plugin, camera, location services, and device storage. And new features are being added all the time. By the time you read this, this paragraph may be irrelevant.

1.7.1. No JavaScript bridge

The JavaScript bridge, used in most cross-platform options, is a major bottleneck in development and in your application’s performance. Scrolling isn’t smooth, applications aren’t always performant, and they’re hard to debug.

Flutter compiles to actual native code and is rendered using the same engine that Chrome uses to render (called Skia), so there’s no need to translate Dart at runtime. This means apps don’t lose any performance or productivity when running on a user’s device.

1.7.2. Compile time

If you’re coming from native mobile development, one of your major pains is the development cycle. iOS is infamous for its compile times. In Flutter, a full compile generally takes less than 30 seconds, and incremental compiles take less than a second thanks to hot reloading. At my day job, we develop features for our mobile client first because Flutter’s development cycle allows us to move so quickly. Only when we’re sure of our implementation do we write those features in the web client.

1.7.3. Write once, test once, deploy everywhere

Not only do you get to write your app one time and deploy to iOS and Android (and soon, web!), you also only have to write your tests once. Dart unit testing is quite easy, and Flutter includes a library for testing widgets.

1.7.4. Code sharing

I’m going to be fair here: I suppose this is technically possible in JavaScript as well. But it’s certainly not possible in native development. With Flutter and Dart, your web and mobile apps can share all the code except each client’s views. You can use dependency injection to run an AngularDart app and a Flutter app with the same models and controllers. (And, in the very near future, Flutter will be able to target Web and Desktop, too.) And obviously, even if you don’t want to share code between your web app and your mobile app, you’re sharing all your code between the iOS and Android apps.

In practical terms, this means you are super productive. I mentioned that we develop our mobile features first at my day job. Because we share business logic between web and mobile, once the mobile feature is implemented, we only have to write views for the web that expect the same controller data.

1.7.5. Productivity and collaboration

Gone are the days of separate teams for iOS and Android. In fact, whether you use JavaScript in your web apps or Dart, Flutter development is familiar enough that all your teams will be unified. It’s not a stretch by any means to expect a JavaScript web developer to also effectively develop in Flutter and Dart. If you believe me here, then it follows that your new unified team will be three times more productive.

1.7.6. Code maintenance

Nothing is more satisfying than fixing a bug once and having it corrected on all your clients. Only in very specific cases is there a bug on the Flutter-produced iOS app and not the Android one (and vice versa). In 100% of these cases, these bugs aren’t bugs, but cosmetic issues, because Flutter follows device OS design systems in its built-in widgets. Because these are issues like text size and alignment, they are trivial in the context of using engineering time to fix them.

1.7.7. The bottom line: Is Flutter for you?

You can spend all day listening to people tell you the benefits or downfalls of any technology. At the end of the day, though, it’s all about the tradeoff. So should you care about Flutter? I’ve sprinkled in the answer to this already, but let me give it to you straight.

Are you an individual developer working on a side project or new product? Then the answer is simple: yes. This is absolutely for you. The amount of time you’ll spend getting up to speed with Dart and Flutter will pay off big time in the long run.

Are you a CTO deciding if your company should adopt the technology? Well, this is a little more nuanced. If you’re starting a new project and trying to use the skills of web developers, then absolutely. You’ll get better performance and a more cohesive team, and all your developers (mobile and web), will be able to pick it up quickly. However, if you have a big team of iOS and Android engineers, then probably not. If you have the resources to not be concerned with keeping parity between your clients, then why rewrite them? Why gamble on a new technology? Flutter is about empowering anyone to build native quality apps, but if you’re already empowered to build native apps, it’s probably not for you. (This is why Airbnb famously abandoned React Native.)

My final comment is this: you can be up and running with a new Flutter app in about an hour from a standing start. If you already do iOS or Android development on your machine, you likely have most of the tools needed already, and you can be up and running in a matter of minutes. You might as well give it a try.

1.8. Future benefits of Flutter: Web apps and desktop apps

As of this writing, the Flutter team has officially announced Flutter for the web (also known as Hummingbird). This project is extremely exciting. When it’s stable, Flutter will be the first framework that is truly “write once, deploy everywhere.” Flutter is working on the functionality to deploy applications not only to iOS and Android, but also ChromeOS, browsers, macOS, Windows desktop apps, and Fuchsia.

As of Google I/O 2019, Flutter web is in technical preview. Right now, you can experiment with it and make web apps. That being said, I will not be talking about Flutter web in this book. There are two reasons for this:

  • As I mentioned, the project is currently in the technical preview stage. That means everything you learn about it is likely to change.
  • More important, the goal of Flutter web is that it “just works.” So, in theory, if you learn everything in this book, once Flutter web becomes stable, you’ll already know everything you need to write a web app with Flutter.

1.9. A brief intro to how Flutter works

At a high level, Flutter is a reactive, declarative, and composable view-layer library, much like ReactJS on the web (but more like React mixed with the browser, because Flutter is a complete rendering engine as well). In a nutshell, you build a mobile UI by composing together a bunch of smaller components called widgets. Everything is a widget, and widgets are just Dart classes that know how to describe their view. Structure is defined with widgets, styles are defined with widgets, and so are animations and anything else you can think of that makes up a UI.[2]

2

A brief intro to widgets from the docs: http://mng.bz/DNxa.

Warning

“Everything is a widget” is a potentially misleading statement that you’ll see everywhere on the internet, including in the official documentation. This doesn’t mean there aren’t other objects in Flutter. Rather, it means that every piece of your app is a widget. Styles, animations, lists, text, buttons, and even pages are widgets. For example, there isn’t an object called “App” that defines the root of your application. The root of your application can technically be any widget. To be sure, there are other objects in the Flutter SDK (such as elements), which we’ll discuss later.

Suppose you’re building a shopping cart app. The app is pretty standard: it’ll list products, which you can add to a cart via Add and Remove buttons. Well, the list, the products, the buttons, the images, and everything else are widgets. Figure 1.3 shows how some of these widgets would be coded. Other than widgets, the only classes you’re likely to write are your own logic-specific classes, which aren’t related to Flutter.

Figure 1.3. Everything is a widget.

Everything is widgets inside widgets inside widgets. Some widgets have state: for example, the quantity widgets that keep track of how many of each item to add to the cart. When a widget’s state changes, the framework is alerted, and it compares the new widget tree description to the previous description and changes only the widgets that are necessary. Looking at our cart example, when a user presses the + button on the quantity widget, it updates the internal state, which tells Flutter to repaint all widgets that depend on that state (in this case, the text widget). Figure 1.4 shows a wire frame of what the widgets might look like before and after pressing the “+” IconButton.

Figure 1.4. setState updates the displayed quantity.

Those two ideas (widgets and updating state) are truly the core of what we care about as developers. For the remainder of this chapter, I want to break down, in depth, what’s really happening.

1.9.1. Everything is a widget

This is a core idea in Flutter. Everything is a widget. Again, this doesn’t mean that there aren’t other object types in Flutter—there are. Later in this book, I explore these other objects in depth, but as a developer you’ll rarely care about anything other than widgets. The point is that there aren’t models and view models or any other specific class type in Flutter.

A widget can define any aspect of an application’s view. Some widgets, such as Row, define aspects of the layout. Some are less abstract and define structural elements, like Button and TextField. Even the root of your application is a widget.

Using the shopping cart example again, figure 1.5 shows how you might code some of the layout widgets, while figure 1.6 shows some structural widgets. To be sure, though, there are a lot more widgets than we can see, because they define layout, styles, animations, and so on.

Figure 1.5. Examples of common layout widgets

Figure 1.6. Examples of common structural widgets

For context, these are some of the most common widgets:

  • LayoutRow, Column, Scaffold, Stack
  • StructuresButton, Toast, MenuDrawer
  • StylesTextStyle, Color
  • AnimationsFadeInPhoto, transformations
  • Positioning and alignmentCenter, Padding

1.9.2. Composing UI with widgets

Flutter favors composition over class inheritance, which allows you to make your own unique widgets. A majority of widgets are combinations of smaller widgets.[3]

3

Composition over inheritance from the Flutter docs: http://mng.bz/dxov.

In practice, that means that in Flutter you aren’t subclassing other widgets in order to build custom widget. This is wrong:

class AddToCartButton
 extends Button {}

Rather, you compose your button by wrapping the Button widget in other widgets:

class AddToCartButton extends StatelessWidget {
  // ... class members
  @override
  build() {
    return Center(                   1
      child: Button(                 2
        child: Text('Add to Cart'),
      ),
    );
  }
}

  • 1 This widget will center this AddToCartButton forever.
  • 2 Pass text in, and now you have a custom component.

If you’re coming from the web, this is similar to how React favors building small, reusable components and combining them.

Widgets have a few different life-cycle methods and object members. The most important method, though, is build(). The build() method must exist in every Flutter widget. This is the method in which you actually describe your view by returning widgets.

1.9.3. Widget types

Most widgets fall under two categories: stateless and stateful. A StatelessWidget is a widget that you (as the developer) are okay with being destroyed. In other words, no information is kept within it that, if lost, will matter. All of the widget’s state or configuration is passed into it. Its only job is to display information and UI. Its life depends on outside forces. It doesn’t tell the framework when to remove it from the tree, or when to rebuild it. Rather, the framework tells it when to rebuild. (If this seems confusing, keep reading. It will make sense when contrasted against StatefulWidget types.)

In our shopping cart example, the AddToCartButton widget is stateless. It doesn’t need to manage state, and it doesn’t need to know about any other part of the tree. Its job is just to wait to be pressed and then execute a function when that happens.

This doesn’t mean the Add to Cart button will never change. You may want to update it at some point to say Remove from Cart: some other widget will pass in the String that represents the text to display on the button (like “Add” or “Remove”), and it will be repainted when the word being passed to it changes. It reacts to new information.

A StatefulWidget in the shopping cart application, on the other hand, is the QuantityCounter widget, because it’s managing a piece of stateful data that tracks the number of items you wish to add to your cart. A StatefulWidget object has an associated State object. The State object has special methods such as setState that tell Flutter when it needs to think about repainting.

State objects are long-lived. They can tell Flutter to repaint, but it can also be told to repaint because the associated stateful widget has been updated by outside forces.[4]

4

Check out this detailed introduction to Widgets from the docs: http://mng.bz/rPae.

Let’s consider our shopping cart app again. So far, we know there are quite a few components on the screen. These components are composed together via a combination of stateful and stateless widgets. Importantly, there is a StatefulWidget called QuantityCounter: a custom widget that I created by combining a variety of built-in widgets. Figure 1.7 shows a wireframe of this custom widget.

Figure 1.7. The quantity widget is composed of buttons, text fields, and layout widgets.

The build method for this would look something like the following. I’ve pointed out the parts you should care about right now.

Listing 1.1. Example build method for the custom QuantityCounter stateful widget
Widget build(BuildContext context) {
  return Container(                         1
    child: Row(
      children: List<Widget>[
         IconButton(
          icon: Icons.subtract,
          onPressed: () {                   2
            setState(() {                   3
               this.quantity--;
            });
          }),
        new Text("Qty: ${this.quantity}),   4
        new IconButton(
          icon: Icons.add,
          onPressed: () {                   5
            setState(() {
              this.quantity++;
            });
          }),
      ],
    )
  );
}

  • 1 build always returns a widget.
  • 2 Built-in property on a button widget that listens for user interaction
  • 3 Decreases the state’s quantity counter
  • 4 The widget will be repainted at this point in the tree every time the state object’s quantity is called.
  • 5 This callback will call setState, which increases the state’s quantity counter.

To be sure, there’s a lot of layout and styling missing there, but that’s the markup you need. The important information in that code block, though, is what’s going on inside the IconButton and Text widgets.

This widget has access to several methods from the base State object class. The most important is setState. Every time the + or - button is pressed, the app will call setState. This method will update whichever part of the widget’s state you tell it to, and will tell Flutter to repaint the widgets that rely on the state change. Figure 1.8 shows wireframes of how the quantity widget might be updated when the “+” button is tapped.

Figure 1.8. User interaction can trigger the framework to re-render using setState.

This process of building and updating widgets is called its life cycle. We’ll explore life cycles in depth throughout the book, but figure 1.9 and the following list give an overview of a StatefulWidget’s life cycle.

Figure 1.9. The stateful widget is actually two objects: the widget and a State object.

Looking at the QuantityWidget again, its life cycle may look something like this:

  1. When you navigate to the page, Flutter creates the object, which creates the State object associated with this widget.
  2. As soon as the widget is mounted, Flutter calls initState.
  3. After the state is initialized, Flutter builds the widget (and, as a consequence, renders it; you’ll see that process in the next section).
  4. Now, the quantity widget is sitting and waiting for three possible events:

    • The user navigates to a different part of the app, in which case the state can be disposed.
    • Widgets outside of this one in the tree have updated and changed some sort of configuration that this widget relies on. In that case, this widget’s state calls didUpdateWidget and repaints if necessary. This may happen if an item sells out and a widget higher in the tree tells this widget to disable itself, since you can no longer add the item to the cart.
    • The button is tapped, which calls setState and updates the widget’s internal state. This also tells Flutter to rebuild and re-render.

1.10. Flutter rendering: Under the hood

The real superpower of Flutter is the process it does one million times every day—the process by which Flutter builds (and rebuilds) your app. At any moment, your Flutter app is composed of a giant widget tree. Figure 1.10 shows a contrived example of what one page of the shopping cart’s widget tree might look like. (In reality, it’s much larger than this tree.)

Figure 1.10. This represents a widget tree, but in reality there are far more widgets in the tree than I can show.

Take a look at one of the CartItem widgets. This widget is Stateful, and each of its children likely relies on the state of that widget. When the state of the CartItem widget is updated, the rendering process in the subtree from this point begins.

Flutter widgets are reactive. They respond to new information from an outside source (or setState), and Flutter rebuilds what it needs to. This is the high-level process:

  1. A user taps a button.
  2. Your app calls setState in the Button.onPressed callback.
  3. Flutter knows that it needs to rebuild, because the Button state is marked dirty.
  4. The new widget replaces the old one in the tree.
  5. Flutter renders the new tree.

Now that Flutter has its new widgets, it’s ready to render. The render step is itself a series of steps. Figure 1.11 shows an overview of the rendering steps that Flutter takes, with an emphasis on step 3.

Figure 1.11. The high-level steps of the rendering process

Flutter kicks off the render by starting any animation tickers. If you need to repaint—for example, because you’re scrolling down a list—the starting position of any given element on the screen is incrementally moved to its ending location, so that it’s a smooth animation. This is controlled by animation tickers, which dictate the time that an element has to move. This effectively controls how dramatic the animations are.

During an animation, Flutter rebuilds and repaints on every frame (which is a lot). Later in this book, we’ll take a deep dive into animations in Flutter.

1.10.1. Composing the widget tree and layout

Next, Flutter builds all the widgets and constructs the widget tree. By widgets, here I mean the data and configuration that dictate how elements on the screen will look. When it builds a button for the tree, it’s not actually building a blue rectangle with text in it; that’s a later step. Widgets just handle the configuration of elements that will eventually be painted on the screen.

After the widget tree is composed, Flutter can start thinking about layout. Flutter walks down the tree—only once—in linear time. (If you aren’t familiar with Big O notation, linear time means fast.) On the way down, it’s collecting information about the position of widgets. In Flutter, layout and size constraints are dictated from parent to child.

On the way back up the tree, every widget now knows its constraints, so the widget can tell its parent its actual size and position. The widgets are being laid out in relation to each other.

In the shopping cart example, this could mean that when the + button is tapped on the QuantityWidget, and the state is updated with a new quantity, Flutter walks down the widget tree, and QuantityWidget tells the buttons and text fields their constraints (not actual size). Then the buttons will tell the widgets representing the + and - icons their constraints, and so on down the tree. Once the algorithm bottoms out at the leaf-node widgets, then all the widgets know their size constraints. On the way back up they can all safely take up the right amount of space at the correct position. Figure 1.12 illustrates this process (on a tree much smaller than any Flutter app would really be).

Figure 1.12. Flutter lays out all the widgets in one walk down and back up the tree, because widgets dictate their children’s size constraints in Flutter.

This single traversal of the widget tree is powerful. In contrast, in a browser, layout is controlled by the DOM and CSS rules. Because of the cascading nature of CSS and the fact that an element’s size and position can be controlled by its parents or itself, it takes many walks down the DOM tree to position all elements. This is one of the biggest performance bottlenecks on the modern web.

1.10.2. Compositing step

Now that each widget is laid out and knows it isn’t conflicting with any other widgets, Flutter can paint the widgets. It’s important to note here that the widgets still aren’t rasterized, or physically painted to pixels on the screen. That’s coming up.

The compositing step is next. This step is when Flutter gives widgets their actual coordinates on the screen. Now they know the exact pixels they’ll take up.

This step is purposefully and importantly separate from the painting step. Because the steps are separate, the widgets that have been composited can be reused if needed. This is useful, for example, when you’re scrolling through a long list, as shown in figure 1.13. Rather than rebuilding each of those list items every time a new one scrolls on or off the screen, Flutter already has them built and painted, and can plug them in where they need to go.

Figure 1.13. The composite step is separate from the painting step, to increase performance.

1.10.3. Paint to the screen

Now the widgets are ready to go. The engine combines the entire tree into a renderable view and tells the operating system to display it. This is called rasterizing, and it’s the last step.

We just covered an entire framework in a couple of paragraphs. It was a lot. You shouldn’t be concerned yet if you don’t know exactly how Flutter works, because I’ll beat this dead horse throughout this entire book. These are the three main ideas I want you to keep in mind as we dive deeper into Flutter, because they’re what matters to us as developers:

  • Flutter is reactive.
  • Everything is a widget.
  • State objects are long-lived and are often reused.
  • Widgets’ constraints are dictated from their parents.

If you’d like more information about how Flutter renders, check out this hour-long Google Tech Talk explaining the rendering engine: http://mng.bz/xlvg. It’s a few years old, but the information is still relevant.

1.11. Final note

If I can leave you with one impression at the end of this chapter, it’s this: Flutter is simple to use and a powerful tool, but it does take effort to use well. It is, especially if you’re not a ReactJS web developer, a new paradigm of approaching the UI. If you find yourself frustrated while learning from this book, don’t assume it’s your fault. In fact, there are only two possible explanations. First, and most likely, you are just like every other human being: programming is hard, and learning takes time. Reread material, take a nap, and get back to it. You will get it. The only other explanation is that I have done a poor job of making the material digestible, and I welcome you to berate me on your choice of platform. I’m @ericwindmill everywhere.

Summary

  • Flutter is a mobile SDK written in Dart that empowers everyone to build beautiful, performant mobile apps.
  • Dart is a language made by Google that can compile to JavaScript. It’s fast, strictly typed, and easy to learn.
  • The advantages of using Flutter are that it compiles to native device code, making it more performant than other cross-platform options. It also has the best developer experience around, thanks to Dart’s JIT and Flutter’s hot reload.
  • Flutter is ideal for anyone who wants to make a highly performant cross-platform app quickly. It’s probably not the best choice for a large company with existing native teams.
  • In Flutter, everything is a widget. Widgets are simply Dart classes that describe their view. A UI is created by composing several small widgets into complete widget trees.
  • Widgets come in two main flavors: stateless and stateful.
  • Flutter provides state management tools, such as widget life-cycle methods and special State objects.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.139.50