135 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'package:flutter/material.dart';
 | |
| 
 | |
| class SearchBarWidget extends StatefulWidget {
 | |
|   final String hintText;
 | |
|   final String buttonText;
 | |
|   final ValueChanged<String> onSearch;
 | |
|   final TextEditingController controller;
 | |
|   final bool showResetButton;
 | |
|   final String resetButtonText;
 | |
|   final VoidCallback? onReset;
 | |
|   final bool isClickableOnly;
 | |
|   final VoidCallback? onInputTap;
 | |
|   final ValueChanged<String>? onTextChanged;
 | |
|   final bool isShowSearchButton;
 | |
| 
 | |
|   const SearchBarWidget({
 | |
|     Key? key,
 | |
|     required this.onSearch,
 | |
|     required this.controller,
 | |
|     this.hintText = '请输入关键字',
 | |
|     this.buttonText = '搜索',
 | |
|     this.showResetButton = false,
 | |
|     this.resetButtonText = '重置',
 | |
|     this.onReset,
 | |
|     this.isClickableOnly = false,
 | |
|     this.onInputTap,
 | |
|     this.onTextChanged,
 | |
|     this.isShowSearchButton = true,
 | |
|   }) : super(key: key);
 | |
| 
 | |
|   @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();
 | |
|   }
 | |
| 
 | |
|   /// 更新输入框内容(可在外部调用)
 | |
|   void updateText(String newText) {
 | |
|     widget.controller.text = newText;
 | |
|     widget.controller.selection = TextSelection.fromPosition(
 | |
|       TextPosition(offset: newText.length),
 | |
|     );
 | |
|     widget.onTextChanged?.call(newText);
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     return Row(
 | |
|       children: [
 | |
|         Expanded(
 | |
|           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,
 | |
|               ),
 | |
|               isDense: true,
 | |
|               contentPadding: const EdgeInsets.symmetric(vertical: 8),
 | |
|             ),
 | |
|             onSubmitted: widget.onSearch,
 | |
|           ),
 | |
|         ),
 | |
|         const SizedBox(width: 10),
 | |
|         if (widget.isShowSearchButton)
 | |
|           ElevatedButton(
 | |
|             onPressed: () => widget.onSearch(widget.controller.text.trim()),
 | |
|             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,
 | |
|             ),
 | |
|             child: Text(
 | |
|               widget.buttonText,
 | |
|               style: const TextStyle(color: Colors.white, fontSize: 16),
 | |
|             ),
 | |
|           ),
 | |
|         if (widget.showResetButton) const SizedBox(width: 10),
 | |
|         if (widget.showResetButton)
 | |
|           ElevatedButton(
 | |
|             onPressed: () {
 | |
|               updateText('');
 | |
|               widget.onReset?.call();
 | |
|             },
 | |
|             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(
 | |
|               widget.resetButtonText,
 | |
|               style: const TextStyle(color: Colors.white, fontSize: 16),
 | |
|             ),
 | |
|           ),
 | |
|       ],
 | |
|     );
 | |
|   }
 | |
| }
 |