The basics
How do I create a Flutter app?
To create an app using React Native, you would run create-react-native-app
from the command line.
$ create-react-native-app <projectname>
To create an app in Flutter, do one of the following:
- Use an IDE with the Flutter and Dart plugins installed.
-
Use the
flutter create
command from the command line. Make sure that the Flutter SDK is in your PATH.
$ flutter create <projectname>
For more information, see Getting Started, which walks you through creating a button-click counter app. Creating a Flutter project builds all the files that you need to run a sample app on both Android and iOS devices.
How do I run my app?
In React Native, you would run npm run
or yarn run
from the project directory.
You can run Flutter apps in a couple of ways:
- Use the “run” option in an IDE with the Flutter and Dart plugins.
-
Use
flutter run
from the project’s root directory.
Your app runs on a connected device, the iOS simulator, or the Android emulator.
For more information, see the Flutter Getting Started documentation.
How do I import widgets?
In React Native, you need to import each required component.
//React Native
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
In Flutter, to use widgets from the Material Design library, import the material.dart
package. To use iOS style widgets, import the Cupertino library. To use a more basic widget set, import the Widgets library. Or, you can write your own widget library and import that.
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/my_widgets.dart';
Whichever widget package you import, Dart pulls in only the widgets that are used in your app.
For more information, see the Flutter Widgets Catalog.
What is the equivalent of the React Native “Hello world!” app in Flutter?
In React Native, the HelloWorldApp
class extends React.Component
and implements the render method by returning a view component.
// React Native
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Hello world!</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
});
In Flutter, you can create an identical “Hello world!” app using the Center
and Text
widgets from the core widget library. The Center
widget becomes the root of the widget tree and has one child, the Text
widget.
// Flutter
import 'package:flutter/material.dart';
void main() {
runApp(
Center(
child: Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
),
);
}
The following images show the Android and iOS UI for the basic Flutter “Hello world!” app.
Now that you’ve seen the most basic Flutter app, the next section shows how to take advantage of Flutter’s rich widget libraries to create a modern, polished app.
How do I use widgets and nest them to form a widget tree?
In Flutter, almost everything is a widget.
Widgets are the basic building blocks of an app’s user interface. You compose widgets into a hierarchy, called a widget tree. Each widget nests inside a parent widget and inherits properties from its parent. Even the application object itself is a widget. There is no separate “application” object. Instead, the root widget serves this role.
A widget can define:
- A structural element—like a button or menu
- A stylistic element—like a font or color scheme
- An aspect of layout—like padding or alignment
The following example shows the “Hello world!” app using widgets from the Material library. In this example, the widget tree is nested inside the MaterialApp
root widget.
// Flutter
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Text('Hello world'),
),
),
);
}
}
The following images show “Hello world!” built from Material Design widgets. You get more functionality for free than in the basic “Hello world!” app.
![]() |
![]() |
When writing an app, you’ll use two types of widgets: StatelessWidget or StatefulWidget. A StatelessWidget is just what it sounds like—a widget with no state. A StatelessWidget is created once, and never changes its appearance. A StatefulWidget dynamically changes state based on data received, or user input.
The important difference between stateless and stateful widgets is that StatefulWidgets have a State object that stores state data and carries it over across tree rebuilds, so it’s not lost.
In simple or basic apps it’s easy to nest widgets, but as the code base gets larger and the app becomes complex, you should break deeply nested widgets into functions that return the widget or smaller classes. Creating separate functions and widgets allows you to reuse the components within the app.
How do I create reusable components?
In React Native, you would define a class to create a reusable component and then use props
methods to set or return properties and values of the selected elements. In the example below, the CustomCard
class is defined and then used inside a parent class.
// React Native
class CustomCard extends React.Component {
render() {
return (
<View>
<Text> Card {this.props.index} </Text>
<Button
title="Press"
onPress={() => this.props.onPress(this.props.index)}
/>
</View>
);
}
}
// Usage
<CustomCard onPress={this.onPress} index={item.key} />
In Flutter, define a class to create a custom widget and then reuse the widget. You can also define and call a function that returns a reusable widget as shown in the build
function in the following example.
// Flutter
class CustomCard extends StatelessWidget {
CustomCard({@required this.index, @required
this.onPress});
final index;
final Function onPress;
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: <Widget>[
Text('Card $index'),
FlatButton(
child: const Text('Press'),
onPressed: this.onPress,
),
],
)
);
}
}
...
// Usage
CustomCard(
index: index,
onPress: () {
print('Card $index');
},
)
...
In the previous example, the constructor for the CustomCard
class uses Dart’s curly brace syntax { }
to indicate named optional parameters.
To require these fields, either remove the curly braces from the constructor, or add @required
to the constructor.
The following screenshots show an example of the reusable CustomCard class.