Cinnamon logo
Cinnamon logo
Cinnamon logo
Close

Home

Projects

Services

About Us

Careers

Blog

Contact Us

Close

Introduction to Increasingly Popular Flutter

Adnan H.

2020-01-16

10min

Development

As Google's open-source SDK, Flutter provides a way to develop apps for Android and iOS from a single codebase. Look how simple it is!

placeholderIntroduction To Flutter.jpg

Share this blog:

twitter logo
facebook logo
linkedin logo
link logo

Flutter is Google's open-source SDK that provides a way to develop apps for Android and iOS from a single codebase. Most of it was built using Google’s Dart programming language except for a thin layer of C/C++ code. It was developed by the Chrome team and uses Dart as its language of choice. It was first unveiled in 2015 at the Dart developer summit and in December of 2018 Flutter 1.0 was released, marking the first stable version of the SDK.

How does it work?

So how does it work? A Flutter app is just an Android or just an iOS app that has a Flutter view as its root and takes up the whole screen. Every flutter project has an ios and android project folder inside it. The projects have exactly one screen, a FlutterActivity in android’s case and a FlutterViewController for iOS. Then you use the Flutter SDK, Dart language and an IDE that supports Flutter (Android Studio/IntelliJ or Visual Studio code) to develop your whole app inside this Flutter view, paint every pixel inside it, create new screens to navigate to etc. An important consequence of such a setup is that Flutter doesn’t use native components, rather it renders its own components that mimic the use, look and feel of native ones. Most developers will use the Flutter view in full screen mode to create a new Flutter app from scratch, however you can even use it to add new features to your existing iOS or Android app. A sneak peek of your Flutter project’s android and ios folders reveals the simplicity of the approach:

package com.example

import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity: FlutterActivity() {
    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
    }
}

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

It’s widgets all the way down

As I've mentioned before, Flutter doesn't use native views but rather renders its own elements that imitate the native look and feel. To describe the arrangement of these elements on screen, developers will use Flutter classes called widgets. Google's documentation describes a widget as „an immutable description of part of a user interface“. Basically, it is a blueprint that describes how a certain part of screen looks or behaves. Most native mobile developers will instantly be reminded of Views, however that is only one of the roles of widgets. They can be used to define a structural element (like a Button or an Image), a stylistic element (e.g. colour or font), a layout aspect (e.g. margin and padding) and several other things. Nearly everything in Flutter is a widget! For example, a Text widget is used to render a text on screen and an Image widget renders an image. Or if you'd like to change the opacity of the Text widget you can use an Opacity widget, if you'd like to center the Text widget on screen you can use a Center widget, etc. You can also create your own custom widgets, so the possibilities are endless. The way you create your app is by ordering those widgets into a widget tree. You use composition to achieve that, i.e. most widgets take either one or an array of widgets as its child or children. For example, let’s say you want to make a simple Hello World app with the text having a certain size, weight and color. You can do it like so:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('Hello World!',
        textDirection: TextDirection.ltr,
        style: TextStyle(fontSize: 22.0, fontWeight: FontWeight.bold, color: Colors.red)
      ),
    );
  }
}

Now say for example we want to put the text in a blue rectangle and make the rectangle print a statement to the console when it's tapped. We’ll pad the rectangle to make it prettier. We can use Container and GestureDetector widgets:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
        onTap: (){
          print('I\'ve just been tapped.');
        },
        child: Container(
          color: Colors.blue,
          padding: EdgeInsets.all(8.0),
          child: Text('Tap me',
            textDirection: TextDirection.ltr,
            style: TextStyle(fontSize: 22.0, fontWeight: FontWeight.bold, color: Colors.white)
          ),
        ),
      ),
    );
  }
}

See how easy was that? We've just created our own custom button by composing several widgets. Note that the function main() is the entry point of your app and you begin to define your widget tree in the runApp() function. The runApp method triggers the build() method of the first widget, which triggers the build() method of the second widget, and the process repeats all the way down to the last widget. Notice that even the whole app is a widget and it’s of a particular type, a class called StatelessWidget.

Stateless & stateful widgets

Composing widgets into a tree is the way you go about building a UI in a Flutter. Most of Flutter’s out-of-the-box widgets are a composition of several other widgets. In fact, any widget tree assembled in a single build() method is also a widget. In order to create your custom widget you will have to inherit either from Stateless or Stateful widget classes. Stateless doesn’t mean these widgets don’t have state, rather that they have no mutable state that they have to track. There is no way for this type of widget to trigger an UI update when a state change occurs. The part of UI described by the stateless widget can only be updated if its parent triggers the update. On the other hand, stateful widgets come with a State object that stores their state between updates and can trigger rebuilds of the UI. The rebuild is triggered via a setState method. The State object has a long lifespan and survives through rebuilds of the widget tree, unlike the stateful widget itself. To give you a simple example, if you’d want to create an ordinary button with static text, we can make it a stateless widget. But, if you’d like to create a button that shows the number of times the user tapped on it, you’d use a stateful widget. The State object stores the integer that represents the number of taps, calls for a UI update after the number increases and then plugs the incremented value back into the new widget. Building on the custom button we’ve created above, here’s an example of a counter button that shows the number of times it has been tapped:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: CounterButton()
    );
  }
}

class CounterButton extends StatefulWidget {
  @override
  _CounterButtonState createState() => _CounterButtonState();
}

class _CounterButtonState extends State<CounterButton> {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: (){
        setState(() {
          count++;
        });
      },
      child: Container(
        color: Colors.blue,
        padding: EdgeInsets.all(8.0),
        child: Text('Clicked $count times',
          textDirection: TextDirection.ltr,
          style: TextStyle(fontSize: 22.0, fontWeight: FontWeight.bold, color: Colors.white)
        ),
      ),
    );
  }
}

Now, this is a simplified explanation, in reality, a widget creates an Element object that is inserted into an Element tree that mirrors the widget tree. The Element object is the instantiation of the widget and holds a reference to it. The widget is just a blueprint for the Element, while the Element is the actual object that is shown on screen.

Declarative programming

Flutter uses a declarative approach inspired by React. Developers coming from native SDKs might need some time to get used to the declarative style of defining UI in Flutter. In native development when the app state changes, the developer must imperatively change the UI (e.g. set properties on elements like view.isHidden or view.color). On the other hand, the change of state in a Flutter app will trigger a rebuild of the affected part of the UI. Instead of changing a property of an existing widget, the widget itself is rebuilt from scratch with the updated property. While this style of programming might seem less intuitive than the imperative style, once you get used to it, it will provide a much faster and more enjoyable developing experience. You don’t need to take my word for it. The fact that Google released a dev preview of Jetpack Compose recently and Apple’s SwiftUI has been available since iOS 13, both toolkits for declarative style programming, both attracting quite the interest in the developer community, shows that Flutter’s approach to building app UIs is the future of mobile development.

Hot reload & hot restart

Flutter's team devoted quite a lot of their time and resources to tooling. This is why we're provided with some great tools that make development much faster and more enjoyable. The tool with the most impact to your development will probably be hot reload. Hot reload is a tool that injects new code into a running Dart Virtual Machine without a need to rebuild the app and without losing your current in-app state. This is possible because the Dart VM uses a just-in-time execution engine. In practice, this means that any changes you make to your codebase will be visible on your device in around 1 second! Not only does this feature save the developer a lot of time and energy, but also provides new avenues for your app development (e.g. sitting with a designer and making UI/UX changes on the fly). There are several scenarios where hot reload will not work, for example if your newly injected code affects the state of the app. In that case you can use hot restart which works in a similar fashion but also restarts the app in order to reset the state. This is still a very quick process (3-4 seconds on a medium-to-large app).

Packages

Installing new libraries is quick and easy. Whether you want to store data in a local database, use networking, Firebase or UserDefaults/SharedPreferences or maybe try reactive programming in Dart, you can do so by adding a Dart package to your project. Just search for your desired package on the pub.dev website, add it to the list of dependencies in your pubspec.yaml file, run pub get command (pub is Dart's package manager) and your package is ready for use! There are plenty of packages on the site to choose from. The site also has a handy package rating, which is a number between 0 and 100 that represents how popular, well written and maintained it is.

Web support

With the release of Flutter 1.12, the web support for Flutter has graduated from a technical preview to beta. Developers can now try their hand at creating a unique web experience as well as a mobile one, and all from the same codebase.

What does the future hold?

Flutter’s popularity has grown remarkably in 2019. In the span of just one year, Flutter breached GitHub's top 10 list of open source projects by number of contributors and by the end of the year settled on 3rd place (with a total of 13 000 contributors). Since its 1.0 release in December 2018, its number of contributors grew by 279%. Flutter's swift rise in popularity is also reflected in the list of languages that gained most contributors, where Dart reigns supreme, with a remarkable 532% increase in the last year. All of these statistics suggest a bright future for Flutter and make it a strong candidate in the mobile development arena.

Share this blog:

twitter logo
facebook logo
linkedin logo
link logo

Subscribe to our newsletter

We send bi-weekly blogs on design, technology and business topics.

Similar blogs

placeholderFlutter_course_done.png

Marketing

Marketing

2022-05-20

5min

Cinnamon College: Flutter Course
placeholderFreelance_or_Agency_1.png

Sales

Matija Bermanec & Lorena Ujević

2022-05-09

6min

Differences in Hiring an Agency vs. Freelancers
placeholderMarketing_blog.png

Marketing

Dino Serdar

2022-05-02

12min

How did we increase traffic by 502.2%?
Job application illustration

You could use our expertise?

Let's work together.