Flutter 搜索建议栏

前言

在平时各类各样的软件中都会有搜索栏方便各位进行信息的搜索,下面就用flutter撸一个搜索栏建议。git

实现效果

有内容的时候显示建议内容以及删除icon,点击icon删除内容而且移除建议内容。

主要源码

  • 构建TextField

这里关键点主要仍是key,主要用于获取当前TextFiled的位置。github

GlobalKey textFieldKey;
TextEditingController _searchController = TextEditingController();
FocusNode _searchFocus = FocusNode();

TextField(
          key: textFieldKey,
          controller: _searchController,
          focusNode: _searchFocus,
          cursorColor: Colors.black,
          decoration: InputDecoration(
              suffixIcon: !_searchFocus.hasFocus
                  ? null
                  : _searchController.text.isEmpty
                      ? null
                      : IconButton(
                          icon: Icon(
                            Icons.close,
                            color: Colors.black,
                          ),
                          onPressed: () {},
                        ),
              focusedBorder: UnderlineInputBorder(
                  borderSide: BorderSide(color: Colors.black)))
        )
复制代码
  • 构建Overlay

findOverLayPosition是根据key来获取当前TextFiled的位置,Positioned中的位置能够根据本身的需求进行调整,高度在这里我是根据获取到的内容条数来进行设置的。async

void findOverLayPosition() {
    RenderBox renderBox = textFieldKey.currentContext.findRenderObject();
    height = renderBox.size.height;
    width = renderBox.size.width;
    Offset offset = renderBox.localToGlobal(Offset.zero);
    xPosition = offset.dx;
    yPosition = offset.dy;
}
  
  // 生成搜索建议
OverlayEntry _buildSearchSuggest() {
    return OverlayEntry(builder: (context) {
      return Positioned(
        left: xPosition - 40.0,
        width: width + 40.0,
        top: yPosition + height + 10,
        height: _keywords.length * height,
        child: Material(
          child: Container(
              height: _keywords.length * height,
              decoration: BoxDecoration(color: Colors.white, boxShadow: [
                BoxShadow(
                  color: Colors.black12,
                  blurRadius: 5.0,
                ),
              ]),
              child: ListView.builder(
                  padding: EdgeInsets.zero,
                  itemBuilder: (context, index) {
                    return InkWell(
                        onTap: () {
                          searchSuggest.remove();
                          searchSuggest = null;
                          search2detail(_keywords[index]);
                        },
                        child: SearchItem(
                          text: _keywords[index],
                          itemHeight: height,
                          isFirstItem: index == 0 ? true : false,
                          isLastItem:
                              index == _keywords.length - 1 ? true : false,
                        ));
                  },
                  itemCount: _keywords.length)),
        ),
      );
    });
  }
  
复制代码
  • 插入Overlay

在这里我是在TextField的ontap方法中获取TextField位置信息的,而后当TextField内容发生变化的时候就插入Overlay,在onSubmitted的时候把Overlay给移除。ide

OverlayEntry searchSuggest;
    
onTap: () {
    findDropdownPosition();
    setState(() {});
    },
onChanged: (value) async {
    if (value.isNotEmpty) {
        if (searchSuggest != null) removeOverlay();

        searchSuggest = _buildSearchSuggest();
        OverlayState overlayState = Overlay.of(context);
        overlayState.insert(searchSuggest);
    else {
        if (searchSuggest != null) removeOverlay();
        }
        setState(() {});
    },
onSubmitted: (value) {
        searchSuggest.remove();
        searchSuggest = null;
         }
复制代码

最后

在实现点击删除按钮把TextFiled内容清除的时候出现了个问题ui

invalid text selection: TextSelection(baseOffset: 2, extentOffset: 2, affinity:TextAffinity.upstream, isDirectional: false) spa

解决方法: 只须要添加小延迟就行了,具体能够看这个issuecode

Future.delayed(Duration(microseconds: 20), () {
    _searchController.clear();
    _searchFocus.unfocus();
    if (searchSuggest != null) removeOverlay();
});
复制代码

详细内容能够查看这里 代码地址cdn

相关文章
相关标签/搜索