Flutter(三十)实战-微信聊天搜索输入框

「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

我们已经实现了微信的聊天列表界面,在微信中聊天界面上方还有一个搜索功能,可以搜索微信的聊天信息,今天我们来模仿实现此功能;

添加搜索入口

在微信的首页,我们滑动页面可以发现,搜索框是随着列表一起滑动的,那么说明搜索部件和ListView很有可能是一体的,我们现在来实现此部件;

class ChatSearchCell extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.red, height: 40,);
  }
}
复制代码

我们先给此部件一个简单的红色背景及高度;

接下来,我们要对聊天界面的代码进行修改,因为搜索框也是ListView的一部分了,我们将其当做是第一个Cell,那么ListViewitemCount个数应该+1:

return ListView.builder(
  itemCount: _list.length + 1,
  itemBuilder: _itemBuilderForRow);
复制代码

之后,在_itemBuilderForRow方法中做判断,当是第一个cell的时候,显示搜索框,之后的cell进行index--操作,显示聊天列表的数据,代码及效果如下:

image.png

布局搜索入口UI

为了更好的对照微信进行布局,我们将导航栏颜色设置为灰色背景,因为此处的搜索入口是需要进行点击事件响应的,因此使用手势包括起来:

image.png

隐藏导航栏下方阴影

我们看到导航栏下方,有一条阴影线,我们将其隐藏,需要设置对应页面AppBarelevation属性,将其设置为0:

image.png

添加白色背景

很明显,我们此处应该显示一个Stack,在一个圆角白色背景上边显示搜索文字和图标:

image.png

使用Stack进行布局,先添加一个圆角的白色背景;

添加搜索图标及文字

通过在Stack上先添加了一个圆角白色背景的Container,因为搜索图标和文字是横向的,因此我们需要再添加一个Row来布局,效果如下:

image.png

  • Stackalignment属性可以设置白底ContainerRow都居中对齐;
  • RowmainAxisAlignment属性可以设置Row中的IconText在主轴方向上居中对齐;

搜索页面

头部搜索框

从搜索页面布局来看,页面大致分为两部分,上部为搜索输入框,下部为显示结果的ListView,那么在搜索页面我们就可以使用Column来进行布局:

image.png

上半部分显示搜索的SearchBar,下半部分显示ListView,但是我们发现此时运行代码是会报错的,报错信息如下:

image.png

这是因为我们在添加一个ListView的时候,需要给ListView指定高度,此时有两种解决方案,为了便于分析,我们将ListView放进Container里边:

  • 第一种,使用ExpendedListView包起来,代码及效果如下:

image.png

  • 第二种,使用ListViewshrinkWrap属性,将其设置为true,代码及效果如下:

image.png

两者结果:使用Expanded的方式,ListView会根据布局自适应剩下的区域;而shrinkWrap该属性将决定列表的长度是否仅包裹其内容的长度。当ListView嵌在一个无限长的容器组件中时,shrinkWrap必须为true,否则Flutter会给出警告

我们此处采用Expanded的方式,需要注意的是Expanded需要设置flex,由于我们此处直接使用了flex默认为1

ListView偏移问题

我们虽然成功添加了ListView,但是ListView的内容是向下偏移了的,这个时候我们需要将这部分偏移移除;需要使用MediaQuery.removePadding方法移除头部偏移,代码如下:

image.png

搜索框布局

我们来看一下目前头部红色区域的代码:

image.png

statusBarHeight获取状态栏高度;

因为我们的搜索框是显示在下半部,也就是状态栏下方的,因此我们采用Column进行布局,代码如下:

image.png

接下来,红色区域使用Row进行左右布局,左边是白色背景的Container,右边是取消按钮,:

image.png

将此区域分为两部分,上半部分采用SizeBox填充状态栏(安全区),下半部分显示搜索区域取消

输入框布局

输入框分为三部分,左边放大镜中间输入框右边是清除按钮,这样我们来使用Row进行布局,代码及效果如下:

image.png

  • 放大镜的Icon使用SizeBox包一下,可以设置宽度,调整大小;
  • 中间的输入框TextField使用Expanded包起来,可以让输入框自适应大小,将清除按钮自动布局到右侧;

输入框光标颜色

TextFieldCursorColor属性可以修改输入框的光标的颜色

cursorColor: Colors.green, // 输入框光标颜色
复制代码

代码及效果如下: image.png

文字的大小颜色和宽度

TextField的文本信息依然是style属性,并且styleTextStyle类型的:

style: TextStyle(fontSize: 18, color: Colors.black, fontWeight: FontWeight.w300),
复制代码

效果如下:

image.png

输入框的边框

当我们在输入框内输入过多文字的时候,会出现如下情况:

image.png

此时需要设置TextField的装饰器decoration

image.png

输入框下方黑线

我们仔细看此时的输入框,在输入框的下边是有一条黑线的,那么如何隐藏呢?需要设置装饰器InputDecorationborder属性:

image.png

占位符

设置TextField占位文本,使用属性hintText

image.png

第一响应

如果我们需要输入框自动聚焦获得第一响应,调起键盘,可以使用TextFieldautofocus属性:

image.png

清除按钮

清除按钮样式:

image.png

清除按钮功能

我们点击清除按钮的时候,是需要清空输入框中的内容的,要想实现此功能,需要使用到TextEditingController,我们来定义一个:

final TextEditingController _textEditingController = TextEditingController();
复制代码

然后将_textEditingController赋值给TextFieldcontroller属性:

image.png

这样,我们就能通过_textEditingController来控制输入框的相关功能;

当在输入框中输入文本信息时,TextFieldonChange方法将会产生回调,返回当前输入框中的内容:

image.png

我们将此方法抽出为:

  void _textFieldOnChange(text) {

  }
复制代码

我们是需要控制清除按钮的显示与隐藏的,默认情况下隐藏,当输入框中有内容是,清除按钮显示,那么我们就需要一个bool值来标识显示与隐藏:

bool _showClear = false; // 是否隐藏请求按钮
复制代码

再添加清除按钮式需要根据此属性值来添加,如果为true,则添加清除按钮:

image.png

然后在_textFieldOnChange方法中,判断是否显示隐藏,效果如下:

iShot2021-11-20 17.22.36.gif

清除按钮也是可以点击清除输入框内容的,我们需要给Icon添加手势:

image.png

我们使用_textEditingController.clear()方法来清除输入框文本内容,但是需要注意的是,此方法并不会触发TextFieldonChange方法,那么点击清除之后,清除按钮本身并不会被隐藏,因此我们需要手动调用onChange方法:

iShot2021-11-20 17.43.22.gif

目前,搜索框相关功能已经完全实现;

Guess you like

Origin juejin.im/post/7035567561785901069