搜索这个功能,大部分APP都会存在,这节课我们就学习一下,如何做一个有提示功能,而且交互很好的搜索条

一个不简单的搜索条 - 图1

主入口文件main.dart

这个还是继承StatelessWidget,然后在home属性中加入SearchBarDemo,这是一个自定义的Widget

  1. import 'package:flutter/material.dart';
  2. import 'search_bar_demo.dart';
  3. void main() =>runApp(MyApp());
  4. class MyApp extends StatelessWidget {
  5. @override
  6. Widget build(BuildContext context) {
  7. return MaterialApp(
  8. title:'Flutter Demo',
  9. theme: ThemeData.light(),
  10. home: SearchBarDemo()
  11. );
  12. }
  13. }

数据文件asset.dart

asset.dart相当于数据文件,工作中这些数据是后台传递给我们,或者写成配置文件的,这里我们就以List的方式代替了。我们在这个文件中定义了两个List:

  • searchList : 这个相当于数据库中的数据,我们要在这里进行搜索。
  • recentSuggest : 目前的推荐数据,就是搜索时,自动为我们进行推荐。

整体代码如下 :

  1. const searchList = [
  2. "jiejie-大长腿",
  3. "jiejie-水蛇腰",
  4. "gege1-帅气欧巴",
  5. "gege2-小鲜肉"
  6. ];
  7. const recentSuggest = [
  8. "推荐-1",
  9. "推荐-2"
  10. ];

AppBar的样式制作search_bar_demo.dart

这节课我们先把第一个搜索界面布好,下节课我们主要作搜索的交互效果。看下面的代码:

  1. import 'package:flutter/material.dart';
  2. import 'asset.dart';
  3. class SearchBarDemo extends StatefulWidget {
  4. _SearchBarDemoState createState() => _SearchBarDemoState();
  5. }
  6. class _SearchBarDemoState extends State<SearchBarDemo> {
  7. @override
  8. Widget build(BuildContext context) {
  9. return Scaffold(
  10. appBar:AppBar(
  11. title:Text('SearchBarDemo'),
  12. actions:<Widget>[
  13. IconButton(
  14. icon:Icon(Icons.search),
  15. onPressed: (){
  16. print('开始搜索');
  17. }
  18. ),
  19. ]
  20. )
  21. );
  22. }
  23. }

这时候就可以在虚拟机中进行预览了,但是这时候点击搜索按钮还没有任何反应。增加动态反应

  • 在点击图标时执行 showSearch(context:context,delegate: searchBarDelegate())
  • 自定义searchBarDelegate 类,这个类继承与SearchDelegate类,继承后要重写里边的四个方法

    buildActions 方法重写

    这个是搜索条右侧的按钮执行方法,我们在这里方法里放入一个clear图标。 当点击时,清空搜索的内容。代码如下:
    1. @override
    2. List<Widget> buildActions(BuildContext context){
    3. return [
    4. IconButton(
    5. icon:Icon(Icons.clear),
    6. onPressed: ()=>query = "",)
    7. ];
    8. }

    buildLeading 方法重写

    这个时搜索栏左侧的图标和功能的编写,这里我们才用AnimatedIcon,然后在点击时关闭整个搜索页面,代码如下。
    1. @override
    2. Widget buildLeading(BuildContext context) {
    3. return IconButton(
    4. icon: AnimatedIcon(
    5. icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
    6. onPressed: () => close(context, null));
    7. }

    buildResults方法重写

    这个方法是搜到到内容后的展现,因为我们的数据都是模拟的,所以我这里就使用最简单的Container+Card组件进行演示了,不做过多的花式修饰了。
    1. @override
    2. Widget buildResults(BuildContext context) {
    3. return Container(
    4. width: 100.0,
    5. height: 100.0,
    6. child: Card(
    7. color: Colors.redAccent,
    8. child: Center(
    9. child: Text(query),
    10. ),
    11. ),
    12. );
    13. }

    buildSuggestions 方法重写

    这个方法主要的作用就是设置推荐,就是我们输入一个字,然后自动为我们推送相关的搜索结果,这样的体验是非常好的。
    具体代码如下:
    1. @override
    2. Widget buildSuggestions(BuildContext context) {
    3. final suggestionList = query.isEmpty
    4. ? recentSuggest
    5. : searchList.where((input) => input.startsWith(query)).toList();
    6. return ListView.builder(
    7. itemCount: suggestionList.length,
    8. itemBuilder: (context, index) => ListTile(
    9. title: RichText(
    10. text: TextSpan(
    11. text: suggestionList[index].substring(0, query.length),
    12. style: TextStyle(
    13. color: Colors.black, fontWeight: FontWeight.bold),
    14. children: [
    15. TextSpan(
    16. text: suggestionList[index].substring(query.length),
    17. style: TextStyle(color: Colors.grey))
    18. ])),
    19. ));
    20. }
    21. }

search_bar_demo.dart文件的代码:

  1. import 'package:flutter/material.dart';
  2. import 'asset.dart';
  3. class SearchBarDemo extends StatefulWidget {
  4. _SearchBarDemoState createState() => _SearchBarDemoState();
  5. }
  6. class _SearchBarDemoState extends State<SearchBarDemo> {
  7. @override
  8. Widget build(BuildContext context) {
  9. return Scaffold(
  10. appBar:AppBar(
  11. title:Text('SearchBarDemo'),
  12. actions:<Widget>[
  13. IconButton(
  14. icon:Icon(Icons.search),
  15. onPressed: (){
  16. showSearch(context:context,delegate: searchBarDelegate());
  17. }
  18. // showSearch(context:context,delegate: searchBarDelegate()),
  19. ),
  20. ]
  21. )
  22. );
  23. }
  24. }
  25. class searchBarDelegate extends SearchDelegate<String>{
  26. @override
  27. List<Widget> buildActions(BuildContext context){
  28. return [
  29. IconButton(
  30. icon:Icon(Icons.clear),
  31. onPressed: ()=>query = "",)
  32. ];
  33. }
  34. @override
  35. Widget buildLeading(BuildContext context) {
  36. return IconButton(
  37. icon: AnimatedIcon(
  38. icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
  39. onPressed: () => close(context, null));
  40. }
  41. @override
  42. Widget buildResults(BuildContext context) {
  43. return Container(
  44. width: 100.0,
  45. height: 100.0,
  46. child: Card(
  47. color: Colors.redAccent,
  48. child: Center(
  49. child: Text(query),
  50. ),
  51. ),
  52. );
  53. }
  54. @override
  55. Widget buildSuggestions(BuildContext context) {
  56. final suggestionList = query.isEmpty
  57. ? recentSuggest
  58. : searchList.where((input) => input.startsWith(query)).toList();
  59. return ListView.builder(
  60. itemCount: suggestionList.length,
  61. itemBuilder: (context, index) => ListTile(
  62. title: RichText(
  63. text: TextSpan(
  64. text: suggestionList[index].substring(0, query.length),
  65. style: TextStyle(
  66. color: Colors.black, fontWeight: FontWeight.bold),
  67. children: [
  68. TextSpan(
  69. text: suggestionList[index].substring(query.length),
  70. style: TextStyle(color: Colors.grey))
  71. ])),
  72. ));
  73. }
  74. }

附件

一个不简单的搜索条-lib.zip