Flutter is a cross-platform framework by Google. In addition to iOS/Android, Web became stable in version 2.0 which is released in March of this year, and Windows/Mac/Linux is beta. Unlike React Native which uses native UI, Flutter uses its own UI. In addition to Material, iOS-style Cupertino is also available, but unless it branches etc., it become the same looks regardless of the platform.
Build the environment
Build the environment according to the official Get started.
First, install Flutter SDK and add PATH.
$ mv ~/Downloads/flutter ~/
$ echo 'export PATH="$PATH:~/flutter/bin"' >> ~/.bash_profile
$ source ~/.bash_profile
$ flutter doctor
Android
Install Android Studio and launch it to download dependencies.
If cmdline-tools component is missing
appears, install it from SDK Manager.
Approve licenses.
$ flutter doctor --android-licenses
Set up an emulator from AVD Manager. Select Hardware - GLES 2.0
as Emulated Performance.
iOS
Install Xcode and CocoaPods, and set up command-line tools.
$ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
$ sudo xcodebuild -runFirstLaunch
$ sudo gem install cocoapods
VSCode
Install Flutter extension, run Flutter: New Project
from Command Palette and select Application, then a project of following structure is created.
$ tree -L 2 .
.
├── README.md
├── analysis_options.yaml
├── android
│ ├── app
│ ├── build.gradle
│ ├── flutter_application_1_android.iml
│ ├── gradle
│ ├── gradle.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── local.properties
│ └── settings.gradle
├── flutter_application_1.iml
├── ios
│ ├── Flutter
│ ├── Runner
│ ├── Runner.xcodeproj
│ └── Runner.xcworkspace
├── lib
│ └── main.dart
├── pubspec.lock
├── pubspec.yaml
├── test
│ └── widget_test.dart
└── web
├── favicon.png
├── icons
├── index.html
└── manifest.json
If Run > Start Debugging
in lib/main.dart
, the build starts for the selected device.
It takes a long time at startup but after that changes is hot reloaded and reflected immediately.
When run on the web, it was rendered by canvas instead of HTML. This behavior can be changed by –web-renderer. Canvas has high performance and can be rendered same as other platform, but the download size is larger.
Look at files
pubspec.yaml
has dependencies and flutter’s settings etc. If add a dependency here and run flutter pub get
, the pakage is installed.
$ cat pubspec.yaml
name: flutter_application_1
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
english_words: ^4.0.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
flutter:
uses-material-design: true
...
Looking at the entry point lib/main.dart
, StatelessWidget
is defined.
$ cat lib/main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
...
There is also a StatefulWidget
which literally has a State
.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
State
returns Widget to render by build()
.
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>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
);
}
}
For example, if you rewrite the body of Scaffold
as follows, the list is rendered.
body: ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, i) {
return ListTile(title: Text(i.toString()));
},
itemCount: 10,
)