Flutter互動篇——使用者互動,路由和主題切換實現
本文介紹Flutter的使用者互動方式和路由操作,以及簡單的主題切換操作。
我們將為上篇文章Flutter控制元件篇(Stateful widget)——ListView新增心形 ❤️圖示,為這個圖示加入點選收藏的功能。然後增加互動,當用戶點選列表中的條目,切換其”收藏”狀態,並將該詞對新增到或移除出”收藏夾”。
為列表新增心形 ❤️圖示
新增一個_saved Set(集合),到 RandomWordsState,這個集合儲存使用者喜歡(收藏)的單詞對。 在這裡,Set 比 List 更合適,因為 Set 中不允許重複的值。
class RandomWordsState extends State<RandomWords> {
final List<WordPair> _suggetions = <WordPair>[];
final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
// 新增一個 _saved Set(集合),儲存使用者喜歡(收藏)的單詞對。不要用 List ,因為 Set 中不允許重複的值。
final Set<WordPair> _saved=new Set<WordPair>();
……
}
在_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()通知框架狀態已經改變。
_buildRow中增加onTap方法》
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的路由)
在這一步中,我們將新增一個顯示收藏夾內容的新頁面(在 Flutter 中稱為路由[route])。我們將您將在主路由和新路由之間導航(切換頁面)。
在 Flutter 中,導航器管理應用程式的路由棧。將路由推入(push)到導航器的棧中,將會顯示更新為該路由頁面。 從導航器的棧中彈出(pop)路由,將顯示返回到前一個路由。
我們在 RandomWordsState 的build方法中為 AppBar 新增一個列表圖示。當用戶點選列表圖示時,包含收藏夾的新路由頁面入棧顯示。
將該圖示及其相應的操作新增到build方法中:
class RandomWordsState extends State<RandomWords> {
// 在 Dart 語言中使用下劃線字首識別符號,會強制其變成私有。
final List<WordPair> _suggetions = <WordPair>[];
final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
// 新增一個 _saved Set(集合),儲存使用者喜歡(收藏)的單詞對。不要用 List ,因為 Set 中不允許重複的值。
final Set<WordPair> _saved=new Set<WordPair>();
@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 屬性需要單個 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是一個匿名函式。
- 新增Navigator.push呼叫,這會使路由入棧(以後路由入棧均指推入到導航管理器的棧)
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,點選後退按鈕就會返回到主頁路由。
效果圖如下:
使用 Themes 修改 UI
- Flutter 裡我們使用theme來控制你應用的外觀和風格,你可以使用預設主題,該主題取決於物理裝置或模擬器,也可以自定義主題以適應您的品牌
- 可以通過配置ThemeData類輕鬆更改應用程式的主題,目前我們的應用程式使用預設主題,下面將更改 primaryColor 顏色為粉色。
在 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(),
);
}
}
熱過載應用。 你會發現,整個背景將會變為粉色,包括 app bar(應用欄)