前言
之前弄了不少flutter
的内容,这里直接小小实战一下,就编写微信的 tabbar
上面的前四个页面来锻炼一下我们的实战能力
---- 仿微信源码地址
另外看看效果(没细搞):
MaterialApp
跟其他大多数应用一样,我们的开发都是从main
函数开始的,这里我们采用 MaterialApp
风格作为我们基本组件(至少目前没用过其他组件),这里面包含了我们的 Router
导航等
void main() {
runApp(const App());
}
//由于没有涉及到状态的变更,一次使用 StatelessWidget 即可
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//MaterialApp代表我们主题纸墨风格框架,我们一般开发都用这个
return MaterialApp(
//去掉debug自选
debugShowCheckedModeBanner: false,
//Android任务管理器界面title,可以设置称自己的app名字
title: "Flutter Demo",
//设置我么你的颜色等
theme: ThemeData(
scaffoldBackgroundColor: Colors.white,
brightness: Brightness.light,
//设置一些card组件的背景颜色,例如一些弹窗组件的背景颜色
cardColor: const Color.fromRGBO(0x33, 0x33, 0x33, 0.8),
),
//这里就是我们的默认主页了
home: const HomePage()
);
}
}
复制代码
Tabbar的HomePage
HomePage 是我们编写的 Tabbar的一个界面,其控制聊天(chat)、联系人(contact)、发现(discover)、我的(mine),其他几个页面默认使用空组件占位即可,等待后续编写
另外,每开始一个新界面都需要使用Scaffold
组件进行包括,其包含着 appbar
和bottombar
的设置,以便于我们后续开发(当然单纯封装的UI小组件不需要)
另外 Tabar
组件,我们使用系统的 BottomNavigationBar
还远远不够,我们使用了PageView
持有了其他四个页面的变量,而(在后面讲解为什么不是像ios
一样放了4个UI组件在一个数组)
然后通过 PageController
控制实际显示界面,此时 BottomNavigationBar
单纯设置 bar
的UI效果,PageView
和 PageController
联动,则负责跳转功能
//编写时我们继承自StatefulWidget,因为内部会更新状态
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//初始化pagecontroller,用来控制page页面
final _controller = PageController(
initialPage: 0
);
//声明到这里,可以默认保存,避免内次切换都要重新初始化,如果想重新初始化,可以特殊处理
int _pageIndex = 0;
@override
Widget build(BuildContext context) {
//每开始一个新界面都需要使用Scaffold进行包括,其包含着 appbar和bottombar的设置
return Scaffold(
//这是一个 Widget 类型,可以自定义 tabbar,这里使用系统的来测试
bottomNavigationBar: BottomNavigationBar(
//设置当前的index
currentIndex: _pageIndex,
//点击后可以用来 index 的选中效果,通过更新页面跳转
onTap: (int index) {
setState(() {
_pageIndex = index;
});
//除了更新bottombar图标,还要更新显示哪个页面
_controller.jumpToPage(index);
},
//设置了默认会显示字体,否则只有选中的才显示字体
unselectedItemColor: Colors.black,
selectedItemColor: Colors.green,
//设置为混合类型,默认未选中只显示一个icon图片
type: BottomNavigationBarType.fixed,
selectedFontSize: 12,
unselectedFontSize: 12,
//设置里面组件
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
label: "聊天",
icon: Image.asset('images/tabbar_chat.png',
width: 20,
height: 20
),
activeIcon: Image.asset('images/tabbar_chat_hl.png',
width: 20,
height: 20
)
),
BottomNavigationBarItem(
label: "联系人",
icon: Image.asset('images/tabbar_contact.png',
width: 20,
height: 20
),
activeIcon: Image.asset('images/tabbar_contact_hl.png',
width: 20,
height: 20
)
),
BottomNavigationBarItem(
label: "发现",
icon: Image.asset('images/tabbar_discover.png',
width: 20,
height: 20
),
activeIcon: Image.asset('images/tabbar_discover_hl.png',
width: 20,
height: 20
)
),
BottomNavigationBarItem(
label: "我的",
icon: Image.asset('images/tabbar_mine.png',
width: 20,
height: 20
),
activeIcon: Image.asset('images/tabbar_mine_hl.png',
width: 20,
height: 20
)
)
],
),
body: PageView(
controller: _controller,
//不设置默认可以左右活动,如果不想左右滑动如下设置,可以根据ios或者android来设置
// physics: const NeverScrollableScrollPhysics(),
//界面切换后的回调,主要是针对android左右滑动回调,此时与bottombar无关了
onPageChanged: (int index) {
setState(() {
_pageIndex = index;
});
},
//设置我们要切换的页面,放到一个数组
children: const [
ChatList(),
Contact(),
Discover(),
Mine()
],
),
);
}
}
复制代码
tabbar的问题点
错误示范
看了相面估计有疑问,我试了一下,将四个页面放到一个数组中,然后直接根据index
切换body
的实际页面也可以呀,如下所示,我第一次也这么写的(这里是错误示范
)
//错误示范,但看起来效果也是一样
final List _pageList = [ChatList(), Contact(), Discover(), Mine()];
body: _pageList[_pageIndex]
复制代码
问题
问题一
我们声明的组件默认在build
中有一个基本组件的声明,这是我们声明的组件,我们正常可以通过变量来控制某个界面的显示和隐藏
,于此同时也控制着一些组件的创建和销毁
因此,当我们的组件挂载到 body
中时,也就意味着每次都切换组件,那么被切换的组件就会释放,而我们 _pageList
存放的只是没有状态未渲染的widget小组件
,跟我们直接放一个Text一样,每一次切换会重新创建当前组件和渲染,并且强制释放上一个组件的内容,因此其状态无法保存
问题二
然后可能会尝试,发现使用了 PageView
,为什么 initStat
e 和 build
也会重走呢,这就涉及到了 flutter
的渲染机制,其默认只会渲染当前一屏的内容,且不会保存组件的默认状态,一旦切换其他页面,需要重新初始状态,但有一点该组件并没有释放,我们的组件一直在 PageView
中持有,因此没有释放
系统给我们提供了一个 maxin
类 AutomaticKeepAliveClientMixin
,我们可以采用多继承的方式,继承自它,那么这个状态就会被保存,就不需要重新渲染后
例如: chat
组件,当我们多继承(with
它) AutomaticKeepAliveClientMixin
,需要重写他的 wantKeepAlive
属性,设置为 true
,然后在 build
中 调用一下 super.build
即可
后面章节都会有代码实例,介绍 AutomaticKeepAliveClientMixin
的使用
pubpec.yaml
这个文件包含了我们的的 sdk版本号、三方仓库、图片资源名称等
//平时用不到,当迁移文件或者改名,记得改一下
name: flutter_wechat_demo
description: 一个仿微信的实战测试demo
//环境sdk版本,一般默认的即可,如果几台电脑不一样,可以根据情况设置最低版本
environment:
sdk: ">=2.16.1"
//三方依赖,一般使用 flutter pub get + 三方库 方式导入
//在这里导入,需要点击右上角 Pub get更新
dependencies:
flutter:
sdk: flutter
http: ^0.13.4
//测试版本依赖
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
//图片资源库地址,图片仓库名字一般与我们ios、android仓库同级
//放入图片后,只需要右键复制路径,粘到这里即可
flutter:
uses-material-design: true
assets:
- images/tabbar_chat.png
- images/tabbar_chat_hl.png
- images/tabbar_contact.png
复制代码