Flutter - why you may love it or hate it

flutter, dart, android, cross-platform 6 mins edit

Flutter is a new Google’s framework for creating cross-platform applications. So far, I haven’t tried to create any cross-platform projects so I wanted to give it a try. This won’t be a next basic tutorial for creating apps with Flutter. I’ll just present my first impression of things that have made me love and hate Flutter after a few hours of having fun with it.

Dart

Before I started implementing my first application, I had thought it would be wise to prepare myself for new language syntax. Flutter is just a framework. Language which it uses is called Dart. Dart is an object-oriented, class defined, garbage-collected language created by Google. It is pretty similar to Kotlin, C# or Swift. Everything you need to know about it you can find on Flutter’s Get started page.

Flutter

One thing that is worth knowing is that Flutter’s application are not compiled like React Native or NativeScript code. It’s not only UI elements, which are compiled, but the whole thing is. Flutter doesn’t use a special bridge to communicate between our code and native code, it uses a C/C++ library for compilation, so it’s much closer to a machine language and it gives us a much better performance.

First application

I’ve decided to continue my journey with Flutter’s “Get started” documentation. The first application I’ve created was developed step by step from this tutorial. You can see the complete code of an application below:

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      home: RandomWords(),
    );
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => new RandomWordsState();
}

class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _biggerFont = const TextStyle(fontSize: 18.0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
      ),
      body: _buildSuggestions(),
    );
  }

  Widget _buildSuggestions() {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0),
        itemBuilder: (context, i) {
          if (i.isOdd) return Divider();
          final index = i ~/ 2;
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
          }
          return _buildRow(_suggestions[index]);
        });
  }

  Widget _buildRow(WordPair pair) {
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }

A first few things you can notice is that:

  • It’s only one file - we don’t create UI’s in a separate file like I’m used to in Android development,
  • It’s short - about 50 lines for application which creates a never-ending list? It’s pretty awesome!
  • Everything is Widget - the whole Flutter application is created using Widgets. Every UI element (and even the main screen block) is a Widget. Creating Flutter app is just creating a tree of Widgets.

Let’s just quickly explain what is going on step by step:

  • we start an application in the main() function calling runApp(),
  • in MyApp class, we return MaterialApp with a title and the rest of the layout - RandomWords class (which of course is a Widget),
  • in RandomWordsState we create State which is a logic for RandomWords class of what we would like to show inside,
  • overriden build method creates the Widget - Scaffold, which in its body calls the function buildSuggestions(), that will return us a ListView Widget,
  • buildSuggestions() for odd indexes creates a Divider (simple horizontal line) and for the even once, inflates a ListTile Widget using buildRow() function,
  • finally the buildRow() creates a simple Text widget using a string generated by the english_words library which is being held in a suggestions array.

Combining layout and logic code in a single place seemed strange to me at first, but I got used to it after some time.

Hot Reload

Flutter supports a great development feature. Hot Reload allows you to rerun your application after some simple changes in no time. That is great! I won’t have to wait a minute every time I make a simple change, shall I? Well.. not necessarily, because it doesn’t work every time. Let’s say that we want to change Text’s color in our application. We adjust _biggerFont implementation to :

final _biggerFont = const TextStyle(fontSize: 18.0, color: Colors.green); 

then save (saving the file applies Hot Reload as well) and… nothing happens. Texts inside the list doesn’t change their color. We have to rerun the application completely to see the changes. Now, if we try to change the text color to blue after pressing save, Hot Reload does work but as you see, in most cases it is better to just rerun application completely to be sure something does or doesn’t work. Nevertheless, rerunning Flutter application seems to be a lot faster than rerunning traditional Android code.

Material Design

As you could have already noticed, everything in the Flutter app depends on Material Design. Even the main application container is called MaterialApp. Personally, I think that is great, because I love all the UI designs there, but for iOS user it might be strange. Every Flutter app looks exactly the same on every platform. You can obviously change some layouts, depending on the device it’s running but it doesn’t automatically adjust the style of the components to match a specific platform.

Things I love in Flutter

  • a lot of predefined Widgets - if you want to add Floating Button, Drawer Navigator or even some action buttons to the toolbar, it will take you only a few lines of the code to implement. All the basic features (like Toolbars - back button or Drawer’s - open) are already implemented,
  • easy implementation of animations,
  • still developed - Google is adding new features all the time, new third-party libraries are being created and you can find a lot of help on StackOverflow already,
  • better performance than all the JavaScript’s methods,
  • Hot Reload - it actually helps :D.

Things I hate in Flutter

  • .yaml files - I’ve spent some time trying to fix a simple bug, which was caused by one additional white-space. When you add image, you need to specify it in pubspec.yaml file and I’ve made a typo there. Fortunately, online validators came to the rescue,
  • ending each Widget’s argument’s with comma - after adding the last argument of a Widget, you should end it with ,. Otherwise the code will be badly / ugly formatted. This sometimes leads to the code which in the end looks like this:
          ],
        ),
      ),
    ),
    );
    
  • ending lines with a semicolon - after getting used to Kotlin, it’s really annoying that I have to add the semicolons again (but that’s more of a Dart thing I guess).

Should I use it?

Everything depends on a scope of a project. If you want to develop multi platform application by yourself it’s easier to use a cross-platform method, rather than writing native code for each one. Choosing between Flutter and React Native / NativeScript depends on you. Thanks to the constant development, it seems to me that it can outrun his competitors, but it hasn’t done it yet. You also need to bare in mind that cross-platform methods always lack some features. It is highly probable that for the very specific task, you would have to add some native code. Fortunately, it’s also not so hard to do with Flutter.