| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  | /// 对话框模式
 | 
					
						
							|  |  |  | enum DialogMode { text, input } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CustomAlertDialog extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |   final String title; | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |   final String content; // 文字模式下显示
 | 
					
						
							|  |  |  |   final String hintText; // 输入模式下提示
 | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |   final String cancelText; | 
					
						
							|  |  |  |   final String confirmText; | 
					
						
							|  |  |  |   final VoidCallback? onCancel; | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |   final VoidCallback? onConfirm; // 文字模式回调
 | 
					
						
							|  |  |  |   final ValueChanged<String>? onInputConfirm; // 输入模式回调
 | 
					
						
							|  |  |  |   final DialogMode mode; // 新增:对话框模式
 | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const CustomAlertDialog({ | 
					
						
							|  |  |  |     Key? key, | 
					
						
							|  |  |  |     required this.title, | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |     this.content = '', | 
					
						
							|  |  |  |     this.hintText = '', | 
					
						
							|  |  |  |     this.cancelText = '取消', | 
					
						
							|  |  |  |     this.confirmText = '确定', | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |     this.onCancel, | 
					
						
							|  |  |  |     this.onConfirm, | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |     this.onInputConfirm, | 
					
						
							|  |  |  |     this.mode = DialogMode.text, // 默认文字模式
 | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |   }) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |   _CustomAlertDialogState createState() => _CustomAlertDialogState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _CustomAlertDialogState extends State<CustomAlertDialog> { | 
					
						
							|  |  |  |   late TextEditingController _controller; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     // 输入模式下初始化 TextField
 | 
					
						
							|  |  |  |     _controller = TextEditingController(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     _controller.dispose(); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool get hasCancel => widget.cancelText.trim().isNotEmpty; | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |     return Dialog( | 
					
						
							|  |  |  |       backgroundColor: Colors.transparent, | 
					
						
							|  |  |  |       child: Container( | 
					
						
							|  |  |  |         decoration: BoxDecoration( | 
					
						
							|  |  |  |           color: Colors.white, | 
					
						
							|  |  |  |           borderRadius: BorderRadius.circular(5), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         child: Column( | 
					
						
							|  |  |  |           mainAxisSize: MainAxisSize.min, | 
					
						
							|  |  |  |           children: [ | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |             const SizedBox(height: 20), | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |             Text( | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |               widget.title, | 
					
						
							|  |  |  |               style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |               textAlign: TextAlign.center, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             const SizedBox(height: 20), | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // ★ 根据 mode 决定展示文字还是输入框 ★
 | 
					
						
							|  |  |  |             if (widget.mode == DialogMode.text) | 
					
						
							|  |  |  |               Padding( | 
					
						
							|  |  |  |                 padding: const EdgeInsets.symmetric(horizontal: 30), | 
					
						
							|  |  |  |                 child: Text( | 
					
						
							|  |  |  |                   widget.content, | 
					
						
							|  |  |  |                   style: const TextStyle(fontSize: 16, color: Colors.black45), | 
					
						
							|  |  |  |                   textAlign: TextAlign.center, | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ) | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |               Padding( | 
					
						
							|  |  |  |                 padding: const EdgeInsets.symmetric(horizontal: 20), | 
					
						
							|  |  |  |                 child: TextField( | 
					
						
							|  |  |  |                   controller: _controller, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                   decoration: InputDecoration( | 
					
						
							|  |  |  |                     hintText: widget.hintText, | 
					
						
							|  |  |  |                     border: const OutlineInputBorder(), | 
					
						
							|  |  |  |                     focusedBorder: OutlineInputBorder( | 
					
						
							|  |  |  |                       borderSide: BorderSide(color: Colors.blue, width: 1), | 
					
						
							|  |  |  |                       borderRadius: BorderRadius.circular(4), | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                     isDense: true, | 
					
						
							|  |  |  |                     contentPadding: const EdgeInsets.symmetric( | 
					
						
							|  |  |  |                       vertical: 10, | 
					
						
							|  |  |  |                       horizontal: 10, | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                   ), | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |               ), | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |             const SizedBox(height: 20), | 
					
						
							|  |  |  |             const Divider(height: 1), | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             hasCancel | 
					
						
							|  |  |  |                 ? _buildDoubleButtons(context) | 
					
						
							|  |  |  |                 : _buildSingleButton(context), | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildDoubleButtons(BuildContext context) { | 
					
						
							|  |  |  |     return Row( | 
					
						
							|  |  |  |       children: [ | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |         // 取消
 | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |         Expanded( | 
					
						
							|  |  |  |           child: InkWell( | 
					
						
							|  |  |  |             onTap: () { | 
					
						
							|  |  |  |               Navigator.of(context).pop(); | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |               widget.onCancel?.call(); | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |             }, | 
					
						
							|  |  |  |             child: Container( | 
					
						
							|  |  |  |               padding: const EdgeInsets.symmetric(vertical: 12), | 
					
						
							|  |  |  |               alignment: Alignment.center, | 
					
						
							|  |  |  |               child: Text( | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |                 widget.cancelText, | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |                 style: const TextStyle( | 
					
						
							|  |  |  |                   fontWeight: FontWeight.w500, | 
					
						
							|  |  |  |                   color: Colors.black, | 
					
						
							|  |  |  |                   fontSize: 18, | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |         Container(width: 1, height: 48, color: Colors.grey[300]), | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // 确定
 | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |         Expanded( | 
					
						
							|  |  |  |           child: InkWell( | 
					
						
							|  |  |  |             onTap: () { | 
					
						
							|  |  |  |               Navigator.of(context).pop(); | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |               if (widget.mode == DialogMode.text) { | 
					
						
							|  |  |  |                 widget.onConfirm?.call(); | 
					
						
							|  |  |  |               } else { | 
					
						
							|  |  |  |                 widget.onInputConfirm?.call(_controller.text.trim()); | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |             }, | 
					
						
							|  |  |  |             child: Container( | 
					
						
							|  |  |  |               padding: const EdgeInsets.symmetric(vertical: 12), | 
					
						
							|  |  |  |               alignment: Alignment.center, | 
					
						
							|  |  |  |               child: Text( | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |                 widget.confirmText, | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |                 style: const TextStyle( | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |                   color: Color(0xFF3874F6), | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |                   fontWeight: FontWeight.w500, | 
					
						
							|  |  |  |                   fontSize: 18, | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |               ), | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |             ), | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildSingleButton(BuildContext context) { | 
					
						
							|  |  |  |     return InkWell( | 
					
						
							|  |  |  |       onTap: () { | 
					
						
							|  |  |  |         Navigator.of(context).pop(); | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |         if (widget.mode == DialogMode.text) { | 
					
						
							|  |  |  |           widget.onConfirm?.call(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           widget.onInputConfirm?.call(_controller.text.trim()); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |       }, | 
					
						
							|  |  |  |       child: Container( | 
					
						
							|  |  |  |         width: double.infinity, | 
					
						
							|  |  |  |         padding: const EdgeInsets.symmetric(vertical: 14), | 
					
						
							|  |  |  |         alignment: Alignment.center, | 
					
						
							|  |  |  |         child: Text( | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |           widget.confirmText, | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |           style: const TextStyle( | 
					
						
							| 
									
										
										
										
											2025-07-28 14:22:07 +08:00
										 |  |  |             color: Color(0xFF3874F6), | 
					
						
							| 
									
										
										
										
											2025-07-22 13:34:34 +08:00
										 |  |  |             fontWeight: FontWeight.w500, | 
					
						
							|  |  |  |             fontSize: 18, | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2025-07-16 08:37:08 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |