Flutter 自带的搜索组件

发布时间 2023-12-15 12:06:45作者: vx_guanchaoguo0

效果如下



官方需要重写四个关键方法

class searchBarDelegate extends SearchDelegate<String> {
 /*这个方法返回一个控件列表,显示为搜索框右边的图标按钮,这里设置为一个清除按钮,并且在搜索内容为空的时候显示建议搜索内容,使用的是showSuggestions(context)方法:*/
  @override
  List<Widget> buildActions(BuildContext context) {
    return null;
  }
/*这个方法返回一个控件,显示为搜索框左侧的按钮,一般设置为返回,这里返回一个具有动态效果的返回按钮:*/
  @override
  Widget buildLeading(BuildContext context) {
    return null;
  }

  @override
  Widget buildResults(BuildContext context) {
    return null;
  }
/*这个方法返回一个控件,显示为搜索内容区域的建议内容。*/
  @override
  Widget buildSuggestions(BuildContext context) {
    return null;
  }

/*这个方法返回一个主题,也就是可以自定义搜索界面的主题样式:*/
  @override
  ThemeData appBarTheme(BuildContext context) {
    // TODO: implement appBarTheme
    return super.appBarTheme(context);
  }
}

首页展示检索框

 Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Padding(
          padding: const EdgeInsets.only(top: 2, bottom: 2, left: 16),
          child: Container(
            height: 35,
            width: MediaQuery.of(context).size.width - 64,
            decoration: BoxDecoration(
                color: const Color.fromRGBO(230, 230, 230, 1.0),
                borderRadius: BorderRadius.circular(20)),
            child: InkWell(
              child: const Row(
                children: <Widget>[
                  Padding(
                      padding: EdgeInsets.only(left: 10, right: 10),
                      child: Icon(Icons.search, color: Colors.grey)),
                  Text(
                    "输入关键词查找片源",
                    style: TextStyle(color: Colors.grey, fontSize: 15),
                  )
                ],
              ),
              onTap: () {
                showSearch(context: context, delegate: SearchBarDelegate());
              },
            ),
          ),
        ),
        toolbarHeight: 45.sp,
        bottom: TabBar(
          controller: _tabController,
          tabs: tabs.map((e) => Tab(text: e)).toList(),
        ),
      ),

实现 SearchDelegate

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class SearchBarDelegate extends SearchDelegate<String> {
  var nameList = ["完美世界", "西行记", "仙逆", "遮天", "圣墟", "斗罗大陆", "涉谷愤怒的海"];
  late bool flag;





  @override
  String get searchFieldLabel => '输入关键词查找片源';

  @override
  TextStyle get searchFieldStyle => TextStyle(fontSize: 14.0.sp);

  @override
  List<Widget>? buildActions(BuildContext context) {
    return [
      IconButton(
        icon: const Icon(Icons.clear),
        onPressed: () {
          query = "";
          showSuggestions(context);
        },
      )
    ];
  }

  @override
  Widget? buildLeading(BuildContext context) {
    return IconButton(
      icon: AnimatedIcon(
          icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
      onPressed: () {
        if (query.isEmpty) {
          close(context, '');
        } else {
          query = "";
          showSuggestions(context);
        }
      },
    );
  }

  @override
  Widget buildResults(BuildContext context) {
    for (int i = 0; i < nameList.length; i++) {
      if (query == nameList[i]) {
        flag = true;
        break;
      } else {
        flag = false;
      }
    }

    return flag == true
        ? Padding(
            padding: const EdgeInsets.all(16),
            child: InkWell(
              child: Text(query),
              onTap: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => TextScreen(s: query),
                  ),
                );
              },
            ))
        : const Center(
            child: Text("很抱歉,没有找到该搜索结果"),
          );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    final suggestionsList = query.isEmpty
        ? nameList
        : nameList.where((input) => input.startsWith(query)).toList();
    return ListView.builder(
        itemCount: suggestionsList.length,
        itemBuilder: (context, index) {
          return InkWell(
            child: ListTile(
              title: RichText(
                text: TextSpan(
                    text: suggestionsList[index].substring(0, query.length),
                    style: const TextStyle(
                        color: Colors.black, fontWeight: FontWeight.bold),
                    children: [
                      TextSpan(
                          text: suggestionsList[index].substring(query.length),
                          style: const TextStyle(color: Colors.grey))
                    ]),
              ),
            ),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => TextScreen(s: suggestionsList[index]),
                ),
              );
            },
          );
        });
  }
}

class TextScreen extends StatelessWidget {
  final String s;

  const TextScreen({super.key, required this.s});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("搜索结果内容"),
      ),
      body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Center(
            child: Text(s),
          )),
    );
  }
}

为了和首页保持一样的效果需要修改源码

  • 修改文字和大小 提供重写方法
@override
  String get searchFieldLabel => '输入关键词查找片源';

  @override
  TextStyle get searchFieldStyle => TextStyle(fontSize: 14.0.sp);
  • 要在输入框之前加一个 检索的图标
  • ~/flutter/packages/flutter/lib/src/material/search.dart
// 导入icon
import 'package:flutter/material.dart';
// 修改源码  直接到文件末尾
return Semantics(
      explicitChildNodes: true,
      scopesRoute: true,
      namesRoute: true,
      label: routeName,
      child: Theme(
        data: theme,
        child: Scaffold(
          appBar: AppBar(
            leading: widget.delegate.buildLeading(context),
            title: TextField(
              controller: widget.delegate._queryTextController,
              focusNode: focusNode,
              style: widget.delegate.searchFieldStyle ?? theme.textTheme.titleLarge,
              textInputAction: widget.delegate.textInputAction,
              keyboardType: widget.delegate.keyboardType,
              onSubmitted: (String _) => widget.delegate.showResults(context),
              decoration: InputDecoration(
                  // 加这个位置
                  prefixIcon: Icon(Icons.search, color: Colors.grey),
                  hintText: searchFieldLabel
              ),
            ),
            flexibleSpace: widget.delegate.buildFlexibleSpace(context),
            actions: widget.delegate.buildActions(context),
            bottom: widget.delegate.buildBottom(context),
          ),
          body: AnimatedSwitcher(
            duration: const Duration(milliseconds: 300),
            child: body,
          ),
        ),
      ),
    );