https://codelabs.developers.google.com/codelabs/first-flutter-app-pt2/#1
介绍
第二部分将学到啥
- 如何编写在iOS和Android上看起来很自然的Flutter应用程序。
- 使用热重载可以加快开发速度。
- 如何为有状态小部件(stateful widget)添加交互性。
- 如何创建和导航,并导航到到第二个屏幕。
- 如何使用主题更改应用程序的外观。
第二部分将构建什么
在part1教程的基础上,用户可以保存和取消保存名字。点击应用栏右上角的列表图标会导航到保存名称的新页面。
开发环境搭建
略
为列表添加图标
在此步骤中,您将为每行添加心形图标。在下一步中,您将使它们可以点击并保存收藏夹。
1). 将_saved Set添加到RandomWordsState。此Set存储用户收藏的单词配对。 Set优先于List,因为正确实现的Set不允许重复条目。
class RandomWordsState extends State<RandomWords> {
final List<WordPair> _suggestions = <WordPair>[];
final Set<WordPair> _saved = new Set<WordPair>();
final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
...
}
2). 在_buildRow
函数中,添加alreadySaved
检查单词是否收藏。
Widget _buildRow(WordPair pair) {
final bool alreadySaved = _saved.contains(pair);
...
}
在_buildRow()
中,您还将向ListTile对象添加心形图标以启用收藏。在下一步中,您将添加与心形图标交互的功能。
3). 添加icons,如下:
Widget _buildRow(WordPair pair) {
final bool 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,
),
);
}
添加交互
此步骤中,你将使得心形图标可以点击。当用户点击列表中的条目,将切换“收藏”状态,把单词从收藏集合中添加或删除。
为此,您将修改_buildRow函数。如果单词条目已添加到收藏夹,再次点击它会将其从收藏夹中删除。
当一个tile被轻击时,该函数调用setState()来通知框架状态已经改变。
1). 添加onTap
,如下:
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: () {
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
);
}
Tips:在Flutter的响应式(reactive)框架中,调用setState()
会触发对State对象的build()
方法的调用,从而更新UI页面。
导航到新页面
在此步骤中,您将添加一个显示收藏夹的新页面(flutter中称之为route)。您将学习如何在home route和新route之间导航(navigate )。
在Flutter中,Navigator管理包含应用程序路由的栈。将route推送到Navigator的栈,将显示更新为该route。从导航器的堆栈弹出route,将显示返回到上一个route(先进后出)。
接下来,您将在RandomWordsState的构建方法中向AppBar添加列表图标。当用户单击列表图标时,包含已保存收藏夹的新路径将被推送到Navigator器,显示图标。
1). 将图标及其相应的操作添加到构建方法:
class RandomWordsState extends State<RandomWords> {
...
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Startup Name Generator'),
actions: <Widget>[
new IconButton(icon: const Icon(Icons.list), onPressed: _pushSaved),
],
),
body: _buildSuggestions(),
);
}
...
}
注: 此处actions
对应的是Widget数组
2). 给RandomWordsState类添加_pushSaved()
函数
3). reload App,可以看到导航条右测的'列表'按钮,接下来是添加具体的响应事件。
4). 调用Navigator.push
,调用Navigator.push,如下所示,将route推送到Navigator的堆栈。 IDE会抱怨无效代码,但您将在下一节中解决此问题。
void _pushSaved() {
Navigator.of(context).push(
);
}
接下来,你会添加MaterialPageRoute以及它的构造器。现在,添加生成ListTile行的代码。
ListTile的divideTiles()方法在每个ListTile之间添加水平间距。divided变量保存最后一行,由便捷函数(convenience function,)转换为列表,toList()
。
5). 添加代码如下
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();
},
),
);
}
builder属性返回一个Scaffold,其中包含新路径的app bar,名为“Saved Suggestions”。
新路由的主体包含一个包含ListTiles行的ListView;每一行用分隔符分隔。
6). 添加分割线,如下:
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(
appBar: new AppBar(
title: const Text('Saved Suggestions'),
),
body: new ListView(children: divided),
);
},
),
);
}
7). hot reload此程序。收藏一些名称单词并点按应用栏中的列表图标,将会跳转到新的route。
新route显示包含收藏的单词对。请注意,导航器会在应用栏中添加“后退”按钮。您不必显式(explicitly)实现Navigator.pop方法。点击后退按钮返回到主route。
修改UI主题
在此步骤中,您将修改应用程序的主题。主题控制应用程序的外观。您可以使用默认主题(取决于物理设备或模拟器),也可以自定义主题以反映您的品牌(branding)。
您可以通过配置ThemeData类轻松更改应用程序的主题。此应用目前使用默认主题,但您将应用的主要颜色更改为白色。
1). 修改MyApp类中的颜色
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
theme: new ThemeData(
primaryColor: Colors.white,
),
home: new RandomWords(),
);
}
}
作为读者的练习,使用ThemeData来更改UI的其他方面。
Material库中的Colors类提供了许多可以使用的颜色常量,热重载使得用户界面快速简便地进行实验。
其他
学习Flutter SDK的其他东西:
更多资源包括:
Please reach out to us at our mailing list. We'd love to hear from you!