本文介绍Flutter的用户交互方式和路由操作,以及简单的主题切换操作。
我们将为上篇文章Flutter控件篇(Stateful widget)——ListView添加心形 ❤️图标,为这个图标加入点击收藏的功能。然后增加交互,当用户点击列表中的条目,切换其”收藏”状态,并将该词对添加到或移除出”收藏夹”。
添加一个_saved Set(集合),到 RandomWordsState,这个集合存储用户喜欢(收藏)的单词对。 在这里,Set 比 List 更合适,因为 Set 中不允许重复的值。
class RandomWordsState extends State<RandomWords> {
final List _suggetions = [];
final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
// 添加一个 _saved Set(集合),存储用户喜欢(收藏)的单词对。不要用 List ,因为 Set 中不允许重复的值。
final Set _saved=new Set();
……
}
在_buildRow方法中添加alreadySaved来检查确保单词对还没有添加到收藏夹中。
Widget _buildRow(WordPair pair){
// 添加 alreadySaved 来检查确保单词对还没有添加到收藏夹中
final bool alreadySaved=_saved.contains(pair);
}
同时在_buildRow()中, 添加一个心形 ❤️图标到 ListTiles以启用收藏功能。接下来,我们就可以给心形 ❤️图标添加交互能力了。
Widget _buildRow(WordPair pair){
// 添加 alreadySaved 来检查确保单词对还没有添加到收藏夹中
final bool alreadySaved=_saved.contains(pair);
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
//在 _buildRow() 中, 添加一个心形 ❤️图标到 ListTiles以启用收藏功能。接下来,你就可以给心形 ❤️图标添加交互能力了。
trailing: new Icon(
alreadySaved?Icons.favorite:Icons.favorite_border,
color: alreadySaved?Colors.red:null,
),
}
至此,我们给列表的每一项都添加了心形图片,接下来就要给他们添加交互功能
我们将为刚刚的心形 ❤️图标增加交互,当用户点击列表中的条目,切换其”收藏”状态,并将该词对添加到或移除出”收藏夹”。
我们在_buildRow中让心形 ❤️图标变得可以点击。如果单词条目已经添加到收藏夹中, 再次点击它将其从收藏夹中删除。当心形 ❤️图标被点击时,函数调用setState()通知框架状态已经改变。
Widget _buildRow(WordPair pair){
// 添加 alreadySaved 来检查确保单词对还没有添加到收藏夹中
final bool alreadySaved=_saved.contains(pair);
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
// 在 _buildRow() 中, 添加一个心形 ❤️图标到 ListTiles以启用收藏功能。接下来,你就可以给心形 ❤️图标添加交互能力了。
trailing: new Icon(
alreadySaved?Icons.favorite:Icons.favorite_border,
color: alreadySaved?Colors.red:null,
),
// 为心形增加点击方法
onTap: (){
setState((){//在 Flutter 的响应式风格的框架中,调用 setState() 会为 State 对象触发 build() 方法,从而导致对 UI 的更新
if(alreadySaved){
_saved.remove(pair);
}else{
_saved.add(pair);
}
});
},
);
}
我们成功的给心形图片添加的点击切换效果,热重载之后如下图所示:
在这一步中,我们将添加一个显示收藏夹内容的新页面(在 Flutter 中称为路由[route])。我们将您将在主路由和新路由之间导航(切换页面)。
在 Flutter 中,导航器管理应用程序的路由栈。将路由推入(push)到导航器的栈中,将会显示更新为该路由页面。 从导航器的栈中弹出(pop)路由,将显示返回到前一个路由。
我们在 RandomWordsState 的build方法中为 AppBar 添加一个列表图标。当用户点击列表图标时,包含收藏夹的新路由页面入栈显示。
将该图标及其相应的操作添加到build方法中:
class RandomWordsState extends State<RandomWords> {
// 在 Dart 语言中使用下划线前缀标识符,会强制其变成私有。
final List _suggetions = [];
final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
// 添加一个 _saved Set(集合),存储用户喜欢(收藏)的单词对。不要用 List ,因为 Set 中不允许重复的值。
final Set _saved=new Set();
@override
Widget build(BuildContext context) {
// 使用 Scaffold 类实现基础的 Material Design 布局
return new Scaffold(
appBar: new AppBar(
title: const Text('Flutter APP Demo'),
// build 方法中为 AppBar 添加一个列表图标。当用户点击列表图标时,包含收藏夹的新路由页面入栈显示。
actions: [
//某些 widget 属性需要单个 widget(child),而其它一些属性,如 action,需要一组widgets(children),用方括号 [] 表示。
new IconButton(icon: const Icon(Icons.list), onPressed: _pushSaved),
],
),
body: _buildSuggestions(),
);
}
在RandomWordsState这个类里添加_pushSaved()方法《绿色部分》:
class RandomWordsState extends State<RandomWords> {
...
void _pushSaved() {
}
}
热重载应用,列表图标将会出现在导航栏中。现在点击它不会有任何反应,因为_pushSaved函数还是空的。
接下来,(当用户点击导航栏中的列表图标时)我们会建立一个路由并将其推入到导航管理器栈中。此操作会切换页面以显示新路由,新页面的内容会在 MaterialPageRoute 的builder属性中构建,builder是一个匿名函数。
void _pushSaved() {
Navigator.of(context).push(
);
}
接下来,添加 MaterialPageRoute 及其 builder。 现在,添加生成 ListTile 行的代码,ListTile 的divideTiles()方法在每个 ListTile 之间添加 1 像素的分割线。 该divided变量持有最终的列表项,并通过toList()方法非常方便的转换成列表显示。
-添加 MaterialPageRoute 及其 builder
void _pushSaved() {
// 添加 Navigator.push 调用,这会使路由入栈(本系列路由入栈均指推入到导航管理器的栈)
Navigator.of(context).push(
// 添加 MaterialPageRoute 及其 builder
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();
})
);
}
void _pushSaved() {
// 添加 Navigator.push 调用,这会使路由入栈(本系列路由入栈均指推入到导航管理器的栈)
Navigator.of(context).push(
// 添加 MaterialPageRoute 及其 builder
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,
),
);
})
);
}
热重载应用程序,点击列表项收藏一些项,点击列表图标,在新的 route(路由)页面中显示收藏的内容。Navigator(导航器)会在应用栏中自动添加一个”返回”按钮,无需调用Navigator.pop,点击后退按钮就会返回到主页路由。
在 MyApp 这个类里修改颜色:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter 下的List列表',
// 通过配置 ThemeData 类轻松更改应用程序的主题
theme: new ThemeData(
primaryColor: Colors.deepOrangeAccent,
),
home: new RandomWords(),
);
}
}