Step4 Write initial counter app from scratch

Goal of this step

  • Write initial lib/main.dart code from scratch.
  • Understand initial code by writing.

Flutter from web developers

https://flutter.dev/docs/get-started/flutter-for/web-devs

Before we start writing code, let's check this table.

This is a table to compare Web world and Flutter world.

The purpose of this table is to use knowledge you already have to learn new thing.

WebFlutterWhat you need to learn
<div>, <table>Container(),Table()Flutter Widgets, Flutter Widget Livebook
<div style="font-size: 24px;">Text(style: TextStyle(fontSize: 24))Flutter for web developers
Bootstrappackage:flutter/material.dartMaterial Components widgets, Official Gallery, Flutter Widget Livebook
javascriptdartdart language tour
  • At first you may feel flutter code is difficult.
  • But to see this table you can find the similarity of web and flutter
  • I hope this table will reduce the difficulty of learning flutter!
  • You need a time to get used to flutter code as it took time to remember HTML, CSS, Bootstrap and Javascript!

Let's get started!

This is initial lib/main.dart code.

From now on, we will make this file step by step.

lib/main.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
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),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

Rename lib/main.dart to lib/initial_main.dart.

I leave initial file for reference. There are a lot of useful comments. And make empty lib/main.dart.

Step 1 Hello World

Step1-1 dart main() function

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

Every app must have a top-level main() function, which serves as the entrypoint to the app. The main() function returns void

https://dart.dev/guides/language/language-tour#the-main-function

Step1-2 StatelessWidget

  1. Make MyApp StatelessWidget class by VS code auto complete
  2. Add Text() (Check Container() has child by hovering)

https://flutter.dev/docs/development/ui/widgets-intro#hello-world

lib/main.dart
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
);
}
}

If you are using a material widget component, like Scaffold, Material, you don't need to specify textDirection in your Text widget...

https://stackoverflow.com/questions/56122888/flutter-no-directionality-widget-found

Step2 Use MaterialApp()

lib/main.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Hello World!')
),
),
);
}
}

MaterialApp():

https://api.flutter.dev/flutter/material/MaterialApp-class.html

As I mentioned at first table, material package is something like Bootstrap.

You can check widgets catalog here https://flutter.dev/docs/development/ui/widgets/material

theme:

You can choose your app's primary color like this.

title:

I think title property is almost useless in mobile https://stackoverflow.com/questions/50615006/flutter-where-is-the-title-of-material-app-used

Step3 Make StatefulWidget: MyHomePage

In this step, let's extract this Scaffold part to another class.

home: Scaffold(
appBar: AppBar(title: Text('Hello World!')),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
),
),
  1. Make StatefulWidget by VS code auto completion
  2. Pass MyHomePage() to home:
lib/main.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage()
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello World!')
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
),
);
}
}

If you want to dive into stateful widget syntax, read the below links.

But I think it is ok not to understand perfectly right now. Just following code auto completion is enough.

Step4 Pass props to MyHomePage

In this step, we are going to learn

  • how to pass down props to MyHomePage
lib/main.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
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;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title)
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
),
);
}
}

final

Once assigned a value, a final variable's value cannot be changed

What is the difference between the “const” and “final” keywords in Dart?

Please focus on the flow now!

But If you want to dive into these code, check the below links!

Step5 setState() and Layout

In this step, we are going to learn

  • How to change state by setState()
  • How to use Row and Column

  1. Declare initial State
  2. Edit floatingActionButton
  3. Learn how to change state by using setState()
  4. Show state in body
  5. Row and Column
lib/main.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
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;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title)
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have clicked the button this many times:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

_ underscore variable in dart

It's not just a naming convention. Underscore fields, classes and methods will only be available in the .dart file where they are defined.

What does Underscore “_” before variable name mean for Flutter

Privacy in Dart exists at the library, rather than the class level.

https://stackoverflow.com/questions/17488611/how-to-create-private-variables-in-dart/17488825

Row and Column

row-and-column Image from: https://flutter.dev/docs/development/ui/layout#lay-out-multiple-widgets-vertically-and-horizontally

Align of Row and Column

Aligning widgets row Aligning widgets column Image from: https://flutter.dev/docs/development/ui/layout#aligning-widgets

String interpolation

$variableName (or ${expression})

For example

Text('$var');
or
Text('${user.name}');

https://dart.dev/guides/language/language-tour#strings

Theme

You can access theme by using

Theme.of(context)

//https://flutter.dev/docs/cookbook/design/themes#using-a-theme

textTheme

https://api.flutter.dev/flutter/material/TextTheme-class.html

Finish!

Okay, we successfully re-created initial counter app!

I hope you've learned the fundamental of flutter!

Refs

https://flutterbyexample.com/dissecting-the-counter-app