Flutter for React Native Developers

This document is for React Native developers looking to apply their existing React Native knowledge to build mobile apps with Flutter. If you understand the fundamentals of the React Native framework, then you can use this document as a jump start to your Flutter development.

A Brief Introduction to Dart for JavaScript Developers

While React Native uses JavaScript, Flutter uses a language called Dart. Dart is an open-source, scalable programming language for building web, server, and mobile apps. It is an object-oriented, single inheritance language that uses a C-style syntax that is AOT-compiled into native and also transcompiles optionally into JavaScript. It supports interfaces, abstract classes and strong types.

Entry Point

While JavaScript does not have any specific entry function, Dart (like C) does have an entry function called main().

// JavaScript
function main() {
  // Can be used as entry point
}
// but it has to be called manually.
main();
// Dart
main() {
}

Try it out in DartPad.

Printing to the console

Printing data to the console can be done in the following way.

// JavaScript
console.log("Level completed.");
// Dart
print('Hello World');

Try it out in DartPad.

Variables

Creating and Assigning Variables

While JavaScript variables cannot be typed, Dart variables are optionally typed but it is a good practice to use typed variables.

In Dart 2, variables must either be explicitly typed or it must be possible for the type system to infer the proper type automatically. Dart 2 performs both static and runtime type checks, using a sound type system. This type system enables better tooling, as well as earlier feedback when you write code.

// JavaScript
var name = "JavaScript";
// Dart
String name = 'dart';
var otherName = 'Dart'; // Also inferred to be a String in Strong mode.
// Both are acceptable in Dart.

Try it out in DartPad.

Default value

In Dart, uninitialized variables have an initial value of null. Even variables with numeric types are initially null because numbers are objects in Dart. But in JavaScript, uninitialized variables are “undefined”.

// JavaScript
var name; // == undefined
// Dart
var name; // == null
int x; // == null

Try it out in the DartPad.

Note: For more information, see the documentation on variables.

Checking for null/zero

In Dart, only the boolean value true is treated as true. But in JavaScript, values like 1 or any non-null objects are treated as true.

// JavaScript
var myNull = null;
if (!myNull) {
  console.log("null is treated as false");
}
var zero = 0;
if (!zero) {
  console.log("0 is treated as false");
}
// Dart
var myNull = null;
if (myNull == null) {
  print('use "== null" to check null');
}
var zero = 0;
if (zero == 0) {
  print('use "== 0" to check zero');
}

Try it out in DartPad.

Functions

For the most part, Dart and JavaScript functions are similar. The only thing that’s different in Dart and JavaScript functions is the declaration.

// JavaScript
function fn() {
  return true;
}
// Dart
fn() {
  return true;
}
// can also be written as
bool fn() {
  return true;
}

Try it out in DartPad.

Note: For more information, see the documentation on functions.

Asynchronous Programming

Futures

Like JavaScript, Dart supports single-threaded execution. In JavaScript, the Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

// JavaScript
_getIPAddress = () => {
  const url="https://httpbin.org/ip";
  return fetch(url)
    .then(response => response.json())
    .then(responseJson => {
      console.log(responseJson.origin);
    })
    .catch(error => {
      console.error(error);
    });
};

Whereas Dart uses Future objects to handle this.

// Dart
_getIPAddress() {
  final url = 'https://httpbin.org/ip';
  HttpRequest.request(url).then((value) {
      print(JSON.decode(value.responseText)['origin']);
  }).catchError((error) => print(error));
}

Try it out in DartPad.

Note: For more information, see the documentation on Futures.

async / await

The async function declaration defines an asynchronous function. In JavaScript, when an async function is called, it returns a Promise. The await operator is used to wait for a Promise.

// JavaScript
async _getIPAddress() {
  const url="https://httpbin.org/ip";
  const response = await fetch(url);
  const json = await response.json();
  const data = await json.origin;
  console.log(data);
}

Whereas in Dart, an async function returns a Future, and the body of the function is scheduled for execution later. The await operator is used to wait for a Future.

// Dart
_getIPAddress() async {
  final url = 'https://httpbin.org/ip';
  var request = await HttpRequest.request(url);
  String ip = JSON.decode(request.responseText)['origin'];
  print(ip);
}

Try it out in DartPad.

Note: For more information, see the documentation on async/await.

Learn The Basics of Flutter

How do I create a Flutter app?

In React Native, you would start off your development process by creating the project using the below command line tool.

$ create-react-native-app {projectname}

In Flutter, you can use this command line tool to do the same.

$ flutter create {projectname}

How do I run my app?

In React Native, you would go to the project directory and use npm run ios/android or yarn run ios/android. In Flutter, if you are using the terminal, then you use the flutter run command in the project root directory to run your app on a connected device or simulator. If you are using an IDE like IntelliJ, Android Studio, or VS Code with the Flutter plugin installed then you can use the in-built tools to run the app.

For more information, see the documentation on getting started.

How do I use import statements?

//React Native
import React from "react";
import { StyleSheet, Text, View } from "react-native";

Contrary to React Native’s way of importing each component needed, in Flutter, you import material.dart from the flutter package, which allows you to use any material design widget without explicitly importing it. Dart automatically imports only the widgets that are actually used.

Alternatively, you could import the cupertino widgets, the basic widgets, or your own custom widget library.

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/my_widgets.dart';

What is the equivalent of the React Native Hello World app in Flutter?

Let’s take a look at how we can define the app in their respective frameworks:

// React Native
import React from "react";
import { StyleSheet, Text, View } from "react-native";

export default class HelloWorldApp extends React.Component {
  render() {
    return (
      <View>
        <Text>Hello World</Text>
      </View>
    );
  }
}
// Flutter
import 'package:flutter/widgets.dart';

void main() { 
  runApp(
    new Center(
      child: new Text(
        'Hello, world!',
        textDirection: TextDirection.ltr,
      ),
    ), 
  );
}

The HelloWorldApp class in React Native extends React.Component and implements the render method by returning a view component as shown.

In Flutter, the execution starts off with the main() function inside which a runApp() function is used to take the given Widget and make it the root of the widget tree. In the Flutter example above, the widget tree consists of two widgets, the Center widget and its child, the Text widget.

The text direction needs to be specified in this instance; when a MaterialApp widget is used, this is taken care of for you. When developing a more complex app you would create another class that is either a Stateless or Stateful widget and also use a MaterialApp widget as the root and pass several other widgets to it.

Preview
Android iOS
Loading Loading


How do I use Widgets and nest them to form a Widget tree?

When writing an app, you will commonly author new widgets that are subclasses of either StatelessWidget or StatefulWidget, depending on whether your widget manages any state. In the above Hello World example, HelloWorldApp class extends a StatelessWidget and overrides a build function that describes the widget in terms of other, lower-level widgets.

// Flutter
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("Flutter"),
        ),
        body: new Center(
          child: new Text('Hello World'),
        ),
      )
    );
  }
}

In the above example, the widget tree consists of five widgets, the MaterialApp, Scaffold, AppBar, Center, and Text widgets. The MaterialApp wraps a number of widgets that are commonly required for material design applications and the Scaffold implements the basic material design visual layout structure. In simple apps it is easy to nest widgets, but as the code base gets larger and the app becomes complex it is advisable to break deeply nested widgets into functions that return the widget or smaller classes.

Note: You can check the working code for Flutter and its equivalent React Native code.

How do I create reusable components and use them?

In React Native, you create a separate class for a reusable component and use that class as a component. You would then use props to access the passed variables and functions. In the below React Native example, we have created a custom card class and used it 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} />

Similarly, in Flutter you just create a class for a custom widget and use that class as you would use a normal widget. Alternatively, you can also create and call a function that returns the widget.

// Flutter
class CustomCard extends StatelessWidget {
  CustomCard({@required this.index, @required this.onPress});
  
  final index;
  final Function onPress;
  
  @override
  Widget build(BuildContext context) {
    return new Card(
      child: new Column(
        children: <Widget>[
          new Text('Card $index'),
          new FlatButton(
            child: const Text('Press'),
            onPressed: this.onPress,
          ),
        ],
      )
    );
  }
}
    ...
// Usage
new CustomCard(
  index: index,
  onPress: () {
    print('Card $index');
  },
)
    ...

The constructor for the CustomCard class shows a Dart feature. The curly braces inside the constructor indicates that the parameters are optional when initialising. In order to make these fields required, we have two options- first one is to remove the curly braces from the constructor and the second is to add the @required to the constructor. The latter approach enables the developer to provide parameter names when using the CustomCard class in the app code as show in the (Usage section) example above.

Preview

Android iOS
Loading Loading

Note: You can check the working code in Flutter and its equivalent React Native code.

Project Structure & Resources

Where do I start writing the code?

If you have used CRNA (create-react-native-app), then you have written your code inside App.js. In Flutter, the entry file is ’projectname’/lib/main.dart and execution starts from the main function.

The minimal Flutter app simply calls the runApp() function with a widget. The runApp() function takes the given Widget and makes it the root of the widget tree. Any widget can be passed to it. But, if you are creating an app that uses material design, you can use MaterialApp class as root and define a theme that can be accessed across the app. If you are creating a screen, then you can use Scaffold which implements the basic material design visual layout structure. But that is not mandatory.

How are files structured in a Flutter app?

┬
└ projectname
  ┬
  ├ android
  ├ build
  ├ ios
  ├ lib
    ┬
    └ main.dart
  ├ test
  └ pubspec.yaml

projectname/android - directory containing android-specific files.

projectname/build - stores iOS and Android build files.

projectname/ios - directory containing iOS-specific files.

projectname/lib - externally accessible Dart source files go here. Other source files can be put into /lib/src

projectname/lib/main.dart - the main function, which is start of execution. Also this is where you start writing your dart code.

projectname/test - automated test files.

projectname/pubspec.yaml - metadata for the app. Equivalent of package.json in React Native.

Where do I put my resources (assets) and how do I use them?

In React Native, to add a static image to your app, place it somewhere in your source code tree and reference it like this :

<Image source={require("./my-icon.png")} />

Flutter apps can include both code and assets (a.k.a. resources). An asset is a file that is bundled and deployed with your app and is accessible at runtime. Common types of assets include static data (such as JSON files), configuration files, icons, and images (JPEG, GIF, PNG, and BMP). All the assets can live under any folder under the root directory.

For best practice, you can put them in an assets folder.

Flutter uses the pubspec.yaml file, located at the root of your project, to identify assets required by an app.

flutter:
  assets:
    - assets/my_icon.png
    - assets/background.png

When an asset’s path is specified in the assets section of pubspec.yaml, the build process looks for any files with the same name in adjacent subdirectories. Such files are then included in the asset bundle along with the specified asset.

It is used like this in the app code:

image: new AssetImage('assets/background.png'),

How do I load images over a network?

In React Native, you specify the uri in the source prop of the Image component and also provide the size if needed.

In Flutter, using NetworkImage creates an object that fetches the image from the given URL.

// Flutter
new NetworkImage("https://example.com/images/background.png"),

How do I install plugins/packages?

In Flutter, you cannot install packages from the command-line like in React Native where you use:

yarn add {package-name} / npm install --save {package-name}.

To install a package in flutter follow these steps:

  • Add package name and version to your package’s pubspec.yaml dependencies. The below example shows how to include google_sign_in dart package:
dependencies:
  flutter:
    sdk: flutter
  google_sign_in: "^2.0.1"
  • Install package from the command line by running flutter packages get.
  • Import the package into your code as shown below:
import 'package:google_sign_in/google_sign_in.dart';

For more information, see the descriptions of the Flutter packages, including scores to help you compare them.

Built-In Widgets

Flutter widgets are built using a modern reactive-style framework which takes inspiration from React Native. The central idea is that you build your UI out of widgets. Widgets describe what their view should look like given their current configuration and state.

Widgets are the basic building blocks of a Flutter app’s user interface. Each widget is an immutable declaration of part of the user interface. Unlike other frameworks that separate views, view controllers, layouts, and other properties, Flutter has a consistent, unified object model: the widget.

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)

Widgets are themselves often composed of many small, single-purpose widgets that combine to produce powerful effects. They form a hierarchy based on composition. Each widget nests inside, and inherits properties from, its parent. There is no separate “application” object. Instead, the root widget serves this role.

Views

What is the equivalent of a View in Flutter?

In React Native, View is a container that supports layout with Flexbox, style, touch handling, and accessibility controls.

In Flutter, we have layout specific widgets like Container, Column, Row, Center etc. You can also use higher-level widgets like the Scaffold widget, which provides options for showing drawers, snack bars, and bottom sheets. Higher-level widgets are built from lower-level widgets using composition (instead of inheritance).

Note: For more information on widgets, see the layout widget catalog.

What is the equivalent of FlatList / ListView?

A List is a scrollable list of components arranged linearly. In React Native we use FlatList or ListView for a performant interface for rendering simple, flat lists.

// React Native
<FlatList
  data={[ ... ]}
  renderItem={({ item }) => <Text>{item.key}</Text>}
/>

In Flutter, ListView is Flutter’s most commonly used scrolling widget. The default constructor takes an explicit list of children. It is appropriate to use ListView for a small number of widgets. The ListView.builder constructor takes an IndexedWidgetBuilder, which builds the children on demand. This constructor is appropriate for list views with a large (or infinite) number of children because the builder is called only for those children that are actually visible.

// Flutter
var data = [ ... ];
new ListView.builder(
  itemCount: data.length,
  itemBuilder: (context, int index) {
    return new Text(
      data[index],
    );
  },
)

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and its equivalent React Native code.

How do I use a Canvas to draw/paint?

In React Native, no in-built canvas component is present, so we use third party libraries like react-native-canvas to use canvas.

// React Native
handleCanvas = canvas => {
  const ctx = canvas.getContext("2d");
  ctx.fillStyle = "skyblue";
  ctx.beginPath();
  ctx.arc(75, 75, 50, 0, 2 * Math.PI);
  ctx.fillRect(150, 100, 300, 300);
  ctx.stroke();
};

render() {
  return (
    <View>
      <Canvas ref={this.handleCanvas} />
    </View>
  );
}

In Flutter, we use CustomPaint widget to draw during the paint phase. We implement abstract class CustomPainter and pass it to painter property in CustomPaint widget.

// Flutter
class MyCanvasPainter extends CustomPainter {

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = new Paint();
    paint.color = Colors.amber;
    canvas.drawCircle(new Offset(100.0, 200.0), 40.0, paint);
    Paint paintRect = new Paint();
    paintRect.color = Colors.lightBlue;
    Rect rect = new Rect.fromPoints(new Offset(150.0, 300.0), new Offset(300.0, 400.0));
    canvas.drawRect(rect, paintRect);
  }
  
  bool shouldRepaint(MyCanvasPainter oldDelegate) => false;
  bool shouldRebuildSemantics(MyCanvasPainter oldDelegate) => false;
}
class _MyCanvasState extends State<MyCanvas> {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new CustomPaint(
        painter: new MyCanvasPainter(),
      ),
    );
  }
}

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and its equivalent React Native code.

Layouts

How do I lay out my Widgets?

In React Native, you would normally use the style prop on the view component to specify the flexbox properties to layout the underlying components like this:

// React Native
<View
  style={{
    flex: 1,
    flexDirection: "column",
    justifyContent: "space-between",
    alignItems: "center"
  }}
>

In Flutter, layout is determined by a combination of the type of Widget that you choose and its layout and style properties. Contrary to how it is done in React Native, where most of the layout can be done with the props that are passed to a specific component, in Flutter most of the layout is done by the use of widgets that are specifically designed to provide layout. The Flutter widgets Column and Row take an array of children and not styling properties (although there are layout properties such as CrossAxisAlignment and direction) and aligns them vertically and horizontally respectively. A Container takes a combination of layout and styling properties. A Center widget centers its child widget tree.

For example, if you want to arrange your components in a Column. In React Native, you would specify it as a prop: flexDirection: “column”. But in Flutter, you would use a Column widget and provide the required children widgets.

// Flutter
new Center(
  child: new Column(
    children: <Widget>[
      new Container(
        color: Colors.red,
        width: 100.0,
        height: 100.0,
      ),
      new Container(
        color: Colors.blue,
        width: 100.0,
        height: 100.0,
      ),
      new Container(
        color: Colors.green,
        width: 100.0,
        height: 100.0,
      ),
    ],
  ),
)

Other layout widgets available are Padding, Align, Stack.

For more information, see the documentation for the layout widgets.

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and its equivalent React Native code.

How do I overlap several widgets on top of one another?

In React Native, we can overlap several components by using absolute positioning.

Flutter uses the Stack widget to arrange children widgets on top of each other. The widgets can entirely or partially overlap the base widget.

The Stack widget positions its children relative to the edges of its box. This class is useful if you simply want to overlap several children.

// Flutter
new Stack(
  alignment: const Alignment(0.6, 0.6),
  children: <Widget>[
    new CircleAvatar(
      backgroundImage: new NetworkImage(
        "https://avatars3.githubusercontent.com/u/14101776?v=4"),
    ),
    new Container(
      decoration: new BoxDecoration(
          color: Colors.black45,
      ),
      child: new Text('Flutter'),
    ),
  ],
)

The above example uses Stack to overlay a Container (that displays its Text on a translucent black background) on top of a CircleAvatar. The Stack offsets the text using the alignment property and Alignments.

Preview

Android iOS
Loading Loading


Styling

How to custom style my components in Flutter?

In React Native, we can use inline styling as well as stylesheets.create.

// React Native
<View style={styles.container}>
  <Text style={{ fontSize: 32, color: "cyan", fontWeight: "600" }}>
    This is a sample text
  </Text>
</View>
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center"
  }
});

Similarly in Flutter, widgets are highly customizable and layout specific components like Padding, Center, Card, Stack etc. can be used. A Text widget can take a TextStyle class for its style property. If you want to use same text style at multiple places, you can create a TextStyle class and use it for multiple Text widgets.

// Flutter
var textStyle = new TextStyle(fontSize: 32.0, color: Colors.cyan, fontWeight: FontWeight.w600);
	...
new Center(
  child: new Column(
    children: <Widget>[
      new Text(
        'Sample text',
        style: textStyle,
      ),
      new Padding(
        padding: new EdgeInsets.all(20.0),
        child: new Icon(Icons.lightbulb_outline,
          size: 48.0, color: Colors.redAccent)
      ),
    ],
  ),
)

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and its equivalent React Native code.

How to use Icons and Colors in Flutter?

There is no inbuilt support for icons in React Native, so third party libraries have to be used. Flutter has inbuilt support for Material icons as well as Cupertino (iOS-like) icons. To use Material icons, Icons class is used. To use Cupertino icons, make sure you add a dependency on cupertino_icons in your project’s pubspec.yaml file.

Here is the list of all Material icons.

For Colors, Colors class is used which uses Material design’s color palette.

new Icon(Icons.lightbulb_outline, color: Colors.redAccent)

How to add style themes in Flutter?

In React Native, we define common themes for components in stylesheets and use it in components. Similarly, in Flutter we can add uniform styling for almost everything by defining it in the ThemeData class and passing it to the theme property in MaterialApp that wraps all the widgets and acts as the root widget of the app.

@override
Widget build(BuildContext context) {
  return new MaterialApp(
    theme: new ThemeData(
      primaryColor: Colors.cyan,
      brightness: Brightness.dark,
    ),
    home: new StylingPage(),
  );
}

A Theme can be applied even without using the MaterialApp widget. The Theme widget takes a ThemeData in it’s data parameter and applies the ThemeData to all of it’s children widgets. The usage is as shown below:

@override
 Widget build(BuildContext context) {
   return new Theme(
     data: new ThemeData(
       primaryColor: Colors.cyan,
       brightness: brightness,
     ),
     child: new Scaffold(
        backgroundColor: Theme.of(context).primaryColor,
             ...
             ...
     ),
   );
 }

State Management

What are Stateful and Stateless widgets and how do I use them?

In React Native, we do not have state-specific components, you can call setState in any component provided it manages that state.

// React Native
export default class BlinkApp extends Component {

  constructor(props) {
    super(props);
    this.state = {
      buttonText: "blink",
      showText: true,
      text: "I love blinking"
    };
    this.toggleBlinkState = this.toggleBlinkState.bind(this);
    var handle;
  }
  
  toggleBlinkState() {
    if (this.state.buttonText == "blink") {
      handle = setInterval(() => {
        this.setState(previousState => {
          return { showText: !previousState.showText };
        });
      }, 1000);
      this.setState({
        buttonText: "Stop blinking"
      });
    } else {
      clearInterval(handle);
      this.setState({ buttonText: "blink", showText: true });
    }
  }

  render() {
    let display = this.state.showText ? this.state.text : " ";
    return (
      <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
        <StatusBar hidden={true} />
        <Text>{display} </Text>
        <Button onPress={this.toggleBlinkState} title={this.state.buttonText} />
      </View>
    );
  }
}

In Flutter, we have Stateful and Stateless widgets and you can use setState only in a StatefulWidget.

Stateless Widget

A widget which has no internal state to manage is a Stateless widget. Icons, IconButton, and Text are examples of stateless widgets, which subclass StatelessWidget. Stateless widgets are useful when the part of the user interface you are describing does not depend on anything other than the configuration information in the object itself and the BuildContext in which the widget is inflated.

// Flutter
import 'package:flutter/material.dart';

void main() => runApp(new MyStatelessWidget(text: "StatelessWidget Example to show immutable data"));

class MyStatelessWidget extends StatelessWidget {
  final String text;
  MyStatelessWidget({Key key, this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text(
        text,
        textDirection: TextDirection.ltr,
      ),
    );
  }
}

In the above example, you will use the constructor of the MyStatelessWidget class to pass the text, which is marked as final. Because this class extends StatelessWidget it can have immutable data.

The build method of a stateless widget is typically only called in three situations:

  • When the widget is inserted into the tree
  • When the widget’s parent changes its configuration
  • When an InheritedWidget it depends on changes.

Stateful Widget

A Stateful widget is a widget that has mutable state. A State is information that can be read synchronously when the widget is built and might change during the lifetime of the widget. It is the responsibility of the widget implementer to ensure that the State is promptly notified when such state changes, StatefulWidget is useful when the part of the user interface you are describing can change dynamically. The state of the widget changes when a user interacts with a Stateful widget (by typing into a form, or moving a slider, for example), or when it changes over time (perhaps a data feed causes the UI to update). Checkbox, Radio, Slider, InkWell, Form, and TextField are examples of stateful widgets, which subclass StatefulWidget.

The code snippet below shows how to define a stateful widget and use createState to create a state of the MyStatefulWidget widget.

class MyStatefulWidget extends StatefulWidget {
  MyStatefulWidget({Key key, this.title}) : super(key: key);
  final String title;
  
  @override
  _MyStatefulWidgetState createState() => new _MyStatefulWidgetState();
}

The following code snippet shows how the state implements the build function and also how the setState function is used to rebuild (call the build function of the stateful _MyStatefulWidgetState widget). A Timer is used to periodically call toggleShowText() that uses a setState() to set showText and rebuild.

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  bool showtext=true;
  bool toggleState=true;
  Timer t2;
  
  void toggleBlinkState(){
    setState((){ 
      toggleState=!toggleState;
    });
    var twenty = const Duration(milliseconds: 1000);
    if(toggleState==false) {
      t2 = new Timer.periodic(twenty, (Timer t) {
        toggleShowText();
      });
    } else {
      t2.cancel();
    }
  }
  
  void toggleShowText(){
    setState((){
      showtext=!showtext;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
        child: new Column(
          children: <Widget>[
            (showtext
              ?(new Text('This execution will be done before you can blink.'))
              :(new Container())
            ),
            new Padding(
              padding: new EdgeInsets.only(top: 70.0),
              child: new RaisedButton(
                onPressed: toggleBlinkState,
                child: (toggleState
                  ?( new Text("Blink")) 
                  :(new Text("Stop Blinking"))
                )
              )
            )
          ],
        ),
      ),
    );
  }
}

What are some of the best practices while using Stateful and Stateless widgets?

1. Figure out which widgets must be Stateful and Stateless

Widgets in Flutter can be Stateful or Stateless, depending on whether they depend on some state. If a widget changes—the user interacts with it, it’s Stateful; otherwise it can be Stateless. Stateful widgets are useful when the part of the user interface you are describing can change dynamically.

2. If using Stateful widget, decide which object manages the widget’s state.

There are three main ways to manage state:

  • The widget manages its own state.
  • The parent manages the widget’s state.
  • A mix-and-match approach

How do you decide which approach to use? The following principles should help you decide:

  • If the state in question is user data, for example the checked or unchecked mode of a checkbox, or the position of a slider, then the state is best managed by the parent widget.
  • If the state in question is aesthetic, for example an animation, then the widget itself best manages the state.
  • When in doubt, let the parent widget manage the child widget’s state.

3. Subclass StatefulWidget and State.

The MyStatefulWidget class manages its own state, so it overrides createState() to create the State object. The framework calls createState() when it wants to build the widget. In this example, createState() creates an instance of _MyStatefulWidgetState , which is implemented in the next step.

class MyStatefulWidget extends StatefulWidget {
  MyStatefulWidget({Key key, this.title}) : super(key: key);
  final String title;
  
  @override
  _MyStatefulWidgetState createState() => new _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  
  @override
  Widget build(BuildContext context) {
    ...
  }
}

4. Plug the stateful widget into the widget tree.

Add your custom stateful widget to the widget tree in the app’s build method.

class MyStatelessWidget extends StatelessWidget {
  // This widget is the root of your application.
  
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyStatefulWidget(title: 'State Change Demo'),
    );
  }
}

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and its equivalent React Native code.

Props

In React Native, most components can be customized when they are created with different parameters. These creation parameters are called props. These parameters can be used in child component using this.props.

// 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>
    );
  }
}
class App extends React.Component {
  
  onPress = index => {
    console.log("Card ", index);
  };
  
  render() {
    return (
      <View>
        <FlatList
          data={[ ... ]}
          renderItem={({ item }) => (
            <CustomCard onPress={this.onPress} index={item.key} />
          )}
        />
      </View>
    );
  }
}

In Flutter, you would just assign a local variable or function marked final with the prop received in the parameterised constructor and use it in the subsequent code.

// Flutter
class CustomCard extends StatelessWidget {

  CustomCard({@required this.index, @required this.onPress});
  final index;
  final Function onPress;
  
  @override
  Widget build(BuildContext context) {
  return new Card(
    child: new Column(
      children: <Widget>[
        new Text('Card $index'),
        new FlatButton(
          child: const Text('Press'),
          onPressed: this.onPress,
        ),
      ],
    ));
  }
}
    ...
//Usage
new CustomCard(
  index: index,
  onPress: () {
    print('Card $index');
  },
)

Preview

Android iOS
Loading Loading

Note: You can check the working code in Flutter and its equivalent React Native code.

Local Storage

How do I store persistent key-value pairs that are global to the app in Flutter?

In React Native, you would use the setItem and getItem functions of the AsyncStorage component to store and retrieve data that is persistent and global to the whole app.

// React Native
await AsyncStorage.setItem( "counterkey", JSON.stringify(++this.state.counter));
AsyncStorage.getItem("counterkey").then(value => {
  if (value != null) {
    this.setState({ counter: value });
  }
});

In Flutter, we use shared_preferences. It is first given as a dependency in the pubspec.yaml as shown:

dependencies:
  flutter:
    sdk: flutter
  shared_preferences: "^0.3.0"

It is then imported in the file where the instance of the shared_preference resides.

import 'package:shared_preferences/shared_preferences.dart';

An instance is obtained and used to perform operations such as storing and retrieving data.

SharedPreferences prefs = await SharedPreferences.getInstance();
_counter=prefs.getInt('counter');
prefs.setInt('counter',++_counter);
setState(() {
  _counter=_counter;
});

Routing

How do I navigate between screens in Flutter?

In React Native, there are three main built-in navigators, if you are using react-navigation– StackNavigator, TabNavigator, and DrawerNavigator. Each of these provides a way to configure and define the screens. From the example, this code snippet shows the definition of each of the navigators :

// React Native
const MyApp = TabNavigator(
  { Home: { screen: HomeScreen }, Notifications: { screen: tabNavScreen } },
  { tabBarOptions: { activeTintColor: "#e91e63" } }
);
const SimpleApp = StackNavigator({
  Home: { screen: MyApp },
  stackScreen: { screen: StackScreen }
});
export default (MyApp1 = DrawerNavigator({
  Home: {
    screen: SimpleApp
  },
  Screen2: {
    screen: drawerScreen
  }
}));

In Flutter, there are two main concepts to understand– A Route is an abstraction for a “screen” or “page” of an app and a Navigator is a widget that manages routes. A Navigator is defined as a widget that manages a set of child widgets with a stack discipline. The navigator manages a stack of Route objects and provides methods for managing the stack, like Navigator.push and Navigator.pop. Initially, the definition of the routes is provided as a parameter(routes) to the MaterialApp widget. A code snippet from our example is as follows :

// Flutter
class NavigationApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
            ...
      routes: <String, WidgetBuilder>{
        '/a': (BuildContext context) => new usualNavscreen(),
        '/b': (BuildContext context) => new drawerNavscreen(),
      }
            ...
  );
  }
}

To navigate to a named route, the of method of the Navigator widget is used to specify the BuildContext (a handle to the location of a widget in the widget tree) and the name of the route is passed to pushNamed function to navigate to the specifed route as shown below:

Navigator.of(context).pushNamed('/a');

One can also use the push method of Navigator which adds the given route to the history of the navigator that most tightly encloses the given context, and transitions to it. In the following example we are using the MaterialPageRoute widget, which is a modal route that replaces the entire screen with a platform-adaptive transition. It takes a WidgetBuilder as a required parameter.

Navigator.push(context, new MaterialPageRoute(builder: (BuildContext context) => new UsualNavscreen()));

How do I use Tab Navigation and Drawer Navigation in Flutter?

In React Native, we define Tab and Drawer navigators and use them to show tabs and drawers, and navigate.

In Flutter, we make use of several lower-level widgets such as Drawer which is basically a material design panel that slides in horizontally and TabBar, TabBarView to show and navigate among Tabs. These lower-level widgets are used in combination with higher-level widget Scaffold which implements them internally. The drawer and bottomNavigationBar parameters of the Scaffold are provided with the above mentioned lower-level widgets.

Tab Navigation

In React Native, we can use TabNavigation. A code snippet from our example is as follows:

// React Native
const MyApp = TabNavigator(
  { Home: { screen: HomeScreen }, Notifications: { screen: tabNavScreen } },
  { tabBarOptions: { activeTintColor: "#e91e63" } }
);

In Flutter, we need to use two main widgets - TabBar and TabBarView. A TabBar Widget is used to create a TabBar and Tab widgets are passed as children to the TabBar widget as shown below:

// Flutter
TabController controller=new TabController(length: 2, vsync: this);

new TabBar(
  tabs: <Tab>[
    new Tab(icon: new Icon(Icons.person),),
    new Tab(icon: new Icon(Icons.email),),
  ],
  controller: controller,
),

Also, a TabController must be passed. A TabController coordinates tab selection between a TabBar and a TabBarView. The length argument of the TabController’s constructor is the total number of tabs. Typically greater than one. vsync is the TickerProvider that can be used. TickerProvider is an interface implemented by classes that can vend Ticker objects. Tickers can be used by any object that wants to be notified whenever a frame triggers, but are most commonly used indirectly via an AnimationController. AnimationControllers need a TickerProvider to obtain their Ticker. If you are creating an AnimationController from a State, then you can use the TickerProviderStateMixin or SingleTickerProviderStateMixin classes to obtain a suitable TickerProvider.

TabBarView widget is passed as the body parameter of the Scaffold widget. All the screens corresponding to the TabBar widget’s tabs are given as children to TabBarView widget along with the same TabController as shown:

// Flutter

class _NavigationHomePageState extends State<NavigationHomePage> with SingleTickerProviderStateMixin {
  TabController controller=new TabController(length: 2, vsync: this);
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      bottomNavigationBar: new Material (
        child: new TabBar(
          tabs: <Tab> [
            new Tab(icon: new Icon(Icons.person),)
            new Tab(icon: new Icon(Icons.email),),
          ],
          controller: controller,
        ),
        color: Colors.blue,
      ),
      body: new TabBarView(
        children: <Widget> [
          new home.homeScreen(),
          new tabScreen.tabScreen()
        ],
        controller: controller,
      )
    );
  }
}

Drawer navigation

In React Native, we can use DrawerNavigation like this:

// React Native
export default (MyApp1 = DrawerNavigator({
  Home: {
    screen: SimpleApp
  },
  Screen2: {
    screen: drawerScreen
  }
}));

In Flutter, we make use of a Drawer widget which is a material design panel that slides in horizontally from the edge of a Scaffold to show navigation links in an application. You can provide a Button, a Text widget or a List of items to display as the child to the Drawer widget. In our example here, we have used a ListTile widget and provided navigation on tap.

// Flutter
new Drawer(
  child:new ListTile(
    leading: new Icon(Icons.change_history),
    title: new Text('Screen2'),
    onTap: () {
      Navigator.of(context).pushNamed("/b");
    },
  ),
  elevation: 20.0,
),

Drawers are typically used with the Scaffold.drawer property. The AppBar automatically displays an appropriate IconButton to show the Drawer when a Drawer is available in the Scaffold. The Scaffold automatically handles the edge-swipe gesture to show the drawer.

// Flutter
@override
Widget build(BuildContext context) {
  return new Scaffold(
    drawer: new Drawer(
      child: new ListTile(
        leading: new Icon(Icons.change_history),
        title: new Text('Screen2'),
        onTap: () {
          Navigator.of(context).pushNamed("/b");
        },
      ),
      elevation: 20.0,
    ),
    appBar: new AppBar(
      title: new Text("Home"),
    ),
    body: new Container(),
  );
}

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and its equivalent React Native code.

Gesture Detection and Touch Event Handling

How do I add a click/press listeners to a widget in Flutter?

In React Native, we can add various listeners to components using Touchables component or use PanResponder.

// React Native
<TouchableOpacity
  onPress={() => {
    console.log("Press");
  }}
  onLongPress={() => {
    console.log("Long Press");
  }}
>
  <Text>Tap or Long Press</Text>
</TouchableOpacity>

For more complex gestures and combining several touches into a single gesture, we use PanResponders in React Native.

// React Native
class App extends Component {

  componentWillMount() {
    this._panResponder = PanResponder.create({
      onMoveShouldSetPanResponder: (event, gestureState) =>
        !!getDirection(gestureState),
      onPanResponderMove: (event, gestureState) => true,
      onPanResponderRelease: (event, gestureState) => {
        const drag = getDirection(gestureState);
      },
      onPanResponderTerminationRequest: (event, gestureState) => true
    });
  }
  
  render() {
    return (
      <View style={styles.container} {...this._panResponder.panHandlers}>
        <View style={styles.center}>
          <Text>Swipe Horizontally or Vertically</Text>
        </View>
      </View>
    );
  }
}

In Flutter, one way to achieve this is using buttons or touchable widgets which have onPress parameters. Another way is by wrapping widgets in a GestureDetector widget which can add event detection to any widget by just passing the function in the respective callback.

// Flutter
new GestureDetector(
  child: new Scaffold(
    appBar: new AppBar(
      title: new Text("Gestures"),
    ),
    body: new Center(
      child: new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          new Text('Tap, Long Press, Swipe Horizontally or Vertically '),
        ],
      )
    ),
  ),
  onTap: () {
    print('Tapped');
  },
  onLongPress: () {
    print('Long Pressed');
  },
  onVerticalDragEnd: (DragEndDetails value) {
    print('Swiped Vertically');
  },
  onHorizontalDragEnd: (DragEndDetails value) {
    print('Swiped Horizontally');
  },
);

Here is the list of all Flutter GestureDetector callbacks.

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and its equivalent React Native code.

Making HTTP Networking Requests

How do I fetch data from API calls?

React Native provides the Fetch API for networking. You just have to make a fetch request and then handle the response to get the data.

// React Native
_getIPAddress = () => {
  fetch("https://httpbin.org/ip")
    .then(response => response.json())
    .then(responseJson => {
      this.setState({ _ipAddress: responseJson.origin });
    })
    .catch(error => {
      console.error(error);
    });
};

A similar flow is followed in Flutter but it uses the dart:io core HTTP support, so to create an HTTP Client we need to add an import.

import 'dart:io';

The client supports HTTP operations, such as GET, POST, PUT, DELETE.

// Flutter
final url = new Uri.https('httpbin.org', 'ip');
final httpClient = new HttpClient();
_getIPAddress() async {
  var request = await httpClient.getUrl(url);
  var response = await request.close();
  var responseBody = await response.transform(UTF8.decoder).join();
  String ip = JSON.decode(responseBody)['origin'];
  setState(() {
    _ipAddress = ip;
  });
}

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and its equivalent React Native code.

Form Input

How do I use TextInput field in Flutter?

In React Native, typically you would use a TextInput component to show a text input box and use the callback to store the value in a variable.

// React Native
<TextInput
  placeholder="Enter your Password"
  onChangeText={password => this.setState({ password })}
 />
<Button title="Submit" onPress={this.validate} />

In Flutter, we use a TextEditingController to manage a TextField. Whenever the text field is modified, the controller notifies its listeners. Listeners can then read the text and selection properties to learn what the user has typed. You can access the text in TextField by the text property of the controller.

// Flutter
final TextEditingController _controller = new TextEditingController();
      ...
new TextField(
  controller: _controller,
  decoration: new InputDecoration(
    hintText: 'Type something', labelText: "Text Field "
  ),
),
new RaisedButton(
  child: new Text('Submit'),
  onPressed: () {
    showDialog(
      context: context,
        child: new AlertDialog(
          title: new Text('Alert'),
          content: new Text('You typed ${_controller.text}'),
        ),
     );
   },
 ),
)

In this example, when the user clicks on the submit button an alert dialog opens up and displays the current text entered in the text field. This is achieved by the use of an alertDialog widget that displays the alert message and the text from the TextField is accessed by the text property of the TextEditingController.

How do I use Forms in Flutter?

In Flutter, we use a Form widget, where TextFormField widgets along with the submit button are passed as children. The TextFormField widget has a parameter called onSaved which takes a callback and executes when the form is saved. A FormState object is used to save, reset, or validate each FormField that is a descendant of this Form. To obtain the FormState, you may use Form.of with a context whose ancestor is the Form, or pass a GlobalKey to the Form constructor and call GlobalKey.currentState.

final formKey = new GlobalKey<FormState>();

...

new Form(
  key:formKey,
  child: new Column(
    children: <Widget>[
      new TextFormField(
        validator: (value) => !value.contains('@') ? 'Not a valid email.' : null,
        onSaved: (val) => _email = val,
        decoration: const InputDecoration(
          hintText: 'Enter your email',
          labelText: 'Email',
        ),
      ),
      new RaisedButton(
        onPressed: _submit,
        child: new Text('Login'),
      ),
    ],
  ),
)

The following code snippet shows how Form.save() and formKey which is a GlobalKey is used to save the form on submit.

void _submit() {
  final form = formKey.currentState;
  if (form.validate()) {
    form.save();
    showDialog(
      context: context,
      child: new AlertDialog(
        title: new Text('Alert'),
        content: new Text('Email: $_email, password: $_password'),
      )
    );
  }
}

Preview

Android iOS
Loading Loading

Note: You can check out the working code for Flutter and React Native

Platform-specific code

When building a cross-platform app, you’ll want to re-use as much code as possible across platforms. Scenarios may arise where it makes sense for the code to be different. In React Native, separate implementation can be given at almost anywhere in the app code by recognizing the platform the app will run on. To get the target platform, you need to use this component :

// React Native
if (Platform.OS === "ios") {
  return "iOS";
} else if (Platform.OS === "android") {
  return "android";
} else {
  return "not recognised";
}

The same goes in Flutter,

// Flutter
if (Theme.of(context).platform == TargetPlatform.iOS) {
  return "iOS";
} else if (Theme.of(context).platform == TargetPlatform.android) {
  return "android";
} else if (Theme.of(context).platform == TargetPlatform.fuchsia) {
  return "fuchsia";
} else {
  return "not recognised ";
}

Debugging

How do I access the In-App Developer Menu?

In React Native, the developer menu can be accessed by shaking your device: ⌘D for the iOS Simulator or ⌘M for Android emulator.

In Flutter, if you are using an IDE, you can use its built-in tools. If you start your application using flutter run you can also access the menu by typing h in the terminal window, or type the following shortcuts:

Action Terminal Shortcut Debug functions/ properties
Widget hierarchy of the app w debugDumpApp()
Rendering tree of the app t debugDumpRenderTree()
Layers L debugDumpLayerTree()
Accessibility S (traversal order) or U (inverse hit test order) debugDumpSemantics()
To toggle the widget inspector i WidgetsApp. showWidgetInspectorOverride
To toggle the display of construction lines p debugPaintSizeEnabled
To simulate different operating systems o defaultTargetPlatform
To display the performance overlay P WidgetsApp. showPerformanceOverlay
To save a screenshot to flutter. png s  
To quit q  

How do I perform hot reload?

Instead of recompiling your app every time you make a change, you can reload your app instantly. The app is updated to reflect your change, and the current state of the app is preserved. In React Native, the shortcut is ⌘R for the iOS Simulator and tapping R twice on Android emulators. In Flutter, If you are using IntelliJ IDE or Android Studio, you can select Save All (⌘s/ctrl-s), or click the Hot Reload button on the toolbar. If you are running the app at the command line using flutter run, type r in the terminal window. You can also perform full restart by typing R in the terminal window.

Is there anything like Chrome Developer Tools in Flutter?

In Flutter, the Dart Observatory is used for debugging. If you have started your application using flutter run, you can open the Web page at the Observatory URL printed to the console (e.g., http://127.0.0.1:8100/). If you are using an IDE, you can also debug your application using its built-in debugger. The Observatory also supports profiling, examining the heap, observing executed lines of code, debugging memory leaks and memory fragmentation, etc. For more information, see the Observatory’s documentation.

The Flutter plugin v21 announced a new feature called “Flutter Inspector” for IntelliJ and Android Studio. The inspector makes it much easier to understand why your application is rendering the way it does. It allows you to:

  • View the UI structure of your app as a tree of widgets.
  • Select a point on your device or simulator and find the corresponding Widget that rendered those pixels.
  • View properties for individual widgets.
  • Generally, better understand layout issues.

The inspector view can be opened via View > Tool Windows > Flutter Inspector (it shows content only when an app is running). To inspect a specific widget, select the ‘Toggle inspect mode’ action in the toolbar, then click on the desired widget on the phone or simulator. The widget will be highlighted in your app’s UI, you’ll see the widget in the widget hierarchy in IntelliJ, and will be able to view the individual properties for that widget.

Note: For more details, see the documentation on debugging in Flutter.

Animations

For a great user experience, animations are essential. In React Native, we use Animated API to create animations. In Flutter, we use the Animation class and AnimationController class. Animation is an abstract class that understands its current value and its state (completed or dismissed). The AnimationController class lets you play an animation forward or in reverse, or stop animation and set the animation to a specific value.

How do I add a simple fade-in animation?

In the React Native example, we use an animated component FadeInView using Animated API. We define initial opacity state, final state, the duration over which transition happens. We add animation component inside Animated component, then we map the opacity state fadeAnim to the opacity of the Text component we want to animate. Then, finally, we start() the animation.

// React Native
class FadeInView extends React.Component {
  state = {
    fadeAnim: new Animated.Value(0) // Initial value for opacity: 0
  };
  componentDidMount() {
    Animated.timing(this.state.fadeAnim, {
      toValue: 1,
      duration: 10000
    }).start();
  }
  render() {
    return (
      <Animated.View style={{...this.props.style, opacity: this.state.fadeAnim }} >
        {this.props.children}
      </Animated.View>
    );
  }
}
    ...
<FadeInView>
  <Text> Fading in </Text>
</FadeInView>
    ...

In the equivalent Flutter example, we use an AnimationController object controller and specify the duration inside it. We animation is defined as a Tween which basically describes some interpolation between a beginning and ending value. We are using a FadeTransition widget where we have opacity property which is mapped to the animation object. The sole job of a Tween is to define a mapping from an input range to an output range. Then we start the animation using controller.forward(). We can perform other operations too using the controller. In the example, We are using the FlutterLogo inside the FadeTransition widget.

// Flutter
void main() {
  runApp(new Center(child: new LogoFade()));
}

class LogoFade extends StatefulWidget {
  _LogoFadeState createState() => new _LogoFadeState();
}

class _LogoFadeState extends State<LogoFade> with TickerProviderStateMixin {
  Animation animation;
  AnimationController controller;

  initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(milliseconds: 3000), vsync: this);
    final CurvedAnimation curve =
        new CurvedAnimation(parent: controller, curve: Curves.easeIn);
    animation = new Tween(begin: 0.0, end: 1.0).animate(curve);
    controller.forward();
  }

  Widget build(BuildContext context) {
    return new FadeTransition(
      opacity: animation,
      child: new Container(
        height: 300.0,
        width: 300.0,
        child: new FlutterLogo(),
      ),
    );
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

Preview

Android iOS
Loading Loading

Note: You can check the working code for Flutter and React Native.

How do I add swipe animation to Cards?

In React Native, you either use PanResponder or third-party libraries for swipe animation. In Flutter, we can achieve this animation by using the Dismissible widget and nest the child widgets.

child: new Dismissible(
  key: key,
  onDismissed: (DismissDirection dir) {
    cards.removeLast();
  },
  child: new Container(
    ...
  ),
),

Preview

Android iOS
Loading Loading

Note: Here is the working code.

CheatSheet

React Native Component Flutter Widget Description
Button Raised Button A basic button that should render nicely on any platform.
  onPress [required] The callback that is called when the button is tapped or otherwise activated.
  Child (A Text widget is used) Text to display inside the button
     
Button Flat Button A basic material design button
  onPress [required] A callback that is called when the button is tapped or otherwise activated.
  Child (A Text widget is used) Text to display inside the button
     
ScrollView ListView A scrollable list of widgets arranged linearly.
  children ( <Widget> []) List of child widgets to display.
  controller [ Scroll Controller ] An object that can be used to control the position to which this scroll view is scrolled.
  itemExtent [ double ] If non-null, forces the children to have the given extent in the scroll direction.
  scroll Direction [ Axis ] The axis along which the scroll view scrolls.
     
FlatList ListView. builder() Constructor for linear array of widgets that are created on demand.
  itemBuilder [required] [ Indexed Widget Builder] helps in building the children on demand. This callback will be called only with indices greater than or equal to zero and less than itemCount.
  itemCount [ int ] It improves the ability of the ListView to estimate the maximum scroll extent.
     
Image Image A widget that displays an image.
  image [required] The image to display.
  Image. asset Several constructors are provided for the various ways that an image can be specified.
  width, height, color, alignment Style and Layout for the Image
  fit Inscribing the image into the space allocated during layout.
     
Modal ModalRoute A route that blocks interaction with previous routes.
  animation The animation that drives the route’s transition and the previous route’s forward transition.
     
Activity Indicator Circular Progress Indicator A widget that shows progress along a circle.
  strokeWidth The width of the line used to draw the circle.
  backgroundColor The progress indicator’s background color. The current theme’s ThemeData. backgroundColor by default.
     
Activity Indicator Linear Progress Indicator A widget that shows progress along a circle.
  value the value of this progress indicator
     
Refresh Control Refresh Indicator A widget that supports the Material “swipe to refresh” idiom.
  color The progress indicator’s foreground color.
  onRefresh A function that’s called when the user has dragged the refresh indicator far enough to demonstrate that they want the app to refresh.
     
View Container Surrounds child widget.
     
View Column displays its children in a vertical array
     
View Row displays its children in a horizontal array
     
View Center centers its child within itself.
     
View Padding insets its child by the given padding.
  padding [required] [ EdgeInsets ] amount of space by which to inset the child.
     
Touchable Opacity Gesture Detector detects gestures
  onTap callback when tap occurs
  onDoubleTap callback when tap occurs
     
Text Input Text Input interface to the system’s text input control
  controller [ Text Editing Controller ] to access and modify text.
     
Text Text A run of text with a single style.
  data [ String ] The text to display.
  textDirection [ Text Align ] How the text should be aligned horizontally.
     
Switch Switch A material design switch.
  value [required] [ boolean ] Whether this switch is on or off
  onChanged [required] [ callback ] Called when the user toggles the switch on or off
     
Slider Slider Used to select from a range of values.
  value [required] [ double ] current value of slider
  onChanged [required] Called when the user selects a new value for the slider