233 lines
6.8 KiB
Dart
233 lines
6.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
|
import 'package:qhd_prevention/customWidget/dotted_border_box.dart';
|
|
|
|
class MultiTextFieldWithTitle extends StatefulWidget {
|
|
final String label;
|
|
final List<String> texts;
|
|
final bool isEditable;
|
|
final String hintText;
|
|
final double fontSize;
|
|
final bool isRequired;
|
|
final ValueChanged<List<String>> onTextsChanged;
|
|
|
|
const MultiTextFieldWithTitle({
|
|
super.key,
|
|
required this.label,
|
|
required this.isEditable,
|
|
required this.hintText,
|
|
required this.onTextsChanged,
|
|
this.fontSize = 15,
|
|
this.texts = const [],
|
|
this.isRequired = true,
|
|
});
|
|
|
|
@override
|
|
State<MultiTextFieldWithTitle> createState() =>
|
|
_MultiTextFieldWithTitleState();
|
|
}
|
|
|
|
class _MultiTextFieldWithTitleState extends State<MultiTextFieldWithTitle> {
|
|
final List<TextEditingController> _controllers = [];
|
|
final List<FocusNode> _focusNodes = [];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
// 延迟初始化,避免构建过程中调用 setState
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
if (mounted) {
|
|
_addTextField();
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
for (var controller in _controllers) {
|
|
controller.dispose();
|
|
}
|
|
for (var node in _focusNodes) {
|
|
node.dispose();
|
|
}
|
|
super.dispose();
|
|
}
|
|
|
|
void _addTextField() {
|
|
setState(() {
|
|
final newController = TextEditingController();
|
|
final newFocusNode = FocusNode();
|
|
|
|
newController.addListener(() {
|
|
widget.onTextsChanged(_getAllTexts());
|
|
});
|
|
|
|
_controllers.add(newController);
|
|
_focusNodes.add(newFocusNode);
|
|
widget.onTextsChanged(_getAllTexts());
|
|
});
|
|
}
|
|
|
|
void _removeTextField(int index) async {
|
|
if (_controllers.length <= 1) return;
|
|
await showDialog<String>(
|
|
context: context,
|
|
builder:
|
|
(_) => CustomAlertDialog(
|
|
title: '提示',
|
|
mode: DialogMode.text,
|
|
content: '确定删除检查情况吗?',
|
|
cancelText: '取消',
|
|
confirmText: '确定',
|
|
onConfirm: () {
|
|
setState(() {
|
|
_controllers[index].dispose();
|
|
_focusNodes[index].dispose();
|
|
|
|
_controllers.removeAt(index);
|
|
_focusNodes.removeAt(index);
|
|
widget.onTextsChanged(_getAllTexts());
|
|
});
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
List<String> _getAllTexts() {
|
|
return _controllers.map((c) => c.text).toList();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 标题行
|
|
InkWell(
|
|
child: Row(
|
|
children: [
|
|
Flexible(
|
|
fit: FlexFit.loose,
|
|
child: Row(
|
|
children: [
|
|
if (widget.isRequired && widget.isEditable)
|
|
Text('* ', style: TextStyle(color: Colors.red)),
|
|
Flexible(
|
|
child: Text(
|
|
widget.label,
|
|
style: TextStyle(
|
|
fontSize: widget.fontSize,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
if (widget.isEditable)
|
|
CustomButton(
|
|
text: " 添加 ",
|
|
height: 30,
|
|
padding: const EdgeInsets.symmetric(
|
|
vertical: 2,
|
|
horizontal: 5,
|
|
),
|
|
backgroundColor: Colors.blue,
|
|
onPressed: _addTextField,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
|
|
// 输入框区域 - 高度自适应
|
|
Column(
|
|
children: [
|
|
// 可编辑状态
|
|
if (widget.isEditable)
|
|
..._controllers.asMap().entries.map((entry) {
|
|
final index = entry.key;
|
|
return _buildTextFieldWithDelete(index);
|
|
}).toList(),
|
|
|
|
// 不可编辑状态
|
|
if (!widget.isEditable)
|
|
...widget.texts.map((c) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 8.0),
|
|
|
|
child: SizedBox(
|
|
width: double.maxFinite,
|
|
child: DottedBorderBox(
|
|
child:
|
|
Text(
|
|
c,
|
|
style: TextStyle(
|
|
fontSize: widget.fontSize,
|
|
color: Colors.grey[600],
|
|
),
|
|
),
|
|
),
|
|
)
|
|
);
|
|
}).toList(),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildTextFieldWithDelete(int index) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 8.0),
|
|
child: Stack(
|
|
children: [
|
|
// 输入框
|
|
Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 7, vertical: 7),
|
|
child: SizedBox(
|
|
width: double.maxFinite,
|
|
child: DottedBorderBox(
|
|
child: TextField(
|
|
controller: _controllers[index],
|
|
decoration: InputDecoration(hintText: widget.hintText),
|
|
focusNode: _focusNodes[index],
|
|
keyboardType: TextInputType.multiline,
|
|
maxLines: 3,
|
|
minLines: 3,
|
|
style: TextStyle(fontSize: widget.fontSize),
|
|
),
|
|
)
|
|
),
|
|
),
|
|
|
|
// 删除按钮(叠加在左上角)
|
|
if (index > 0)
|
|
Positioned(
|
|
top: 0,
|
|
left: 0,
|
|
child: GestureDetector(
|
|
onTap: () => _removeTextField(index),
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.red,
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
padding: const EdgeInsets.all(4),
|
|
child: const Icon(Icons.close, size: 10, color: Colors.white),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|