0% found this document useful (0 votes)
330 views

Google Flutter

This document provides instructions for creating a simple Flutter app that generates random startup company names. It introduces key Flutter concepts like stateless and stateful widgets. The app is built by: 1. Setting up the Flutter environment and creating an initial app template 2. Importing an external English words package to generate random names 3. Adding a stateful RandomWords widget to manage the randomly generated names 4. Moving the name generation logic from a stateless to the new stateful widget's state class

Uploaded by

ayi imaduddin
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
330 views

Google Flutter

This document provides instructions for creating a simple Flutter app that generates random startup company names. It introduces key Flutter concepts like stateless and stateful widgets. The app is built by: 1. Setting up the Flutter environment and creating an initial app template 2. Importing an external English words package to generate random names 3. Adding a stateful RandomWords widget to manage the randomly generated names 4. Moving the name generation logic from a stateless to the new stateful widget's state class

Uploaded by

ayi imaduddin
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 16

1.

Introduction
Flutter is Google's mobile SDK for crafting high-quality native interfaces on iOS and Android in
record time. Flutter works with existing code, is used by developers and organizations around the
world, and is free and open source.

In this codelab, you'll create a simple Flutter app. If you are familiar with object-oriented code and
basic programming concepts such as variables, loops, and conditionals, you can complete this
codelab. You don't need previous experience with Dart or mobile programming.

What you'll learn in part 1


 How to write a Flutter app that looks natural on both iOS and Android.
 Basic structure of a Flutter app.
 Finding and using packages to extend functionality.
 Using hot reload for a quicker development cycle.
 How to implement a stateful widget.
 How to create an infinite, lazily loaded list.

In part 2 of this codelab, you'll add interactivity, modify the app's theme, and add the ability to
navigate to a new page (called a route in Flutter).

What you'll build in part 1


You'll implement a simple mobile app that generates proposed names for a startup company. The
user can select and unselect names, saving the best ones. The code lazily generates ten names at a
time. As the user scrolls, new batches of names are generated. The user can scroll forever, with new
names being continually generated.

The animated GIF shows how the app works at the completion of part 1:

2. Set up your Flutter environment


You need two pieces of software to complete this lab: the Flutter SDK, and an editor. This codelab
assumes Android Studio, but you can use your preferred editor.

You can run this codelab using any of the following devices:

 A physical device (Android or iOS) connected to your computer and set to developer mode.
 The iOS simulator. (Requires installing XCode tools.)
 The Android emulator. (Requires setup in Android Studio.)
3. Create the initial Flutter app
Create a simple templated Flutter app, using the instructions in Getting Started with your first Flutter
app. Name the project startup_namer (instead of myapp). You'll be modifying this starter app to
create the finished app.

Tip: If you don't see "New Flutter Project" as an option in your IDE, make sure you have
the plugins installed for Flutter and Dart.

In these codelabs, you'll mostly be editing lib/main.dart, where the Dart code lives.

Replace the contents of lib/main.dart.


Delete all of the code from lib/main.dart. Replace with the following code, which displays "Hello
World" in the center of the screen.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: const Text('Welcome to Flutter'),
),
body: const Center(
child: const Text('Hello World'),
),
),
);
}
}

Tip: When pasting code into your app, indentation can become skewed. You can fix this
automatically with the Flutter tools:

 Android Studio / IntelliJ IDEA: Right-click the dart code and select Reformat Code with dartfmt.
 VS Code: Right-click and select Format Document.
 Terminal: Run flutter format <filename>.

Run the app. You should see either Android or iOS output, depending on your device.

Tip: The first time you run on a physical device, it can take awhile to load. After this, you can
use hot reload for quick updates. Save also performs a hot reload if the app is running.
Observations

 This example creates a Material app. Material is a visual design language that is standard on
mobile and the web. Flutter offers a rich set of Material widgets.
 The main method uses fat arrow (=>) notation, Use fat arrow notation for one-line functions
or methods.
 The app extends StatelessWidget, which makes the app itself a widget. In Flutter, almost
everything is a widget, including alignment, padding, and layout.
 The Scaffold widget, from the Material library, provides a default app bar, a title, and a body
property that holds the widget tree for the home screen. The widget subtree can be quite
complex.
 A widget's main job is to provide a build method that describes how to display the widget in
terms of other, lower-level widgets.
 The body for this example consists of a Center widget containing a Text child widget. The
Center widget aligns its widget subtree to the center of the screen.

4. Use an external package


In this step, you'll start using an open-source package named english_words, which contains a few
thousand of the most used English words plus some utility functions.

You can find the english_words package, as well as many other open source packages,
on pub.dartlang.org.

The pubspec file manages the assets for a Flutter app. In pubspec.yaml, append english_words:
^3.1.0(english_words 3.1.0 or higher) to the dependencies list:

dependencies:
flutter:
sdk: flutter

cupertino_icons: ^0.1.0
english_words: ^3.1.0 # add this line

While viewing the pubspec in Android Studio's editor view, click Packages get. This pulls the
package into your project. You should see the following in the console:

flutter packages get


Running "flutter packages get" in startup_namer...
Process finished with exit code 0

In lib/main.dart, import the new package:

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart'; // Add this line.

As you type, Android Studio gives you suggestions for libraries to import. It then renders the import
string in gray, letting you know that the imported library is unused (so far).
Next, you'll use the english_words package to generate the text instead of using the string "Hello
World".

Make the changes shown below:

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

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
final wordPair = new WordPair.random(); // Add this line.
return new MaterialApp(
title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center( // Change "const" to "new".
//child: const Text('Hello World'), // Replace this text...
child: new Text(wordPair.asPascalCase), // With this text.
),
),
);
}
}

Tip: "Pascal case" (also known as "upper camel case"), means that each word in the string,
including the first one, begins with an uppercase letter. So, "upper camel case" becomes
"UpperCamelCase".

If you didn't change Center to "new Center", the type system will warn that the Center object should
not be typed as a constant (const), because its child Text object is no longer a constant. Therefore,
both Center and Text must create instances using new.

If the app is running, use the hot reload button ( ) to update the running app. Each time you click
hot reload or save the project, you should see a different word pair, chosen at random, in the running
app. This is because the word pairing is generated inside the build method, which is run each time
the MaterialApp requires rendering, or when toggling the Platform in Flutter Inspector.

Problems?

If your app is not running correctly, look for typos. If needed, use the code at the following links to
get back on track.

 pubspec.yaml
 lib/main.dart
5. Add a stateful widget
Stateless widgets are immutable, meaning that their properties can't change—all values are final.

Stateful widgets maintain state that might change during the lifetime of the widget. Implementing a
stateful widget requires at least two classes: 1) a StatefulWidget class that creates an instance of 2)
a State class. The StatefulWidget class is, itself, immutable, but the State class persists over the
lifetime of the widget.

In this step, you'll add a stateful widget, RandomWords, which creates its State class,
RandomWordsState. You'll then use RandomWords as a child inside the existing MyApp stateless
widget.

Create a minimal state class. It can go anywhere in the file outside of MyApp, but the solution places
it at the bottom of the file. Add the following text:

class RandomWordsState extends State<RandomWords> {


// TODO Add build method
}

Notice the declaration State<RandomWords>. This indicates that we're using the generic State class
specialized for use with RandomWords. Most of the app's logic and state resides here—it maintains
the state for the RandomWords widget. This class saves the generated word pairs, which grows
infinitely as the user scrolls, and favorite word pairs (in part 2), as the user adds or removes them
from the list by toggling the heart icon.

RandomWordsState depends on the RandomWords class. You'll add that next.

Add the stateful RandomWords widget to main.dart. The RandomWords widget does little else
besides creating its State class:

class RandomWords extends StatefulWidget {


@override
RandomWordsState createState() => new RandomWordsState();
}

After adding the state class, the IDE complains that the class is missing a build method. Next, you'll
add a basic build method that generates the word pairs by moving the word generation code from
MyApp to RandomWordsState.

Add the build method to RandomWordsState, as shown below:

class RandomWordsState extends State<RandomWords> {


@override // Add from this line ...
Widget build(BuildContext context) {
final WordPair wordPair = new WordPair.random();
return new Text(wordPair.asPascalCase);
} // ... to this line.
}
Remove the word generation code from MyApp by making the changes below:

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
final WordPair wordPair = new WordPair.random(); // Delete this line.

return new MaterialApp(


title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
//child: new Text(wordPair.asPascalCase), // Change this line to...
child: new RandomWords(), // ... this line.
),
),
);
}
}

Hot reload the app. The app should behave as before, displaying a word pairing each time you hot
reload or save the app.

Tip: If you see the following warning on a hot reload, consider restarting the app:

Reloading...
Not all changed program elements ran during view reassembly; consider restarting.

It may be a false positive, but restarting ensures that your changes are reflected in the app's UI.

Problems?

If your app is not running correctly, you can use the code at the following link to get back on track.

 lib/main.dart

6. Create an infinite scrolling ListView


In this step, you'll expand RandomWordsState to generate and display a list of word pairings. As the
user scrolls, the list (displayed in a ListView widget) grows infinitely. ListView's builder factory
constructor allows you to build a list view lazily, on demand.

Add a _suggestions list to the RandomWordsState class for saving suggested word pairings. Also,
add a _biggerFont variable for making the font size larger.

Tip: Prefixing an identifier with an underscore enforces privacy in the Dart language.
class RandomWordsState extends State<RandomWords> {
// Add the next two lines.
final List<WordPair> _suggestions = <WordPair>[];
final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
...
}

Next, you'll add a _buildSuggestions() function to the RandomWordsState class. This method will
build the ListView that displays the suggested word pairing.

The ListView class provides a builder property, itemBuilder, that's a factory builder and callback
function specified as an anonymous function. Two parameters are passed to the function—the
BuildContext, and the row iterator, i. The iterator begins at 0 and increments each time the function
is called—once for every suggested word pairing. This model allows the suggestion list to grow
infinitely as the user scrolls.

Add the entire _buildSuggestions function, shown below, to the RandomWordsState class (delete the
comments, if you prefer):

Widget _buildSuggestions() {
return new ListView.builder(
padding: const EdgeInsets.all(16.0),
// The itemBuilder callback is called once per suggested
// word pairing, and places each suggestion into a ListTile
// row. For even rows, the function adds a ListTile row for
// the word pairing. For odd rows, the function adds a
// Divider widget to visually separate the entries. Note that
// the divider may be difficult to see on smaller devices.
itemBuilder: (BuildContext _context, int i) {
// Add a one-pixel-high divider widget before each row
// in the ListView.
if (i.isOdd) {
return new Divider();
}

// The syntax "i ~/ 2" divides i by 2 and returns an


// integer result.
// For example: 1, 2, 3, 4, 5 becomes 0, 1, 1, 2, 2.
// This calculates the actual number of word pairings
// in the ListView,minus the divider widgets.
final int index = i ~/ 2;
// If you've reached the end of the available word
// pairings...
if (index >= _suggestions.length) {
// ...then generate 10 more and add them to the
// suggestions list.
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
}
);
}
The _buildSuggestions function calls _buildRow once per word pair. This function displays each new
pair in a ListTile, which will allow you to make the rows more attractive in part 2.

Add a _buildRow function to RandomWordsState:

Widget _buildRow(WordPair pair) {


return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
}

Update the build method for RandomWordsState to use _buildSuggestions(), rather than directly
calling the word generation library. (Scaffold implements the basic Material Design visual layout.)

@override
Widget build(BuildContext context) {
//final wordPair = new WordPair.random(); // Delete these...
//return new Text(wordPair.asPascalCase); // ... two lines.

return new Scaffold ( // Add from here...


appBar: new AppBar(
title: new Text('Startup Name Generator'),
),
body: _buildSuggestions(),
); // ... to here.
}

Update the build method for MyApp, changing the title, and changing the home to be a
RandomWords widget.

@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
home: new RandomWords(),
);
}

Restart the app. You should see a list of word pairings, no matter how far you scroll.

Problems?

If your app is not running correctly, you can use the code at the following link to get back on track.

 lib/main.dart
7. Next steps
Congratulations!
You have completed part 1 of this codelab! If you'd like to extend this app, proceed to part 2, where
you will modify the app as follows:

 Add interactivity.
 Add the ability to navigate to a new route.
 Modify the theme color.

When part 2 is completed, the app will look like this:


1. Introduction
Flutter is Google's mobile SDK for crafting high-quality native interfaces on iOS and Android in
record time. Flutter works with existing code, is used by developers and organizations around the
world, and is free and open source.

In this codelab, you'll extend a basic Flutter app to include interactivity. You'll also create a second
page (called a route) that the user can navigate to. Finally, you'll modify the app's theme (color). This
codelab extends part 1, Create a Lazily Loaded List, but we'll provide the starting code, if you'd like
to start with part 2.

What you'll learn in part 2


 How to write a Flutter app that looks natural on both iOS and Android.
 Using hot reload for a quicker development cycle.
 How to add interactivity to a stateful widget.
 How to create and navigate to a second screen.
 How to change the look of an app using themes.

What you'll build in part 2


You'll start with a simple mobile app that generates an endless list of proposed names for a startup
company. By the end of this codelab, the user can select and unselect names, saving the best ones.
Tapping the list icon in the upper right of the app bar navigates to a new page (called a route) that
lists only the favorited names.

The animated GIF shows how the finished app works.

2. Set up your Flutter environment


If you haven't completed Part 1, see Set up Your Flutter Environment, in Write Your First Flutter App,
part 1, to set up your environment for Flutter development.

3. Get the Starting App


If you have worked through part 1 of this codelab, you already have the starting
app, startup_namer. You can proceed to the next step.

If you don't have startup_namer, no fear, you can get it using the following instructions.

Create a simple templated Flutter app using the instructions in Getting Started with your first Flutter
app. Name the project startup_namer (instead of myapp).
Delete all of the code from lib/main.dart. Replace with the code from this file, which displays an
infinite, lazily loaded list of proposed startup names.

Update pubspec.yaml by adding the English Words package, as shown below:

dependencies:
flutter:
sdk: flutter

cupertino_icons: ^0.1.0
english_words: ^3.1.0 // Add this line.

The English Words package generates pairs of random words, which are used as potential startup
names.

While viewing the pubspec in Android Studio's editor view, click Packages get upper right. This pulls
the package into your project. You should see the following in the console:

flutter packages get


Running "flutter packages get" in startup_namer...
Process finished with exit code 0

Run the app. Scroll as far as you want, viewing a continual supply of proposed startup names.

4. Add icons to the list


In this step, you'll add heart icons to each row. In the next step, you'll make them tappable and save
the favorites..

Add a _saved Set to RandomWordsState. This Set stores the word pairings that the user favorited.
Set is preferred to List because a properly implemented Set does not allow duplicate entries.

class RandomWordsState extends State<RandomWords> {


final List<WordPair> _suggestions = <WordPair>[];
final Set<WordPair> _saved = new Set<WordPair>(); // Add this line.
final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
...
}

In the _buildRow function, add an alreadySaved check to ensure that a word pairing has not already
been added to favorites.

Widget _buildRow(WordPair pair) {


final bool alreadySaved = _saved.contains(pair); // Add this line.
...
}

In _buildRow() you'll also add heart-shaped icons to the ListTile objects to enable favoriting. In the
next step, you'll add the ability to interact with the heart icons.
Add the icons, as shown below:

Widget _buildRow(WordPair pair) {


final bool alreadySaved = _saved.contains(pair);
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: new Icon( // Add the lines from here...
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
), // ... to here.
);
}

Hot reload the app. You should now see open hearts on each row, but they are not yet interactive.

5. Add interactivity
In this step, you'll make the heart icons tappable. When the user taps an entry in the list, toggling its
"favorited" state, that word pairing is added or removed from a set of saved favorites.

To do this, you'll modify the _buildRow function. If a word entry has already been added to favorites,
tapping it again removes it from favorites. When a tile has been tapped, the function
calls setState() to notify the framework that state has changed.

Add onTap, as shown below:

Widget _buildRow(WordPair pair) {


final alreadySaved = _saved.contains(pair);
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
onTap: () { // Add 9 lines from here...
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
}, // ... to here.
);
}
Tip: In Flutter's reactive style framework, calling setState() triggers a call to the build() method
for the State object, resulting in an update to the UI.

Hot reload the app. You should be able to tap any tile to favorite, or unfavorite, the entry. Tapping a
tile generates an implicit ink splash animation emanating from the tap point.

6. Navigate to a new screen


In this step, you'll add a new page (called a route in Flutter) that displays the favorites. You'll learn
how to navigate between the home route and the new route.

In Flutter, the Navigator manages a stack containing the app's routes. Pushing a route onto the
Navigator's stack, updates the display to that route. Popping a route from the Navigator's stack,
returns the display to the previous route.

Next, you'll add a list icon to the AppBar in the build method for RandomWordsState. When the user
clicks the list icon, a new route that contains the saved favorites is pushed to the Navigator,
displaying the icon.

Add the icon and its corresponding action to the build method:

class RandomWordsState extends State<RandomWords> {


...
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Startup Name Generator'),
actions: <Widget>[ // Add 3 lines from here...
new IconButton(icon: const Icon(Icons.list), onPressed: _pushSaved),
], // ... to here.
),
body: _buildSuggestions(),
);
}
...
}

Tip: Some widget properties take a single widget (child), and other properties, such as action,
take an array of widgets (children), as indicated by the square brackets ([]).

Add a _pushSaved() function to the RandomWordsState class.

void _pushSaved() {
}

Hot reload the app. The list icon ( ) appears in the app bar. Tapping it does nothing yet,
because the _pushSaved function is empty.
Next, you'll build a route and push it to the Navigator's stack. This action changes the screen to
display the new route. The content for the new page is built in MaterialPageRoute's builder property,
in an anonymous function.

Call Navigator.push, as shown below, which pushes the route to the Navigator's stack. The IDE will
complain about invalid code, but you will fix that in the next section.

void _pushSaved() {
Navigator.of(context).push(
);
}

Next, you'll add the MaterialPageRoute and its builder. For now, add the code that generates the
ListTile rows. The divideTiles() method of ListTile adds horizontal spacing between each ListTile.
The divided variable holds the final rows, converted to a list by the convenience function, toList().

Add the code, as shown below:

void _pushSaved() {
Navigator.of(context).push(
new MaterialPageRoute<void>( // Add 20 lines from here...
builder: (BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(WordPair pair) {
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final List<Widget> divided = ListTile
.divideTiles(
context: context,
tiles: tiles,
)
.toList();
},
), // ... to here.
);
}

The builder property returns a Scaffold, containing the app bar for the new route, named "Saved
Suggestions." The body of the new route consists of a ListView containing the ListTiles rows; each
row is separated by a divider.

Add horizontal dividers, as shown below:

void _pushSaved() {
Navigator.of(context).push(
new MaterialPageRoute<void>(
builder: (BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(WordPair pair) {
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final List<Widget> divided = ListTile
.divideTiles(
context: context,
tiles: tiles,
)
.toList();

return new Scaffold( // Add 6 lines from here...


appBar: new AppBar(
title: const Text('Saved Suggestions'),
),
body: new ListView(children: divided),
); // ... to here.
},
),
);
}

Hot reload the app. Favorite some of the selections and tap the list icon in the app bar. The new
route appears containing the favorites. Note that the Navigator adds a "Back" button to the app bar.
You did not have to explicitly implement Navigator.pop. Tap the back button to return to the home
route.

7. Change the UI using Themes


In this step, you'll modify the app's theme. The theme controls the look and feel of your app. You can
either use the default theme, which is dependent on the physical device or emulator, or customize
the theme to reflect your branding.

You can easily change an app's theme by configuring the ThemeData class. This app currently uses
the default theme, but you'll change the app's primary color to white.

Change the color in the MyApp class:

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
theme: new ThemeData( // Add the 3 lines from here...
primaryColor: Colors.white,
), // ... to here.
home: new RandomWords(),
);
}
}

Hot reload the app. The entire background is now white, even the app bar.

As an exercise for the reader, use ThemeData to change other aspects of the UI. The Colors class
in the Material library provides many color constants you can play with, and hot reload makes
experimenting with the UI quick and easy.

8. Well done!
You've written an interactive Flutter app that runs on both iOS and Android. In this codelab, you've:

 Written Dart code.


 Used hot reload for a faster development cycle.
 Implemented a stateful widget, adding interactivity to your app.
 Created a route and added logic for moving between the home route and the new route.
 Learned about changing the look of your app's UI using themes.

You might also like