foreword
I have done a lot flutter
of content before, here is a little actual combat, and we will write the first four pages tabbar
on to exercise our actual combat ability.
---- Imitate WeChat source address
Also look at the effect (not detailed):
MaterialApp
Like most other applications, our development main
starts with functions, here we use MaterialApp
style as our basic component (at least no other components have been used so far), which contains our Router
navigation, etc.
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's HomePage
HomePage is an interface of the Tabbar we wrote, which controls chat (chat), contact (contact), discovery (discover), mine (mine), and other pages can use empty components by default to occupy the place, waiting for subsequent writing
In addition, each new interface needs to Scaffold
be included using components, which contain appbar
and bottombar
settings for our subsequent development (of course, simple encapsulated UI widgets are not required)
In addition, the Tabar
components we use the system BottomNavigationBar
are far from enough, we use PageView
variables that hold the other four pages, and (in the following, we will explain why we don't ios
put 4 UI components in an array like the same)
Then through the PageController
control of the actual display interface, theBottomNavigationBar
UI effect of the simple setting at this time, and the linkage , are responsible for the jump functionbar
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()
],
),
);
}
}
复制代码
Problems with tabbars
Error demonstration
I have some doubts after reading the face, I tried it, put the four pages into an array, and then directly according index
to the actual page to switch body
, as shown below, I wrote it for the first time ( 这里是错误示范
)
//错误示范,但看起来效果也是一样
final List _pageList = [ChatList(), Contact(), Discover(), Mine()];
body: _pageList[_pageIndex]
复制代码
question
问题一
The components we declare have a basic component declaration by default build
. This is the component we declare. We can normally control a certain interface through variables 显示和隐藏
, and at the same time control some components.创建和销毁
Therefore, when our component is mounted body
in , it means that the component is switched every time, then the switched component will be released, and what we _pageList
store is only the unrendered unrendered state, just widget小组件
like we put a Text directly, Each toggle recreates the current component and rendering, and forces the content of the previous component to be released, so its state cannot be saved
问题二
Then you may try and find that if you use it PageView
, why initStat
e and build
will be replayed? This involves flutter
the rendering mechanism of , which will only render the content of the current screen by default, and will not save the default state of the component. Once you switch to other pages , the initial state needs to be re-initialized, but at one point the component is not released, our component has been held PageView
in , so it is not released
The system provides us with a maxin
class AutomaticKeepAliveClientMixin
, we can use multiple inheritance, inherit from it, then this state will be saved, no need to re-render
For example: chat
component, when we inherit multiple ( with
it) AutomaticKeepAliveClientMixin
, we need to rewrite his wantKeepAlive
property , set it to true
, and then call it build
insuper.build
There will be code examples in the following chapters to introduce AutomaticKeepAliveClientMixin
the use of
pubpec.yaml
This file contains our sdk version number, third-party warehouse, image resource name, etc.
//平时用不到,当迁移文件或者改名,记得改一下
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
复制代码