在Flutter中,使用BottomNavigationBar
和IndexedStack
可以實現一個功能完整的底部導航欄。BottomNavigationBar
用于顯示底部的導航按鈕,而IndexedStack
則用于管理頁面的切換,確保每個頁面的狀態得以保留(即頁面不會因為切換而重新構建)。
以下是實現的完整代碼示例及詳細解釋:
代碼實現
import 'package:flutter/material.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key); Widget build(BuildContext context) {return MaterialApp(title: 'BottomNavigationBar + IndexedStack',theme: ThemeData(primarySwatch: Colors.blue,),home: const BottomNavigationExample(),);}
}class BottomNavigationExample extends StatefulWidget {const BottomNavigationExample({Key? key}) : super(key: key); _BottomNavigationExampleState createState() =>_BottomNavigationExampleState();
}class _BottomNavigationExampleState extends State<BottomNavigationExample> {// 當前選中的索引int _currentIndex = 0;// 頁面列表final List<Widget> _pages = [const HomePage(),const SearchPage(),const ProfilePage(),]; Widget build(BuildContext context) {return Scaffold(body: IndexedStack(index: _currentIndex, // 根據當前索引顯示對應的頁面children: _pages, // 所有頁面),bottomNavigationBar: BottomNavigationBar(currentIndex: _currentIndex, // 當前選中的索引onTap: (int index) {setState(() {_currentIndex = index; // 更新索引});},items: const [BottomNavigationBarItem(icon: Icon(Icons.home),label: 'Home',),BottomNavigationBarItem(icon: Icon(Icons.search),label: 'Search',),BottomNavigationBarItem(icon: Icon(Icons.person),label: 'Profile',),],),);}
}// 首頁
class HomePage extends StatelessWidget {const HomePage({Key? key}) : super(key: key); Widget build(BuildContext context) {return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: const [Icon(Icons.home, size: 50, color: Colors.blue),Text('Home Page', style: TextStyle(fontSize: 24)),],),);}
}// 搜索頁
class SearchPage extends StatelessWidget {const SearchPage({Key? key}) : super(key: key); Widget build(BuildContext context) {return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: const [Icon(Icons.search, size: 50, color: Colors.green),Text('Search Page', style: TextStyle(fontSize: 24)),],),);}
}// 個人中心頁
class ProfilePage extends StatelessWidget {const ProfilePage({Key? key}) : super(key: key); Widget build(BuildContext context) {return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: const [Icon(Icons.person, size: 50, color: Colors.purple),Text('Profile Page', style: TextStyle(fontSize: 24)),],),);}
}
代碼解析
-
IndexedStack
的作用IndexedStack
是一個特殊的堆棧組件,它會根據index
屬性顯示其子組件列表中的某一個子組件。- 與普通的
Stack
不同,IndexedStack
只渲染當前索引對應的子組件,但所有子組件的狀態都會被保留。因此,當用戶切換回某個頁面時,該頁面的狀態不會丟失。
-
BottomNavigationBar
的配置currentIndex
: 表示當前選中的導航項索引。onTap
: 當用戶點擊導航項時觸發的回調函數,用于更新_currentIndex
。items
: 定義了導航欄的每一項,包括圖標和標簽。
-
頁面狀態保留
- 使用
IndexedStack
管理頁面,而不是直接使用PageView
或Navigator
,可以確保每個頁面的狀態在切換時不會被銷毀。這對于需要保存滾動位置、輸入框內容等場景非常有用。
- 使用
-
頁面切換邏輯
- 用戶點擊底部導航欄時,
onTap
回調會觸發setState
,更新_currentIndex
,從而讓IndexedStack
顯示對應索引的頁面。
- 用戶點擊底部導航欄時,
運行效果
- 應用啟動后,默認顯示首頁(
HomePage
)。 - 點擊底部導航欄的不同選項,頁面會切換到對應的頁面(
SearchPage
或ProfilePage
)。 - 切換回之前的頁面時,頁面狀態保持不變。
注意事項
-
性能優化
如果頁面較多或頁面內容較復雜,可以考慮懶加載頁面(例如通過AutomaticKeepAliveClientMixin
實現),以減少內存占用。 -
動態數據更新
如果頁面需要動態更新數據,可以在每個頁面中使用StatefulWidget
,并通過setState
或其他狀態管理工具(如Provider
、Riverpod
)來更新頁面內容。 -
更多自定義
BottomNavigationBar
支持更多自定義樣式,例如背景顏色、字體大小、圖標大小等,可以根據需求調整。