| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  | class SearchBarWidget extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |   final String hintText; | 
					
						
							|  |  |  |   final String buttonText; | 
					
						
							|  |  |  |   final ValueChanged<String> onSearch; | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |   final TextEditingController controller; | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |   final bool showResetButton; | 
					
						
							|  |  |  |   final String resetButtonText; | 
					
						
							|  |  |  |   final VoidCallback? onReset; | 
					
						
							|  |  |  |   final bool isClickableOnly; | 
					
						
							|  |  |  |   final VoidCallback? onInputTap; | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |   final ValueChanged<String>? onTextChanged; | 
					
						
							| 
									
										
										
										
											2025-07-24 11:18:47 +08:00
										 |  |  |   final bool isShowSearchButton; | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const SearchBarWidget({ | 
					
						
							|  |  |  |     Key? key, | 
					
						
							|  |  |  |     required this.onSearch, | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |     required this.controller, | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |     this.hintText = '请输入关键字', | 
					
						
							|  |  |  |     this.buttonText = '搜索', | 
					
						
							|  |  |  |     this.showResetButton = false, | 
					
						
							|  |  |  |     this.resetButtonText = '重置', | 
					
						
							|  |  |  |     this.onReset, | 
					
						
							|  |  |  |     this.isClickableOnly = false, | 
					
						
							|  |  |  |     this.onInputTap, | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |     this.onTextChanged, | 
					
						
							| 
									
										
										
										
											2025-07-24 11:18:47 +08:00
										 |  |  |     this.isShowSearchButton = true, | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |   }) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   _SearchBarWidgetState createState() => _SearchBarWidgetState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _SearchBarWidgetState extends State<SearchBarWidget> { | 
					
						
							|  |  |  |   late FocusNode _focusNode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     _focusNode = FocusNode(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     _focusNode.dispose(); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// 更新输入框内容(可在外部调用)
 | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |   void updateText(String newText) { | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |     widget.controller.text = newText; | 
					
						
							|  |  |  |     widget.controller.selection = TextSelection.fromPosition( | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |       TextPosition(offset: newText.length), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |     widget.onTextChanged?.call(newText); | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Row( | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         Expanded( | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |           child: TextField( | 
					
						
							|  |  |  |             focusNode: _focusNode, | 
					
						
							|  |  |  |             controller: widget.controller, | 
					
						
							|  |  |  |             readOnly: widget.isClickableOnly, | 
					
						
							|  |  |  |             autofocus: false, | 
					
						
							|  |  |  |             style: const TextStyle(fontSize: 15), | 
					
						
							|  |  |  |             onChanged: widget.onTextChanged, | 
					
						
							|  |  |  |             onTap: () { | 
					
						
							|  |  |  |               if (widget.isClickableOnly) { | 
					
						
							|  |  |  |                 // 可点击但不弹出键盘
 | 
					
						
							|  |  |  |                 widget.onInputTap?.call(); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             decoration: InputDecoration( | 
					
						
							|  |  |  |               filled: true, | 
					
						
							|  |  |  |               fillColor: const Color(0xFFF5F5F5), | 
					
						
							|  |  |  |               prefixIcon: const Icon(Icons.search_rounded), | 
					
						
							|  |  |  |               hintText: widget.hintText, | 
					
						
							|  |  |  |               border: OutlineInputBorder( | 
					
						
							|  |  |  |                 borderRadius: BorderRadius.circular(5), | 
					
						
							|  |  |  |                 borderSide: BorderSide.none, | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |               ), | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |               isDense: true, | 
					
						
							|  |  |  |               contentPadding: const EdgeInsets.symmetric(vertical: 8), | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |             ), | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |             onSubmitted: widget.onSearch, | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         const SizedBox(width: 10), | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |         if (widget.isShowSearchButton) | 
					
						
							| 
									
										
										
										
											2025-07-24 11:18:47 +08:00
										 |  |  |           ElevatedButton( | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |             onPressed: () => widget.onSearch(widget.controller.text.trim()), | 
					
						
							| 
									
										
										
										
											2025-07-24 11:18:47 +08:00
										 |  |  |             style: ElevatedButton.styleFrom( | 
					
						
							|  |  |  |               backgroundColor: Colors.green, | 
					
						
							|  |  |  |               padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), | 
					
						
							|  |  |  |               shape: RoundedRectangleBorder( | 
					
						
							|  |  |  |                 borderRadius: BorderRadius.circular(5), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               elevation: 4, | 
					
						
							|  |  |  |               shadowColor: Colors.black45, | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |             ), | 
					
						
							| 
									
										
										
										
											2025-07-24 11:18:47 +08:00
										 |  |  |             child: Text( | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |               widget.buttonText, | 
					
						
							| 
									
										
										
										
											2025-07-24 11:18:47 +08:00
										 |  |  |               style: const TextStyle(color: Colors.white, fontSize: 16), | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |         if (widget.showResetButton) const SizedBox(width: 10), | 
					
						
							|  |  |  |         if (widget.showResetButton) | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |           ElevatedButton( | 
					
						
							|  |  |  |             onPressed: () { | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |               updateText(''); | 
					
						
							|  |  |  |               widget.onReset?.call(); | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |             }, | 
					
						
							|  |  |  |             style: ElevatedButton.styleFrom( | 
					
						
							|  |  |  |               backgroundColor: Colors.blue, | 
					
						
							|  |  |  |               padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), | 
					
						
							|  |  |  |               shape: RoundedRectangleBorder( | 
					
						
							|  |  |  |                 borderRadius: BorderRadius.circular(5), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               elevation: 1, | 
					
						
							|  |  |  |               shadowColor: Colors.black26, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             child: Text( | 
					
						
							| 
									
										
										
										
											2025-07-30 11:20:11 +08:00
										 |  |  |               widget.resetButtonText, | 
					
						
							|  |  |  |               style: const TextStyle(color: Colors.white, fontSize: 16), | 
					
						
							| 
									
										
										
										
											2025-07-11 11:03:21 +08:00
										 |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-07-24 11:18:47 +08:00
										 |  |  | } |