1. 源碼下載
喜歡的話,別忘了點個關注,還有給個 Github 右上角的小星星吧。
源碼下載地址,代碼會根據(jù)不斷更新。
Flutter 仿生微信(目錄)
上一篇: Flutter 仿生微信(1):TabBar 創(chuàng)建
下一篇: Flutter 仿生微信(3):發(fā)現(xiàn)頁面搭建
2. 思路
這里我遇到了一點困難,查了不少資料,但是收獲甚微,有大牛有解決方案的可以私信我。
2.1 思路 1
上一篇中我們除了 TabBar,使用 Provider,將 FMHomeManager 作為 ChangeNotify 來整合數(shù)據(jù)。最初的思路是同樣的將 FMHomeManager 傳遞給另一個 Provider 來處理 Body 的內容。但是遇到了一些報錯,這里就不細說了,查了很多資料,然后放棄了。
大致思路如下,我們先注冊兩個不同的 Provider。
Provider1 -> FMHomeManager -> TabBar,并在 TabBar 中監(jiān)聽 FMHomeManger 的通知
Provider2 -> FMHomeManager -> Body,并在 Body 中監(jiān)聽 FMHomeManger 的通知
然后我們改變 FMHomeManager 的屬性后,同時對 TabBar,Body 發(fā)出通知。但是由于 ChangeNotify 的 Reuse 問題,這個方案被擱置了。
2.2 思路 2
于是我這里準備將 FMHomeManger 單獨拿出來,做一個中間層,收到的數(shù)據(jù)改變經過 FMHomeManager 統(tǒng)一轉發(fā)。同時在 FMHomeManager 中新增 FMPagesManager 和 FMTabBarManager 兩個 ChangeNotify。
于是這里將 FMHomeManger 創(chuàng)建為單例,然后通過單例類管理最終要發(fā)出去的通知。
TabBar (ValueChanged) -> FMHomeManger -> 對 FMPagesManger 同步數(shù)據(jù) -> 同時對 FMPagesManager 和 FMTabBarManager 的監(jiān)聽者們發(fā)出通知。

3. 示例代碼
FMHomeManager.dart
import 'package:FMWeixinApp/chat/FMChat.dart';
import 'package:FMWeixinApp/find/FMFind.dart';
import 'package:FMWeixinApp/maillist/FMMailList.dart';
import 'package:FMWeixinApp/mine/FMMine.dart';
import 'package:flutter/material.dart';
class FMHomeManager {
// 單例模式
static FMHomeManager _instance;
static FMHomeManager get instance => _getInstance();
factory FMHomeManager()=> _getInstance();
FMHomeManager._init() {}
static FMHomeManager _getInstance(){
if(_instance == null) {
print("init");
_instance = new FMHomeManager._init();
}
return _instance;
}
// 下標
var _selectedIndex = 0;
// 下標 get, set
int get selectedIndex => _selectedIndex;
set selectedIndex(int index){
_selectedIndex = index;
}
// PageManager
FMPagesManager _pagesManager = FMPagesManager();
FMPagesManager get pagesManager => _pagesManager;
// TabBarManager
FMTabBarManager _tabBarManager = FMTabBarManager(
(index){
FMHomeManager.instance.selectedIndex = index;
FMHomeManager.instance.notifyAll();
}
);
FMTabBarManager get tabBarManager => _tabBarManager;
// 發(fā)送通知
void notifyAll(){
_pagesManager.selectedPage = _selectedIndex;
_pagesManager.notifyListeners();
_tabBarManager.notifyListeners();
}
}
class FMPagesManager with ChangeNotifier {
// FMHomeManager
// 下標
int _selectedPage = 0;
// Pages
List <Widget> _pages = [];
// 構造方法
FMPagesManager(){
_initialPages();
}
// 下標
int get selectedPage => _selectedPage;
set selectedPage(int indext){
_selectedPage = indext;
}
// Pages
List <Widget> _initialPages(){
_pages.add(FMChat());
_pages.add(FMMailList());
_pages.add(FMFind());
_pages.add(FMMine());
return _pages;
}
List <Widget> get pages => _pages;
}
class FMTabBarManager with ChangeNotifier {
ValueChanged<int> _valueChanged;
FMTabBarManager(this._valueChanged);
// 下標
int _selectedIndex = 0;
// 下標 get, set
int get selectedIndex => _selectedIndex;
set selectedIndex(int index){
_selectedIndex = index;
this._valueChanged(index);
}
}
FMHome.dart
import 'package:FMWeixinApp/home/FMHomeManager.dart';
import 'package:FMWeixinApp/home/pages/FMPages.dart';
import 'package:FMWeixinApp/home/tabbar/FMTabBar.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class FMHome extends StatefulWidget {
@override
FMHomeState createState()=> FMHomeState();
}
class FMHomeState extends State <FMHome> {
FMHomeManager manager = FMHomeManager();
@override
Widget build(BuildContext context) {
// TODO: implement build
return _scaffold();
}
Scaffold _scaffold(){
return Scaffold(
// TabBar
bottomNavigationBar: ChangeNotifierProvider(
create: (context)=> manager.tabBarManager,
child: FMTabBar(),
),
body: ChangeNotifierProvider(
create: (context) => manager.pagesManager,
child: FMPages(),
),
);
}
}
FMPages.dart
import 'package:FMWeixinApp/home/FMHome.dart';
import 'package:FMWeixinApp/home/FMHomeManager.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class FMPages extends StatefulWidget {
@override
FMPagesState createState()=> FMPagesState();
}
class FMPagesState extends State <FMPages> {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Consumer<FMPagesManager>(builder: (context, manager, child){
return manager.pages[manager.selectedPage];
});
}
}

4. 源碼分析
4.1 分頁設計
我們的頁面為 TabBar 對應多個不同頁面,所以這里我們需要針對 TabBar 進行分頁。我們創(chuàng)建了 FMPagesManager 作為頁面管理者,同時創(chuàng)建了4個不同頁面,F(xiàn)MChat(), FMMailList(), FMFind(), FMMine(),并在 FMPagesManager.pages 中按照順序進行保存。同時我們還創(chuàng)建了 FMPagesManager.selectedPage 作為當前顯示頁面。
頁面保存好后,我們創(chuàng)建了 FMPages.dart 文件,將 FMPages() 作為 body 提供給 home.scaffold.body。
在 FMPages.dart 文件中,我們按照 FMPagesManager.selectedPage 讀取 pages 中已經保存好的頁面作為最上層顯示。
4.2 消息分發(fā)
最開始接收到點擊信息的是 FMTabBar,在代碼中,我把這個點擊事件返回給上層 FMHomeManger,然后更改 FMHomePages.selectedPage 后,同時刷新 TabBar 和 Body。