基于TextField实现通用搜索组件

search_bar.dart


enum SearchBarType { home, normal, homeLight }

/// 通用搜索组件
class SearchBar extends StatefulWidget {
  final bool enabled;

  // 是否隐藏左侧图标
  final bool hideLeft;

  // 搜索框类型
  final SearchBarType searchBarType;

  // 提示信息
  final String hint;

  // 默认输入内容
  final String defaultText;

  // 左侧图标点击
  final void Function() leftButtonClick;

  // 右侧图标点击
  final void Function() rightButtonClick;

  // 语音图标点击
  final void Function() speackClick;

  // 输入框点击
  final void Function() inputBoxClick;

  // 输入框文本变化
  final ValueChanged<String> onChanged;

  const SearchBar(
      {Key key,
      this.enabled = true,
      this.hideLeft,
      this.searchBarType = SearchBarType.normal,
      this.hint,
      this.defaultText,
      this.leftButtonClick,
      this.rightButtonClick,
      this.speackClick,
      this.inputBoxClick,
      this.onChanged})
      : super(key: key);

  @override
  _SearchBarState createState() => _SearchBarState();
}

class _SearchBarState extends State<SearchBar> {
  // 是否显示清除按钮
  bool showClear = false;

  // 输入框文本控制器
  final TextEditingController _controller = TextEditingController();

  @override
  void initState() {
    super.initState();
    // 初始化输入框文本内容
    if (widget.defaultText != null) {
      setState(() {
        _controller.text = widget.defaultText;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    // 根据输入框类型构建不同样式的输入框
    return widget.searchBarType == SearchBarType.normal
        ? _genNormalSearch()
        : _genHomeSearch();
  }

  /// 构建首页搜索组件样式
  _genHomeSearch() {
    return Container(
      child: Row(
        children: [
          // 左侧图标
          _wrapTap(
              Container(
                  padding: EdgeInsets.fromLTRB(6, 5, 5, 5),
                  child: Row(
                    children: [
                      Text('上海',
                          style: TextStyle(
                              color: _homeFrontColor(), fontSize: 14)),
                      Icon(Icons.expand_more,
                          color: _homeFrontColor(), size: 22)
                    ],
                  )),
              widget.leftButtonClick),
          // 搜索框
          Expanded(child: _inputBox(), flex: 1),
          // 右侧消息图标
          _wrapTap(
              Container(
                padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
                child: Icon(
                  Icons.comment,
                  color: _homeFrontColor(),
                  size: 26,
                ),
              ),
              widget.rightButtonClick)
        ],
      ),
    );
  }

  /// 构建通用搜索组件样式
  _genNormalSearch() {
    return Container(
      child: Row(
        children: [
          // 左侧图标
          _wrapTap(
              Container(
                padding: EdgeInsets.fromLTRB(6, 5, 10, 5),
                child: widget.hideLeft ?? false
                    ? null
                    : Icon(
                        Icons.arrow_back_ios,
                        size: 26,
                        color: Colors.grey,
                      ),
              ),
              widget.leftButtonClick),
          // 搜索框
          Expanded(child: _inputBox(), flex: 1),
          // 右侧搜索文字
          _wrapTap(
              Container(
                padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
                child: Text('搜索',
                    style: TextStyle(color: Colors.blue, fontSize: 17)),
              ),
              widget.rightButtonClick)
        ],
      ),
    );
  }

  /// 构建搜索框
  Widget _inputBox() {
    Color inputBoxColor;
    if (widget.searchBarType == SearchBarType.normal) {
      inputBoxColor = Colors.white;
    } else {
      inputBoxColor = Color(int.parse('0xffEDEDED'));
    }
    return Container(
      height: 30,
      padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
      // 搜索组件样式(设置背景色以及圆角)
      decoration: BoxDecoration(
          color: inputBoxColor,
          borderRadius: BorderRadius.circular(
              widget.searchBarType == SearchBarType.normal ? 5 : 15)),
      child: Row(
        children: [
          //搜索图标
          Icon(Icons.search,
              size: 20,
              color: widget.searchBarType == SearchBarType.normal
                  ? Color(0xffA9A9A9)
                  : Colors.blue),
          // 输入框
          Expanded(
              child: widget.searchBarType == SearchBarType.normal
                  ? TextField(
                      controller: _controller,
                      onChanged: _onChanged,
                      autofocus: true,
                      style: TextStyle(
                          fontSize: 18,
                          color: Colors.black,
                          fontWeight: FontWeight.w300),
                      // 输入文本样式
                      decoration: InputDecoration(
                          contentPadding: EdgeInsets.fromLTRB(5, 0, 5, 0),
                          border: InputBorder.none,
                          hintText: widget.hint ?? '',
                          hintStyle: TextStyle(fontSize: 15)),
                    )
                  : _wrapTap(
                      // 首页搜索组件样式
                      Container(
                        child: Text(
                          widget.defaultText,
                          style: TextStyle(fontSize: 13, color: Colors.grey),
                        ),
                      ),
                      widget.inputBoxClick)),
          !showClear
              ? _wrapTap(
                  // 语音图标
                  Icon(
                    Icons.mic,
                    size: 22,
                    color: widget.searchBarType == SearchBarType.normal
                        ? Colors.blue
                        : Colors.grey,
                  ),
                  widget.speackClick)
              : _wrapTap(
                  // 清除图标
                  Icon(
                    Icons.clear,
                    size: 22,
                    color: Colors.grey,
                  ), () {
                  // 清空搜索内容
                  setState(() {
                    _controller.clear();
                  });
                  // 清空输入框内容
                  _onChanged('');
                })
        ],
      ),
    );
  }

  /// 输入框监听文本变化
  _onChanged(String text) {
    if (text.length > 0) {
      setState(() {
        showClear = true;
      });
    } else {
      setState(() {
        showClear = false;
      });
    }
    // 回调输入的内容
    if (widget.onChanged != null) {
      widget.onChanged(text);
    }
  }

  /// 首页前景色
  _homeFrontColor() {
    return widget.searchBarType == SearchBarType.normal
        ? Colors.black54
        : Colors.white;
  }

  // 返回自带点击事件的widget
  _wrapTap(Widget widget, void Function() callback) {
    return GestureDetector(
      onTap: () {
        if (callback != null) callback();
      },
      child: widget,
    );
  }
}

使用

SearchBar(
            searchBarType: appBarAlpha > 0.2
                ? SearchBarType.homeLight
                : SearchBarType.home,
            inputBoxClick: _jumpToSearch,
            speackClick: _jumpToSpeak,
       		// 输入框提示信息
            defaultText: SEARCH_BAR_DEFAULT_TEXT,
            leftButtonClick: () {},
          )
          
  /// 跳转到搜索页
  void _jumpToSearch() {}

  /// 跳转到语音识别页面
  void _jumpToSpeak() {}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值