搜索框与抽屉冲突问题
							parent
							
								
									fa4b765565
								
							
						
					
					
						commit
						e7fbd5e12c
					
				|  | @ -184,6 +184,7 @@ class _DepartmentPickerState extends State<DepartmentPicker> { | |||
|                       controller: _searchController, | ||||
|                       isShowSearchButton: false, | ||||
|                       onSearch: (keyboard) { | ||||
| 
 | ||||
|                       }, | ||||
|                     ), | ||||
|                   ), | ||||
|  |  | |||
|  | @ -1,43 +1,59 @@ | |||
| import 'package:flutter/material.dart'; | ||||
| 
 | ||||
| class SearchBarWidget extends StatelessWidget { | ||||
| class SearchBarWidget extends StatefulWidget { | ||||
|   final String hintText; | ||||
|   final String buttonText; | ||||
|   final ValueChanged<String> onSearch; | ||||
|   final TextEditingController controller; // 改为必传参数 | ||||
|   final bool autoFocus; | ||||
|   final TextEditingController controller; | ||||
|   final bool showResetButton; | ||||
|   final String resetButtonText; | ||||
|   final VoidCallback? onReset; | ||||
|   final bool isClickableOnly; | ||||
|   final VoidCallback? onInputTap; | ||||
|   final ValueChanged<String>? onTextChanged; // 新增文本变化回调 | ||||
|   final ValueChanged<String>? onTextChanged; | ||||
|   final bool isShowSearchButton; | ||||
| 
 | ||||
|   const SearchBarWidget({ | ||||
|     Key? key, | ||||
|     required this.onSearch, | ||||
|     required this.controller, // 必须传入controller | ||||
|     required this.controller, | ||||
|     this.hintText = '请输入关键字', | ||||
|     this.buttonText = '搜索', | ||||
|     this.autoFocus = false, | ||||
|     this.showResetButton = false, | ||||
|     this.resetButtonText = '重置', | ||||
|     this.onReset, | ||||
|     this.isClickableOnly = false, | ||||
|     this.onInputTap, | ||||
|     this.onTextChanged, // 可选文本变化监听 | ||||
|     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) { | ||||
|     controller.text = newText; | ||||
|     controller.selection = TextSelection.fromPosition( | ||||
|     widget.controller.text = newText; | ||||
|     widget.controller.selection = TextSelection.fromPosition( | ||||
|       TextPosition(offset: newText.length), | ||||
|     ); | ||||
|     // 可选:触发文本变化回调 | ||||
|     onTextChanged?.call(newText); | ||||
|     widget.onTextChanged?.call(newText); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|  | @ -45,22 +61,24 @@ class SearchBarWidget extends StatelessWidget { | |||
|     return Row( | ||||
|       children: [ | ||||
|         Expanded( | ||||
|           child: GestureDetector( | ||||
|             onTap: isClickableOnly ? onInputTap : null, | ||||
|             child: AbsorbPointer( | ||||
|               absorbing: isClickableOnly, | ||||
|           child: TextField( | ||||
|                 controller: controller, | ||||
|                 autofocus: autoFocus, | ||||
|                 readOnly: isClickableOnly, | ||||
|             focusNode: _focusNode, | ||||
|             controller: widget.controller, | ||||
|             readOnly: widget.isClickableOnly, | ||||
|             autofocus: false, | ||||
|             style: const TextStyle(fontSize: 15), | ||||
|                 onChanged: onTextChanged, | ||||
|                 // 监听文本变化 | ||||
|             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: hintText, | ||||
|               hintText: widget.hintText, | ||||
|               border: OutlineInputBorder( | ||||
|                 borderRadius: BorderRadius.circular(5), | ||||
|                 borderSide: BorderSide.none, | ||||
|  | @ -68,16 +86,13 @@ class SearchBarWidget extends StatelessWidget { | |||
|               isDense: true, | ||||
|               contentPadding: const EdgeInsets.symmetric(vertical: 8), | ||||
|             ), | ||||
|                 onSubmitted: onSearch, | ||||
|               ), | ||||
|             ), | ||||
|             onSubmitted: widget.onSearch, | ||||
|           ), | ||||
|         ), | ||||
|         const SizedBox(width: 10), | ||||
|         if (isShowSearchButton) | ||||
|           // 搜索按钮 | ||||
|         if (widget.isShowSearchButton) | ||||
|           ElevatedButton( | ||||
|             onPressed: () => onSearch(controller.text.trim()), | ||||
|             onPressed: () => widget.onSearch(widget.controller.text.trim()), | ||||
|             style: ElevatedButton.styleFrom( | ||||
|               backgroundColor: Colors.green, | ||||
|               padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), | ||||
|  | @ -88,17 +103,16 @@ class SearchBarWidget extends StatelessWidget { | |||
|               shadowColor: Colors.black45, | ||||
|             ), | ||||
|             child: Text( | ||||
|               buttonText, | ||||
|               widget.buttonText, | ||||
|               style: const TextStyle(color: Colors.white, fontSize: 16), | ||||
|             ), | ||||
|           ), | ||||
|         // 重置按钮 | ||||
|         if (showResetButton) const SizedBox(width: 10), | ||||
|         if (showResetButton) | ||||
|         if (widget.showResetButton) const SizedBox(width: 10), | ||||
|         if (widget.showResetButton) | ||||
|           ElevatedButton( | ||||
|             onPressed: () { | ||||
|               updateText(''); // 使用统一方法清空 | ||||
|               onReset?.call(); | ||||
|               updateText(''); | ||||
|               widget.onReset?.call(); | ||||
|             }, | ||||
|             style: ElevatedButton.styleFrom( | ||||
|               backgroundColor: Colors.blue, | ||||
|  | @ -110,8 +124,8 @@ class SearchBarWidget extends StatelessWidget { | |||
|               shadowColor: Colors.black26, | ||||
|             ), | ||||
|             child: Text( | ||||
|               resetButtonText, | ||||
|               style: TextStyle(color: Colors.white, fontSize: 16), | ||||
|               widget.resetButtonText, | ||||
|               style: const TextStyle(color: Colors.white, fontSize: 16), | ||||
|             ), | ||||
|           ), | ||||
|       ], | ||||
|  |  | |||
|  | @ -73,7 +73,7 @@ class MyApp extends StatelessWidget { | |||
|           behavior: HitTestBehavior.translucent, // 让空白区域也能点击 | ||||
|           onTap: () { | ||||
|             // 收起键盘 | ||||
|             FocusScope.of(context).requestFocus(_blankFocusNode); | ||||
|             FocusScope.of(context).unfocus(); | ||||
|           }, | ||||
|           child: child, | ||||
|         ); | ||||
|  |  | |||
|  | @ -76,22 +76,25 @@ class _CheckRecordPageState extends State<CheckRecordPage> { | |||
|   Widget build(BuildContext context) { | ||||
|     // 取屏幕宽度 | ||||
|     final double screenWidth = MediaQuery.of(context).size.width; | ||||
|     final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); | ||||
| 
 | ||||
|     return Scaffold( | ||||
|       key: _scaffoldKey, // ② 绑定 key | ||||
| 
 | ||||
|       appBar: MyAppbar( | ||||
|         title: appBarTitle, | ||||
|         actions: [ | ||||
|           TextButton( | ||||
|           // 用 Builder 拿到 Scaffold 之下的 context | ||||
|           Builder( | ||||
|             builder: (innerContext) { | ||||
|               return TextButton( | ||||
|                 onPressed: () { | ||||
|               _scaffoldKey.currentState?.openEndDrawer(); | ||||
|                   // 通过 innerContext 调用 openEndDrawer | ||||
|                   Scaffold.of(innerContext).openEndDrawer(); | ||||
|                 }, | ||||
|                 child: Text( | ||||
|                   "查询", | ||||
|                   style: TextStyle(color: Colors.white, fontSize: 16), | ||||
|                 ), | ||||
|               ); | ||||
|             }, | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|  | @ -145,8 +148,9 @@ class _CheckRecordPageState extends State<CheckRecordPage> { | |||
|             padding: EdgeInsets.all(10), | ||||
|             child: SearchBarWidget( | ||||
|               controller: _searchController, | ||||
|               autoFocus: true, | ||||
| 
 | ||||
|               onSearch: (keyboard) { | ||||
| 
 | ||||
|                 // 输入请求接口 | ||||
|                 _page=1; | ||||
|                 searchKey=keyboard; | ||||
|  |  | |||
|  | @ -60,7 +60,6 @@ class _DangerWaitListPageState extends State<DangerWaitListPage> { | |||
| 
 | ||||
|   // 隐患等级文本 | ||||
|   final List<String> _levelTexts = ["重大隐患","一般隐患"]; | ||||
|   final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|  | @ -101,20 +100,23 @@ class _DangerWaitListPageState extends State<DangerWaitListPage> { | |||
|     final double screenWidth = MediaQuery.of(context).size.width; | ||||
| 
 | ||||
|     return Scaffold( | ||||
|       key: _scaffoldKey, // ② 绑定 key | ||||
|       appBar: MyAppbar( | ||||
|         title: widget.dangerType.displayName, | ||||
|         actions: [ | ||||
|           if(1==widget.appItem) | ||||
|           TextButton( | ||||
|           if (1 == widget.appItem) | ||||
|             Builder( | ||||
|               builder: (innerContext) { | ||||
|                 return TextButton( | ||||
|                   onPressed: () { | ||||
|               // 查询 右侧弹窗页面 | ||||
|               _scaffoldKey.currentState?.openEndDrawer(); | ||||
|                     // 通过 innerContext 拿到 ScaffoldState,打开右侧抽屉 | ||||
|                     Scaffold.of(innerContext).openEndDrawer(); | ||||
|                   }, | ||||
|                   child: Text( | ||||
|                     "查询", | ||||
|                     style: TextStyle(color: Colors.white, fontSize: 16), | ||||
|                   ), | ||||
|                 ); | ||||
|               }, | ||||
|             ), | ||||
|         ], | ||||
|       ), | ||||
|  |  | |||
|  | @ -39,7 +39,6 @@ class _RiskControlPageState extends State<RiskControlPage> { | |||
| 
 | ||||
|   // 风险等级文本 | ||||
|   final List<String> _levelTexts = ["重大风险/A级", "较大风险/B级", "一般风险/C级", "低风险/D级"]; | ||||
|   final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); | ||||
| 
 | ||||
| 
 | ||||
|   @override | ||||
|  | @ -59,19 +58,23 @@ class _RiskControlPageState extends State<RiskControlPage> { | |||
|     final double screenWidth = MediaQuery.of(context).size.width; | ||||
| 
 | ||||
|     return Scaffold( | ||||
|       key: _scaffoldKey, // ② 绑定 key | ||||
|       appBar: MyAppbar( | ||||
|         title: "风险分布", | ||||
|         actions: [ | ||||
|           TextButton( | ||||
|           // 用 Builder 拿到 Scaffold 之下的 context | ||||
|           Builder( | ||||
|             builder: (innerContext) { | ||||
|               return TextButton( | ||||
|                 onPressed: () { | ||||
|               // 查询 右侧弹窗页面 | ||||
|               _scaffoldKey.currentState?.openEndDrawer(); | ||||
|                   // 通过 innerContext 调用 openEndDrawer | ||||
|                   Scaffold.of(innerContext).openEndDrawer(); | ||||
|                 }, | ||||
|                 child: Text( | ||||
|                   "查询", | ||||
|                   style: TextStyle(color: Colors.white, fontSize: 16), | ||||
|                 ), | ||||
|               ); | ||||
|             }, | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|  |  | |||
							
								
								
									
										290
									
								
								pubspec.lock
								
								
								
								
							
							
						
						
									
										290
									
								
								pubspec.lock
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue