Insights

At DVT, we run regular online events focused on the latest technology trends within the IT industry and invite guest speakers to share their knowledge and insights on various topics. The DVT Insights Events aim to enlighten you, educate you and often, provide a new view on a burning issue within the technology space.

Mobile Development: Old dog new flutter trick
Pieter Venter

Mobile Development: Old dog new flutter trick

Monday, 08 March 2021 14:22


Imagine a world where you have access to the collective knowledge of humanity, on a device, within reach. What would you ask this device? How far would you go down the rabbit hole to find an answer to a secret? What would you try to gain from such a device?


Cat pictures, obviously.


Now, in 2021, if your favorite cat app wasn’t available on the 7 devices you use during the day, that would be absolutely unacceptable. Unimaginable, really.


I’d say one of the largest frustrations regarding current development trends would be the inability to deploy what you’ve created onto multiple things. Doing android development, iOS development, web development… etc is amazing in terms of depth — you can really understand a wide variety of aspects regarding your particular field of expertise, but you’re limited to what you can create and, perhaps more importantly, who you can reach.


Where am I going with all of this?


I recently started doing some Flutter development and I have honestly been surprised at how much fun I’m having and how much you can do (and learn) with Flutter. So, I thought I’d make a series of articles for anyone else in a similar situation — looking for a new technology to learn, to help you deploy your cat pictures onto various different things.


But why Flutter ? What’s so great about it ? What are the advantages to using something like Flutter ?


Good questions. Let’s delve deeper.


For anyone who hasn’t heard of Flutter before, Flutter is an open source Software Development Kit (SDK) backed by Google — a free framework that allows you to write code and deploy it to various different platforms — mobile, web and desktop too, all from a single codebase. Not only does the Flutter framework allow you to develop beautiful looking mobile apps, it also keeps native performance in mind, by making sure that everything works as you’d expect it to, for your specific platform and hardware.


Flutter makes use of Dart, which enables compilation to 32-bit and 64-bit ARM machine code for iOS and Android, as well as JavaScript for the web and Intel x64 for desktop devices. If you’ve used something like Kotlin, Swift or even Javascript before, you should be able to learn Dart really quickly.


Flutter includes the contributions of hundreds of developers from around the world and has a vibrant ecosystem of thousands of plug-ins. Every Flutter app is a native app that uses the standard Android and iOS build tools, therefore you can access everything from the underlying operating system, including code and UIs written in Kotlin or Java on Android, and Swift or Objective-C on iOS. Put this all together, combine it with best-in-class tooling for Visual Studio Code, Android Studio, IntelliJ or the programmer’s editor of your choice, and you have Flutter — a development environment for building beautiful native experiences for iOS or Android from a single codebase.


Flutter has been adopted by the broader community quite quickly, as evidenced by the thousands of Flutter apps that are already published to the Apple and Google Play stores. It’s clear that developers are ready for a new approach to UI development in order to create impressive iOS and Android apps.


So in a nutshell, Flutter makes it simple to deliver quality apps to any platform you want — not only that, but it allows you to do this really quickly, with techniques specifically designed to boost productivity, such as allowing you to quickly reload to see the changes you’ve made.You can have a look here if you’re interested in learning more. If you’ve ever considered something like React Native, perhaps you should give Flutter a chance as well.


I won’t go into the details of installing and configuring the Flutter plugin into your favorite IDE, as I’m sure you’ll find a ton of other resources on this available. Personally, I thought Flutter would be pretty cool because I could add it to Android Studio, which I use daily, so this was a bonus for me. You can develop Flutter apps on Linux, macOS, ChromeOS, and Windows. No real specific prerequisites for you to get started then and no cost associated either, so that’s pretty cool.


So, for the sake of my first article in this series, I thought I’d keep it really simple and just walk through some Flutter basics and create a simple app to serve as an introduction to anyone interested in making Flutter apps in future. I’m going to focus on making this series something which the majority of people can understand, so if you’re a manager or someone within the tech space, you should still try to follow along. You can find all of the code available on my github if you’re not interested in coding along.


Let’s go.


When you make a new project in Flutter, you’ll find a whole bunch of code already generated in the lib folder, specifically the main.dart file, but let’s remove all of it. ”Simplicity is the ultimate sophistication”, right?


The lib folder is where you’ll be adding in all your code to achieve magic during this article, you can copy my code here or just follow along.


Let’s get started:



import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp();
  }
}

Lots of strange things happening here, right?


We’ll get through all of it, I promise.


Let’s start off with Flutter building blocks : Widgets.


For the sake of simplicity, everything you see on the screen is created by a widget or several widgets. At the most basic level, a widget is, therefore, a UI element which helps us to achieve a specific layout. See a button? Text? Some cat pictures? These are all one widget or a combination of different widgets. This isn’t entirely true on a technical level, as there are some widgets which can help you achieve things you might not see or notice but, in general, a widget builds the UI.


(On a technical note, this is one of the really powerful Flutter features and really allows components to follow an extensible and open approach, as Flutter abstracts basically everything into a datatype called Widget and because almost everything is therefore of type Widget, you can swap out any UI component into something else seamlessly because they’re all the same data type: Widget. One more time: Widget. I digress.)


One thing you’ll notice here is that we’re extending StatelessWidget.


Stateless widget tells Flutter that the content won’t be changing. This means that after our app has started running, we won’t be able to make any changes to the content which is being displayed for this specific widget. This is a bit of optimization on Flutters part, as the framework now understands that it won’t have to redraw this component again if something were to change, it just stays the same. Your cat pictures won’t be changing.


Stateful widget is a bit different and it’s something we’ll get to in a future article, but by extending from stateful widget, we’re telling Flutter that a specific component might change in future. If you were making a calculator app and wanted to display the result of a mathematical operation on the UI, you’d need to make the component you wanted to update a Stateful widget, so that Flutter knows it might or will be changing. In simpler terms, your cat pictures might change to new or different cat pictures.


You can (and will) mix Stateful and Stateless widgets throughout your apps — some components of your app will change, while others just won’t.


Now, because we’re using MaterialApp, that just means that our app will be making use of material design, you could also use something else, but we’ll skip that for now. To keep this example simple, we’re going to look at one of the parameters available to MaterialApp, specifically : home.



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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

The home parameter tells the app which of our pages do we want to load first when the app is created, in our case, this will be a class we’ll create, inside a file I called my_home_page.dart.


So, under the lib folder, you’ll create a new dart file called my_home_page.dart:



This will be the first page displayed by your app. Progress !


Now, let’s take a break for a moment and go on a bit of a journey.


Most of the apps we use have a similar structure to them. Think about it… your favourite app has a toolbar, with some kind of title and icons at the top, some content in the middle and maybe some cool buttons at the bottom to navigate around.


So, while you’re free to write your app the way you want it and arrange components manually, Flutter makes it simple to achieve this type of structure by giving us a Scaffold component. Scaffold helps us to easily build our apps with a toolbar, a body, perhaps a bottomNavigationBar and a variety of other available parameters.


So, let’s get back to work.


Remember how I said that almost everything is a widget?


Well, inside our newly created my_home_page.dart, we’re going to create a new Stateless widget called MyHomePage:



import 'package:flutter/material.dart';

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
 
  }
}

If you’re following along in an IDE, you’ll notice that the build method is complaining about something. That’s because we have to return a Widget here. We could return a button, a text, any widget really, but let’s make use of Scaffold to get some structure to our app:



import 'package:flutter/material.dart';

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}

Let’s start at the top of our app. Our scaffold allows us to specify that we want to add an appBar, so that’s exactly what we’ll do:



class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
    );
  }
}

At this point, after you’ve added in the AppBar and you run the app, you might start feeling a bit excited, this should look quite familiar to you:



5 star ratings guarenteed*


Inside our appBar, you’ll see there are a variety of parameters available, but the one we’ll be using is title. Notice how title requires something which is of type Widget. This means that we can pass in anything here which is of type Widget.



I told you.


To prove a point here, I’m going to show you something a bit crazy, so try to follow me here…



class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Container(),
      ),
    );
  }
}

The title parameter to our appBar just has to be a type of widget.


Here, I’m putting a Container widget. What is a Container widget? Well, a container widget just… contains… another widget.


Now, I have a title which is a container… and that container can internally keep another container and it’ll still be a widget.



class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Container(
          child: Container(
           //etc... you can keep adding any amount of widgets here
          ),
        ),
      ),
    );
  }
}

While this power might be too great for some, the point I’m trying to prove is that you can pass in any widget for the title, even something you create yourself, because it just requires a widget, nothing more specific than that.


Want to know what’s also a widget? Text. No more funny containers.



class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("The Flutter Series")),
    );
  }
}

So now we’ve passed in a simple Text widget to our appBar and that’s what it’ll display if you run the app:



100 000+ downloads guaranteed.


Furthermore, if you wanted to centre that title, that’s a lot of code! There’s surely no way we can just ask Flutter to centre the title for us to make designers/managers/marketing happy, right? That would be way too simple…



class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("The Flutter Series"),
        centerTitle: true,
      ),
    );
  }
}

Yip.


Moving on.


Let’s add some content to our app. All apps need a picture at least somewhere, so let’s add one. This part of the article is going to ramp up a bit in terms of complexity, but let’s try to keep it simple.


First, we’re going to find a picture to use.


Done.


Next, we’re going to add that into our project:



So, I’m going to create a new folder called assets and inside add an images folder. Here, you’ll add all your resource files you want to show in your app, also inclusive of icon files.


After adding in your images to these folders, we’re going to open a file which can be quite scary (and honestly quite frustrating) when you’re starting with flutter: pubspec.yaml


pubspec.yaml is a file where we specify project dependencies, essentially. Here, you can define where flutter has to get images from; define some font files; add in other libraries as dependencies, etc.


For those who have experience with yaml files, I’m sure this will be quite simple and straightforward, for the rest of us, read this carefully:



Indentation:
             it matters !!

If your indentation isn’t correct in the pubspec file, you’re going to quit your Flutter career before it even begins, so it’s important to understand how it works, otherwise you’ll spend quite a bit of time here (source: just trust me).


Scrolling down inside the pubspec file, you’ll find the following section which talks about adding in assets to your application:



To make it work, we’re going to uncomment the code they’ve provided us, and just modify it slightly, by changing it to:



assets:
  - assets/images/

A useful tip for anyone starting out would be to check the alignment of assets — make sure it aligns with uses-material-design:



Now, we’re done with pubspec.yaml. After going back to main.dart, because the pubspec file was changed, you’ll be prompted to get dependencies again, after that we’re good to go.


Let’s get that image up.


Back in my_home_page.dart, we’re going to add a body to our scaffold with a new widget we talked about earlier, the container:



class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("The Flutter Series"),
        centerTitle: true,
      ),
      body: Container(),
    );
  }
}

(The Container widget is a staple widget you’ll use after learning a bit of Flutter, it’s a really nice widget which allows you to adjust the content inside by specifying some margins; you can add a background colour or an image to a container; set the width and height of the content inside and a whole variety of other parameters. When starting out, I’d suggest using container widgets as the root layout for most of the components you make, as it’s just simpler to adjust your content later).


Up to this point, we’ve had a lot of singular widgets, but haven’t really had a way to specify more than one widget, just a lot of individual components. So let’s add in a new component called the Column widget.


Column allows us to add a number of widgets inside it. Everything else up to this point has just had a single child, but column can take multiple items. Why specifically column? Well, column will arrange the widgets you pass to it vertically. If we’re building the UI for the app, it usually makes sense to build it from the top and move down, right ?


(The opposite of a Column widget would be a Row)


Here’s our code at the moment:



class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("The Flutter Series"),
        centerTitle: true,
      ),
      body: Container(
        child: Column(
          children: [
      
          ],
        ),
      ),
    );
  }
}

We’re going to add another container (yip) and use a few new properties this time.


We’re going to use width, height, and decoration.


Width and Height specify the size of the container, while Decoration is how we specify that we want to change this container in a specific way. I’ll add some code and explain afterwards:



class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("The Flutter Series"),
        centerTitle: true,
      ),
      body: Container(
        child: Column(
          children: [
            Container(
              width: double.infinity,
              height: 300,
              decoration: BoxDecoration(
                  image: DecorationImage(
                      image: AssetImage("assets/images/sample.jpg"))),
            )
          ],
        ),
      ),
    );
  }
}

What’s going on here?





width: double.infinity,


This is a flutter way of saying : use up all the space horizontally.



height: 300,

Here, I’m just setting the height to 300 (or any size you want, just an example value), nothing too strange.



decoration: BoxDecoration(
    image: DecorationImage(
        image: AssetImage("assets/images/sample.jpg"))),

Now, for the large bit of code. Basically, it’s saying that we want to add a decoration to this specific container, using an image asset (called sample.jpg) located inside the folder of images we created earlier.


At this point, you can run the app and you’ll see your picture with your toolbar.


And that’s everything…


Or is it… ?


How about we do some cleanup on our code.


At this point, the body of our app is quite a lot of code:



Container(
  child: Column(
    children: [
      Container(
        width: double.infinity,
        height: 300,
        decoration: BoxDecoration(
          image: DecorationImage(
              fit: BoxFit.cover,
              image: AssetImage("assets/images/sample.jpg")),),
      )
    ],
  ),
)

If only there was a way to group this into a singular, reusable component we could use.


Remember how everything is a widget? Remember how we defined a widget as something which helps us build the UI?


By creating a new file, home_page_content.dart, we can declare a class called HomePageContent where we can do some really cool changes:



class HomePageContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          Container(
            width: double.infinity,
            height: 300,
            decoration: BoxDecoration(
              image: DecorationImage(
                  fit: BoxFit.cover,
                  image: AssetImage("assets/images/sample.jpg")),),
          )
        ],
      ),
    );
  }
}

We’ve now refactored this to be a single, contained widget.


Back to my_home_page.dart — what does our body parameter expect in our Scaffold? That’s right! Anything of type Widget. We can now refactor our code in the Scaffold:



import 'package:flutter/material.dart';
import 'package:flutter_app77/home_page_content.dart';

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("The Flutter Series"),
        centerTitle: true,
      ),
      body: HomePageContent(),
    );
  }
}

That’s pretty awesome, right?!


This means that almost any changes we make inside our HomePageContent won’t be a breaking change in MyHomePage, because our home page won’t really care about what we change inside this widget. This also means that we can reuse the content again somewhere else in the app because it’s now a widget.


Now, we’re done. I promise.


If you’ve followed this to the end, firstly, thank you, secondly, you should now be able to write an app which will be wildly popular and successful:



Features — optional


Keen to learn more about Flutter ?

You could join one of the Flutter communities for more insight into what’s happening, by joining on Slack, Discord, Reddit, Twitter or any of the other platforms available. If you’re interested in seeing what Flutter is capable of, you can check out this page for more info on the latest available widgets you can use, API documentation, codelabs, videos, some samples and a whole lot more. Want to watch some videos instead ? You can head over to the Flutter channel on YouTube and learn some new tricks there. Google’s UI toolkit Flutter uses a rich set of customizable widgets to build apps with almost zero effort. Flutter makes it really simple to develop for both Android and iOS and a whole bunch of other platforms too, with really no prerequisite required to get started, there isn’t a better time for you to start learning a new trick.

DVT 25 Years of Service