Learning How To Flutter | iRyanBell.com
iRyanBell

Learning How To Flutter

May 15, 2019

Google Flutter Create challenge

Flutter is a new open-source mobile application development framework featuring fast hot-reloads and reactive state propagation. It provides an alternative to React Native (https://facebook.github.io/react-native) for writing single-source codebases that can be deployed natively across Android, iOS, Web, and Desktop platforms.

Last month, I completed my first Flutter-based project to enter into Google’s “Flutter Create” challenge.

Flutter Create is a contest that challenges you to build something interesting, inspiring, and beautiful with Flutter using 5KB or less of Dart code.

This challenge largely functioned as an onboarding crash course for new developers to become acquainted with the framework’s underlying language, Dart. Dart has been around since 2011, yet this was my first time encountering it in the wild.

When asked why Google went with Dart instead of Javascript, the answer seems to be due to the optimization problem of pushing hot diffing updates to the screen and being able to compile down fast, native binaries. Despite the duality of the language being written for the compiler, yet spoken by humans, it’s actually fairly pleasant to use.

5Kb is enough space that you can make something functional without having to focus your efforts entirely on minification (as compared with a challenge like this recent JS1k Competition which was all about the minify: https://js1k.com/2019-x/demo/4142).

The size limit prevents entrants from doing much more than presenting a single, concise idea. It’s a nice way to get your feet wet in the language without being able to bury yourself under spaghetti sauce.

The entries from the challenge were showcased at Google’s latest I/O conference. Here’s a video featuring entries from the competition:

Flutter Create Highlight Reel https://www.youtube.com/watch?v=WLvpROMUjYQ

Meet Dart

Dart is an object-oriented, class defined, garbage-collected language using a C-style syntax that transcompiles optionally into JavaScript. It supports interfaces, mixins, abstract classes, reified generics, static typing, and a sound type system.

Stepping into a new programming language is always a humbling experience. There’s generally quite a bit of stumbling around and Googling every which way. The speed of attaining language fluency varies by the documentation available and StackOverflow support. Thankfully, the problems I faced were easily Googleable.

The first friction point for me was the object-oriented design pattern of Flutter development. In general, I prefer writing in a functional style wherever it can be applied. When I read through OOP-style code, I can’t help but see the typical boilerplate wrappers as being unnecessary and distracting. Coupled with the language’s typed data objects and verbose enums, you see a lot of text on the screen for relatively simple concepts. With nesting performed at the parenthesis level, there’s also a bit of a nutty china doll closing bracket hell.

Check out the starter:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

It’s very easy to understand what’s going on here, but you can see how the verbosity might run away from us.

I would much prefer to see something like:

import 'material'

const title = 'Welcome to Flutter'
const appBar = matterial.appBar({ title })
const body = material.center('Hello World')
const home = matterial.scaffold({ appBar, body })

(() => material.app(title, home))()

Check out this boilerplate for putting a button on an empty screen…:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

To create a button with an icon, the code is literally this verbose:

IconButton(
  icon: Icon(
    Icons.ICON
  )
)

It’s like saying “I’d like to create an icon button with an icon of an icon Icon icon.”

I’m hoping with a bit more practice, I’ll become more flexible at switching between functional / OOP styles, and find a way to use Dart that allows me to express myself with more lambdas and fewer classes.

For the challenge, I wanted to try my hand at building a social to-do list with speech recognition. The gist is that you would tap a mic button on, say something like “item 1, item 2,” tap the mic button off, and find your list populated with two items as dictated. To remove tasks, you would swipe left, and to complete tasks, you would swipe right. From there, a Share button would allow you to text message, email, or tweet your progress report.

I went with the working title, GSDist, as in “Get sh_t done…ist” — in hindsight, this is not a very good title.

Here’s a starting point for a UX prototype that illustrates this workflow: https://www.figma.com/file/dKU2LO8nXQN0R8lbkm2hjY1p/GSDist

Download link:
https://iryanbell.com/downloads/GSDist.fig

Off we go!

To begin development in Flutter, stop by Flutter.dev and choose your adventure — Windows, macOS, or Linux flavor.

https://flutter.dev/docs/get-started/install

Ideally, a double-click would be enough to get us through installation. But that’s not the case with Flutter. (This might be a good time to make yourself a cup of coffee…)

The process consists of manually installing Dart + Flutter, manually updating your bash PATH in .bash_profile (which may require creating a new hidden file for macOS if it doesn’t already exist), manually installing Xcode, manually activating the Xcode CLI tools with a signed license, manually installing Android Studio, manually installing the Android hardware accelerator, manually installing emulators for Android and iOS, manually installing brew, manually configuring cocoapods, manually installing the VS Code extension, manually editing the Xcode Runner project, and manually adding your Android / iOS developer credentials.

It’s a straight forward procedure, but it’s far from quick and easy.

Packages are available at https://pub.dev/

I found a speech recognition package at: https://pub.dev/packages/speech_recognition

Ideally, we would import a package and rock & roll. But with all of the interlocking software tools, there’s room for gears to grind. Right off the bat, I found myself on this GitHub repo’s issues page:

https://github.com/rxlabz/speech_recognition/issues/16

To import the library, you end up needing to modify a “Podfile” and append the magic words “target Runner do, useframeworks!, ENABLEBITCODE-NO, SWIFT_VERSION-4.2” to fix some error message where the main clue looks like “AVFoundation.AVAudioSession:23:14: note: did you mean ‘category’?”

This kind of work can be extremely cryptic to the uninitiated. The user who left the breadcrumbs for the fix signed the message with: “This was all very painful to figure out for myself…”

With Flutter installed, Speech Recognition enabled, and a game plan laid out in Figma, we’re finally ready to begin.

In the next chapter, we’ll put our Widget working hats on and get into it with a Material scaffold. More soon!