Flutter: implement a simple search box on appBar, a simple search history

search bar

Effect picture
insert image description here
code

import 'package:flutter/material.dart';

class NovelSearch extends StatefulWidget {
    
    
  
  State<StatefulWidget> createState() => _NovelSearchState();
}

class _NovelSearchState extends State<NovelSearch> {
    
    
  String searchVal = '';
  
  Widget build(BuildContext context) {
    
    
    return Scaffold(
      appBar: AppBar(
        //清除title左右的padding,默认会有一定的距离
        titleSpacing: 0,
        elevation: 0,
        title: SearchAppBar(
          hintLabel: "搜索书名",
          onSubmitted: (value) {
    
    
            setState(() {
    
    
              this.searchVal = value;
            });
          },
        ),
      ),
      body: Text("搜索值是:${
      
      this.searchVal}"),
    );
  }
}

class SearchAppBar extends StatefulWidget {
    
    
  SearchAppBar({
    
    Key? key, required this.hintLabel, required this.onSubmitted})
      : super(key: key);
  final String hintLabel;
  // 回调函数
  final Function(String) onSubmitted;

  
  State<StatefulWidget> createState() => _SearchAppBarState();
}

class _SearchAppBarState extends State<SearchAppBar> {
    
    
  // 焦点对象
  FocusNode _focusNode = FocusNode();
  // 文本的值
  String searchVal = '';
  //用于清空输入框
  TextEditingController _controller = TextEditingController();

  void initState() {
    
    
    super.initState();
    //  获取焦点
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
    
    
      _focusNode.requestFocus();
    });
  }

  
  Widget build(BuildContext context) {
    
    
    // 获取屏幕尺寸
    MediaQueryData queryData = MediaQuery.of(context);
    return Container(
      // 宽度为屏幕的0.8
      width: queryData.size.width * 0.8,
      // appBar默认高度是56,这里搜索框设置为40
      height: 40,
      // 设置padding
      padding: EdgeInsets.only(left: 20),
      // 设置子级位置
      alignment: Alignment.centerLeft,
      // 设置修饰
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(10), color: Colors.white),
      child: TextField(
        controller: _controller,
        // 自动获取焦点
        focusNode: _focusNode,
        autofocus: true,
        decoration: InputDecoration(
            hintText: widget.hintLabel,
            hintStyle: TextStyle(color: Colors.grey),
            // 取消掉文本框下面的边框
            border: InputBorder.none,
            icon: Padding(
                padding: const EdgeInsets.only(left: 0, top: 0),
                child: Icon(
                  Icons.search,
                  size: 18,
                  color: Theme.of(context).primaryColor,
                )),
            //  关闭按钮,有值时才显示
            suffixIcon: this.searchVal.isNotEmpty
                ? IconButton(
                    icon: Icon(Icons.close),
                    onPressed: () {
    
    
                      //   清空内容
                      setState(() {
    
    
                        this.searchVal = '';
                        _controller.clear();
                      });
                    },
                  )
                : null),
        onChanged: (value) {
    
    
          setState(() {
    
    
            this.searchVal = value;
          });
        },
        onSubmitted: (value) {
    
    
          widget.onSubmitted(value);
        },
      ),
    );
  }
}

search history

effect
insert image description here
code

import 'package:flutter/material.dart';

/**
 * 搜索历史
 */

class SearchHistory extends StatefulWidget {
    
    
  List<String> list;
  final Function() clearHistory;
  SearchHistory({
    
    Key? key, required this.list, required this.clearHistory})
      : super(key: key) {
    
    
    list.removeWhere((element) => element.isEmpty);
  }
  
  State<StatefulWidget> createState() => _SearchHistoryState();
}

class _SearchHistoryState extends State<SearchHistory> {
    
    
  
  Widget build(BuildContext context) {
    
    
    return Column(
      // 设置内容靠左
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        SizedBox(
          height: 30,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              //添加一个padding
              Padding(
                padding: EdgeInsets.only(left: 10),
                child: Text(
                  '搜索历史',
                  style: TextStyle(color: Colors.grey, fontSize: 12),
                ),
              ),
              // 构建一个文本按钮
              GestureDetector(
                onTap: () {
    
    
                  widget.clearHistory();
                },
                child: Padding(
                  padding: EdgeInsets.only(right: 10),
                  child: Text(
                    widget.list.isNotEmpty ? '清空历史' : '',
                    style: TextStyle(
                      fontSize: 12,
                      color: Colors.grey,
                    ),
                  ),
                ),
              )
            ],
          ),
        ),
        Expanded(
          child: SingleChildScrollView(
            padding: EdgeInsets.all(2),
            child: Wrap(
              children: List.generate(
                  widget.list.length, (index) => _listItem(widget.list[index])),
            ),
          ),
        )
      ],
    );
  }

  //  构建子组件
  _listItem(String title) {
    
    
    // FittedBox用于调整其子部件的大小以适应可用空间
    return FittedBox(
      fit: BoxFit.scaleDown,
      alignment: Alignment.centerLeft,
      child: Container(
        padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
        margin: EdgeInsets.all(5),
        decoration: BoxDecoration(
            color: Colors.grey.withOpacity(0.5),
            borderRadius: BorderRadius.circular(10)),
        child: Text(
          title,
          style: TextStyle(fontSize: 12),
        ),
      ),
    );
  }
}

Guess you like

Origin blog.csdn.net/weixin_41897680/article/details/131523726
Recommended