昨天實作了「收藏」按鈕,每一次心動的點擊,都代表一則寶貴的靈感被我們珍藏起來~但問題來了:這些收藏的靈感去哪了?它們此刻正靜靜地躺在我們昨天建立的FavoriteProvider狀態裡,等著被看見。
一個只能存、不能看的收藏夾是沒有靈魂的,因此,今天我們的核心任務就是打造一個專屬的「收藏頁面」。這將會是使用者的靈感寶庫,一個可以隨時回來翻閱、回味這些知識靈感的地方。
這個過程中,將學習如何在Flutter中進行頁面跳轉 (Navigation),並親眼見證Riverpod跨頁面同步狀態的驚人威力。
第一步:建立收藏頁面UI骨架
在lib/presentation/目錄下,建立一個新檔案favorites_page.dart。
這個頁面需要讀取favoriteProvider的狀態,所以我們會將它建立為一個ConsumerWidget。它的基本結構包含一個頂部的AppBar和一個用於顯示列表的body。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 引入我們昨天建立的 favorite provider
import 'package:three_inspiration/features/favorite/favorite_provider.dart';
class FavoritesPage extends ConsumerWidget {
const FavoritesPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// 監聽收藏列表的狀態
final favoritedInsights = ref.watch(favoriteProvider);
return Scaffold(
appBar: AppBar(
title: const Text('我的收藏'),
),
body: favoritedInsights.isEmpty
// 如果列表為空,顯示提示訊息
? const Center(
child: Text(
'你還沒有收藏任何靈感喔!',
style: TextStyle(fontSize: 18, color: Colors.grey),
),
)
// 否則,使用 ListView.builder 顯示列表
: ListView.builder(
itemCount: favoritedInsights.length,
itemBuilder: (context, index) {
final insight = favoritedInsights[index];
// 這裡我們先用一個簡單的 ListTile
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: ListTile(
title: Text(insight.summary),
subtitle: Wrap(
spacing: 8.0,
children: insight.tags.map((tag) => Chip(label: Text(tag))).toList(),
),
),
);
},
),
);
}
}
程式碼解析:
第二步:實作頁面跳轉
頁面建好了,但要怎麼過去呢?首先,需要在主頁(HomePage)上加一個入口,最適合的位置就是AppBar的右上角。
回到lib/presentation/home_page.dart,修改_HomePageState的build方法,在Scaffold的appBar 參數中加入actions。
// 在 home_page.dart 檔案頂部引入 favorites_page.dart
import 'package:three_inspiration/presentation/favorites_page.dart';
// ... 在 _HomePageState 的 build 方法中 ...
@override
Widget build(BuildContext context) {
// ...
return Scaffold(
appBar: AppBar(
title: const Text('今日三則靈感'),
// 在 AppBar 右側加入一個 actions 列表
actions: [
IconButton(
icon: const Icon(Icons.collections_bookmark_outlined),
onPressed: () {
// 點擊後,導航到收藏頁面
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const FavoritesPage()),
);
},
),
],
),
body: // ...
);
}
Navigator.push是Flutter內建的導航方法,它會將一個新的頁面(我們用MaterialPageRoute包裝的 FavoritesPage)推入導航堆疊中,Flutter會自動處理轉場動畫和在AppBar左側顯示返回按鈕。
現在執行App,點擊主頁右上角的書籤圖示,應該就能順利跳轉到我們剛建立的收藏頁面了!
第三步:優化收藏卡片與互動
一個只能看的列表是不夠的,還需要能互動,現在來實作「取消收藏」的功能。
回到favorites_page.dart,將ListTile變得更豐富一些,加入一個刪除按鈕。
// ... 在 ListView.builder 的 itemBuilder 中 ...
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: ListTile(
title: Text(insight.summary),
subtitle: Padding(
padding: const EdgeInsets.only(top: 8.0),
// 根據 Wireframe,為未來的筆記功能預留空間
child: Text(
'點此新增筆記...',
style: TextStyle(color: Colors.grey.shade600, fontStyle: FontStyle.italic),
),
),
// 在列表項的尾部加入一個取消收藏的按鈕
trailing: IconButton(
icon: const Icon(Icons.delete_outline, color: Colors.redAccent),
onPressed: () {
// 呼叫 provider 的 removeFavorite 方法
ref.read(favoriteProvider.notifier).removeFavorite(insight.id);
},
),
),
);
我們使用了ref.read(favoriteProvider.notifier).removeFavorite(insight.id)。當你點擊刪除按鈕時:
日更靈感App越來越像一個完整的產品了,但它目前還是有健忘症。只要你關閉App再重新打開,所有收藏的靈感都會消失得無影無蹤。
為了解決這個問題,明天將引入本地端資料Hive,學習如何將我們的收藏資料持久化地儲存到手機上,讓它們在 App重啟後依然存在。敬請期待!
【哈囉你好:)感謝你的閱讀!其他我會常出沒的地方:Threads】