前言
在平時各種各樣的軟體中都會有搜尋欄方便各位進行資訊的搜尋,下面就用flutter擼一個搜尋欄建議。
實現效果
有內容的時候顯示建議內容以及刪除icon,點選icon刪除內容並且移除建議內容。主要原始碼
- 構建TextField
這裡關鍵點主要還是key,主要用於獲取當前TextFiled的位置。
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中的位置可以根據自己的需求進行調整,高度在這裡我是根據獲取到的內容條數來進行設定的。
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給移除。
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內容清除的時候出現了個問題
invalid text selection: TextSelection(baseOffset: 2, extentOffset: 2, affinity:TextAffinity.upstream, isDirectional: false)
解決方法: 只需要新增小延遲就好了,具體可以看這個issue
Future.delayed(Duration(microseconds: 20), () {
_searchController.clear();
_searchFocus.unfocus();
if (searchSuggest != null) removeOverlay();
});
複製程式碼
詳細內容可以檢視這裡 程式碼地址