前言:上节我们简单地封装了网络请求dio,这节我们继续我们的页面完善,本节我们将在聊天页面新增一个搜索栏,用来检索聊天信息
问题抛出:为什么每次进到chatPage的时候,总是会再次请求数据,即每次都会进initState()方法,那么能不能不重新请求呢??????
补充内容
1.为widget持久化保持状态
AutomaticKeepAliveClientMixin:用来保持widget的状态持久
``step1:with AutomaticKeepAliveClientMixin
class _State extends State<ChatPage> with AutomaticKeepAliveClientMixin{
};
step2:重写get wantKeepAlive
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
step3:集成父方法
Widget build(BuildContext context) {
super.build(context);
...
}
...
run:发现还是不能持久化状态!!!!!!
//homePage
return Scaffold(
body: widgets[_currentIndex],
分析原因:当切换到其他page的时候,widge其实已经不显示了,虽然数据在内存中会存在,但是页面重新出现的时候,会重新进行渲染,所以又会进一次initState(),所以接下来该怎么办呢......
2.重写HomePage,为4个Page保持持久化状态
final _controller = PageController();
return Scaffold(
body: PageView(
physics: NeverScrollableScrollPhysics(),//禁止滑动
controller: _controller,
children: widgets,
),
)
onTap: (int index){
_controller.jumpToPage(index);
setState(() {
_currentIndex = index;
});
},
run:大功告成✿✿ヽ(°▽°)ノ✿
正文:
1.新建搜索栏search_bar.dart
import 'package:flutter/material.dart';
import 'package:wechat_demo/const.dart';
class SearchCell extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: 50,
color: wechatThemeColor,
child: Stack(
alignment: Alignment.center,
children: [
Container(
margin: EdgeInsets.only(left: 5,bottom: 5,right: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('images/放大镜b.png',width: 20,height: 20,color: Colors.grey,),
SizedBox(width: 5,),
Text('搜索',style: TextStyle(color: Colors.grey,fontSize: 16),),
],
)
],
),
);
}
}
引用
Widget _cellForIndex(BuildContext context,int index){
//返回搜索栏
if(index == 0){
return SearchCell();
}
index --;//保证从数据源的第0个位置来时取
return ListTile(
title: Text(_chatListDatas[index].name),
leading: Container(
width: 50,
height:50,
child: Image.network(_chatListDatas[index].imageUrl),
),
subtitle: Text(_chatListDatas[index].message,overflow: TextOverflow.ellipsis,),
);
}
run

35.png
2.为搜索栏cell添加点击事件,进入搜索页面
新建search_page.dart
import 'package:wechat_demo/chat/search_page.dart';
class SearchCell extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (e){
Navigator.of(context).push(
//进入搜索页面
MaterialPageRoute(builder: (context)=>SearchPage())
);
},
child: Container(
height: 50,
color: wechatThemeColor,
child: ...省略
);
}
}
3.搜索页面添加搜索栏SearchBar
class SearchBar extends StatefulWidget {
@override
_SearchBarState createState() => _SearchBarState();
}
class _SearchBarState extends State<SearchBar> {
final TextEditingController _editController = TextEditingController();
//显示清除按钮
bool _showCancle = false;
//监听文本变化内容
_onChange(String text){
if(text.length > 0){
setState(() {
_showCancle = true;//显示清除按钮
});
}else{
setState(() {
_showCancle = false;//隐藏清除按钮
});
}
}
@override
Widget build(BuildContext context) {
return Container(
color: wechatThemeColor,
height: 88,
alignment: Alignment.center,
child: Column(
children: [
Container(
height: 40,
),
Row(
children: [
Container(
padding: EdgeInsets.only(left: 5,right: 5),
height: 40,
width: ScreenWidth(context) - 60,
margin: EdgeInsets.only(left: 10,bottom: 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
child: Row(
children: [
Image.asset('images/放大镜b.png',color: Colors.grey,width: 20,),
Expanded(flex: 1,child: TextField(
onChanged: _onChange,
cursorColor: Colors.green,
autofocus: true,//自动聚焦
controller: _editController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 5,bottom: 10),//文本内容偏移量
hintText: '搜索',//无文字时,显示默认文字
focusColor: Colors.green,//改变聚焦的颜色
border: InputBorder.none,//去掉下边框的线
labelStyle: TextStyle(
color: Colors.black,
fontSize: 16,
)
),
)),
_showCancle == true ? GestureDetector(onTap: (){
_editController.clear();//文本置空
_onChange('');//文本置空
},
child: Icon(Icons.cancel,color: Colors.grey,),) : Container(),
],
),
),
SizedBox(width: 10,),
GestureDetector(
onTap: (){
Navigator.of(context).pop();
},
child: Text('取消',style: TextStyle(fontSize: 16),),
)
],
),
],
),
);
}
}
searchpage引用searchBar
class _SearchPageState extends State<SearchPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
SearchBar(),
Expanded(flex: 1,child: ListView(
)),
],
)
),
);
}
}
run

36.png
4.textfiled返回回调,把搜索文本往外传递
class SearchBar extends StatefulWidget {
//新增回调
var editBlock = (String text){};
//构造函数
SearchBar({
this.editBlock,
});
@override
_SearchBarState createState() => _SearchBarState();
}
_onChange(String text){
if(text.length > 0){
setState(() {
_showCancle = true;
});
}else{
setState(() {
_showCancle = false;
});
}
//往外传递回调
if(widget.editBlock != null){
widget.editBlock(text);
}
}
run

5.为searchPage传递数据,并进行筛选数据
class SearchPage extends StatefulWidget {
final List<ChatModel> listDatas;
SearchPage({
this.listDatas
});
@override
_SearchPageState createState() => _SearchPageState();
}
class SearchCell extends StatelessWidget {
final List<ChatModel> listDatas;
SearchCell({
this.listDatas,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (e){
Navigator.of(context).push(
MaterialPageRoute(builder: (context)=>SearchPage(listDatas: listDatas,))
);
},
}
...省略
}
然后在chatPage中传递数据到SearchCell
Widget _cellForIndex(BuildContext context,int index){
if(index == 0){
return SearchCell(listDatas: _chatListDatas,);
}
...省略
}
筛选数据
_handleResult(String searchText){
//先清空搜索结果数据
_reultDatas.clear();
if(searchText.length > 0){
for(int i = 0; i < widget.listDatas.length ; i++){
ChatModel model = widget.listDatas[i];
if(model.name.contains(searchText)){
_reultDatas.add(model);
}
}
}
setState(() {
});
}
SearchBar(editBlock: (text){
print('接收到的text是${text}');
_handleResult(text);
},),
run

37.png
到此应该全部结束了,完结✿✿ヽ(°▽°)ノ✿
额外补充:
筛选出匹配的文字进行高亮显示
//对于搜索文字内容进行高亮显示
Widget _highlightText(String allStr , String searchStr){
List<TextSpan> spans = [];
List<String> strs = allStr.split(searchStr);//文字截取
for(int i = 0 ; i < strs.length ; i++){
if(strs[i].length == 0 && i < strs.length-1){
spans.add(TextSpan(
text: searchStr,
style: TextStyle(color: Colors.green,fontSize: 16),
));
}else{
spans.add(TextSpan(
text: strs[i],
style: TextStyle(color: Colors.black,fontSize: 16),
));
if(i < strs.length-1){
spans.add(TextSpan(
text: searchStr,
style: TextStyle(color: Colors.green,fontSize: 16),
));
}
}
}
return RichText(text: TextSpan(
children: spans,
));
}
Widget _cellForIndex(BuildContext context , int index){
return ListTile(
title: _highlightText(_reultDatas[index].name,_searchStr),
leading: Container(
width: 50,
height:50,
child: Image.network(_reultDatas[index].imageUrl),
),
subtitle: Text(_reultDatas[index].message,overflow: TextOverflow.ellipsis,),
);
}
run

38.png
完结✿✿ヽ(°▽°)ノ✿