(两百一十二) 学习编写你的第一个 Flutter App 第二部分
前言:之前学习了第一部分,继续学习第二部分https://codelabs.flutter-io.cn/codelabs/first-flutter-app-pt2-cn/index.html#01. 向列表里添加图标在这部分,我们将为每一行添加一个心形的(收藏)图标,下一步你将能够为这个图标加入点击收藏的功能。添加一个 _saved Set(集合)到 RandomWordsS...
前言:之前学习了第一部分,继续学习第二部分https://codelabs.flutter-io.cn/codelabs/first-flutter-app-pt2-cn/index.html#0
代码:https://github.com/happyjiatai/Flutter
目录
1. 向列表里添加图标
在这部分,我们将为每一行添加一个心形的(收藏)图标,下一步你将能够为这个图标加入点击收藏的功能。
添加一个 _saved Set(集合)到 RandomWordsState,这个集合存储用户喜欢(收藏)的单词对。 在这里,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);
...
}
在 _buildRow 方法中添加 alreadySaved 来检查确保单词对还没有添加到收藏夹中。
Widget _buildRow(WordPair pair) {
final bool alreadySaved = _saved.contains(pair); // 新增本行
...
}
同时在 _buildRow() 中, 添加一个心形 ❤️图标到 ListTiles以启用收藏功能。接下来,你就可以给心形 ❤️图标添加交互能力了。
向列表添加图标,如下所示:
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,
), // ... 新增代码结束
);
}
热重载应用,你现在可以在每一行看到心形 ❤️图标️,但它们还没有交互。
连爱心图标都可以预制么,爱了爱了
2. 添加交互
在这部分,我们将为刚刚的心形 ❤️图标增加交互,当用户点击列表中的条目,切换其"收藏"状态,并将该词对添加到或移除出"收藏夹"。
为了做到这个,我们在 _buildRow 中让心形 ❤️图标变得可以点击。如果单词条目已经添加到收藏夹中, 再次点击它将其从收藏夹中删除。当心形 ❤️图标被点击时,函数调用 setState() 通知框架状态已经改变。
增加 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: () { // 增加如下 9 行代码...
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
}, // ... 一直到这里
);
}
提示: 在 Flutter 的响应式风格的框架中,调用 setState() 会为 State 对象触发 build() 方法,从而导致对 UI 的更新
热重载应用,你就可以点击任何一行测试收藏或取消收藏功能,你的点击同时自带 Material Design 里的水波动画特效。
其实就是添加点击事件
3. 导航到新页面
在这一步中,您将添加一个显示收藏夹内容的新页面(在 Flutter 中称为路由[route])。您将学习如何在主路由和新路由之间导航(切换页面)。
在 Flutter 中,导航器管理应用程序的路由栈。将路由推入(push)到导航器的栈中,将会显示更新为该路由页面。 从导航器的栈中弹出(pop)路由,将显示返回到前一个路由。
接下来,我们在 RandomWordsState 的 build 方法中为 AppBar 添加一个列表图标。当用户点击列表图标时,包含收藏夹的新路由页面入栈显示。
将该图标及其相应的操作添加到 build 方法中:
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(),
);
}
...
}
提示: 某些 widget 属性需要单个 widget(child),而其它一些属性,如 action,需要一组widgets(children),用方括号 [] 表示。
在 RandomWordsState 这个类里添加 _pushSaved() 方法:
class RandomWordsState extends State<RandomWords> {
...
// 新增代码开始
void _pushSaved() {
}
// 新增代码结束
}
热重载应用,列表图标(
)将会出现在导航栏中。现在点击它不会有任何反应,因为 _pushSaved 函数还是空的。
接下来,(当用户点击导航栏中的列表图标时)我们会建立一个路由并将其推入到导航管理器栈中。此操作会切换页面以显示新路由,新页面的内容会在 MaterialPageRoute 的 builder 属性中构建,builder 是一个匿名函数。
添加 Navigator.push 调用,这会使路由入栈(以后路由入栈均指推入到导航管理器的栈)
void _pushSaved() {
Navigator.of(context).push(
);
}
接下来,添加 MaterialPageRoute 及其 builder。 现在,添加生成 ListTile 行的代码,ListTile 的 divideTiles() 方法在每个 ListTile 之间添加 1 像素的分割线。 该 divided 变量持有最终的列表项,并通过 toList()方法非常方便的转换成列表显示。
添加如下所示的代码:
void _pushSaved() {
Navigator.of(context).push(
new MaterialPageRoute<void>( // 新增如下20行代码 ...
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,其中包含名为"Saved Suggestions"的新路由的应用栏。新路由的body 由包含 ListTiles 行的 ListView 组成;每行之间通过一个分隔线分隔。
添加水平分隔符,如下代码所示:
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( // 新增 6 行代码开始 ...
appBar: new AppBar(
title: const Text('Saved Suggestions'),
),
body: new ListView(children: divided),
); // ... 新增代码段结束.
},
),
);
}
热重载应用程序,点击列表项收藏一些项,点击列表图标(
),在新的 route(路由)页面中显示收藏的内容。Navigator(导航器)会在应用栏中自动添加一个"返回"按钮,无需调用Navigator.pop,点击后退按钮就会返回到主页路由。
4. 使用 Themes 修改 UI
这一部分,我们将会一起修改应用的主题。Flutter 里我们使用 theme 来控制你应用的外观和风格,你可以使用默认主题,该主题取决于物理设备或模拟器,也可以自定义主题以适应您的品牌。
你可以通过配置 ThemeData 类轻松更改应用程序的主题,目前我们的应用程序使用默认主题,下面将更改 primaryColor 颜色为白色。
在 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(),
);
}
}
热重载应用。 你会发现,整个背景将会变为白色,包括 app bar(应用栏)。
一个小练习,你可以看一下 ThemeData 的文档,添加其他属性来更多改变 UI 样式。Material library 中的 Colors 类提供了许多可以使用的颜色常量, 你可以使用热重载来快速简单地尝试、实验。
应该类似于Android的主题配置https://api.flutter.dev/flutter/material/ThemeData-class.html

我参考改了个黄色的=-=



5.总结
- 写了 Dart 代码
- 使用热重载加速了开发进程
- 实现了一个 stateful widget,为你的应用加入了交互功能
- 创建了一个新的页面(route),为主页和这个新页面的跳转加入了逻辑
- 学会了如何使用 themes 修改应用的 UI
我感觉是主要学习了列表的点击事件、actionbar的页面跳转和主题设置,学习了个新名词‘路由’
更多推荐



所有评论(0)