news_repost_text_view.dart 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import 'package:flutter/material.dart';
  2. import 'package:location/utils/common_expand.dart';
  3. class NewsRepostTextView extends StatefulWidget {
  4. final String? initialValue; // 初始值
  5. final String hintText; // 提示文本
  6. final TextEditingController controller;
  7. final ValueChanged<String>? onChanged; // 文本变化回调
  8. final VoidCallback? onSubmitted; // 提交回调
  9. final int minLength; // 最小字数
  10. final int maxLength; // 最大字数
  11. const NewsRepostTextView({
  12. Key? key,
  13. this.initialValue,
  14. required this.controller,
  15. this.hintText = '请输入举报原因,确保您提交的信息真实、客观,且符合中华人民共和国相关法律法规。我们将由专门的审核团队对您提供的内容进行核查并第一时间处理。',
  16. this.onChanged,
  17. this.onSubmitted,
  18. this.minLength = 3,
  19. this.maxLength = 500,
  20. }) : super(key: key);
  21. @override
  22. _NewsRepostTextViewState createState() => _NewsRepostTextViewState();
  23. }
  24. class _NewsRepostTextViewState extends State<NewsRepostTextView> {
  25. late TextEditingController _controller;
  26. late FocusNode _focusNode;
  27. bool _isValid = true; // 当前输入是否有效
  28. int _currentLength = 0; // 当前字数
  29. @override
  30. void initState() {
  31. super.initState();
  32. _controller = widget.controller;//TextEditingController(text: widget.initialValue);
  33. _focusNode = FocusNode();
  34. _currentLength = widget.initialValue?.length ?? 0;
  35. _validateText();
  36. // 监听文本变化
  37. _controller.addListener(() {
  38. setState(() {
  39. _currentLength = _controller.text.length;
  40. _validateText();
  41. widget.onChanged?.call(_controller.text);
  42. });
  43. });
  44. }
  45. @override
  46. void dispose() {
  47. _controller.dispose();
  48. _focusNode.dispose();
  49. super.dispose();
  50. }
  51. // 验证文本长度
  52. void _validateText() {
  53. final text = _controller.text;
  54. _isValid = text.length >= widget.minLength && text.length <= widget.maxLength;
  55. }
  56. // 获取当前文本状态的提示信息
  57. String get _lengthStatusText {
  58. if (_currentLength < widget.minLength) {
  59. return '至少输入${widget.minLength}个字';
  60. } else if (_currentLength >= widget.maxLength) {
  61. return '已超出最大字数限制';
  62. } else {
  63. return '${_currentLength}/${widget.maxLength}';
  64. }
  65. }
  66. // 获取当前文本状态的颜色
  67. Color get _lengthStatusColor {
  68. if (_currentLength < widget.minLength || _currentLength > widget.maxLength) {
  69. return Colors.red;
  70. } else {
  71. return Colors.grey;
  72. }
  73. }
  74. @override
  75. Widget build(BuildContext context) {
  76. return GestureDetector(
  77. onTap: () {
  78. // 点击时收起键盘
  79. FocusScopeNode currentFocus = FocusScope.of(context);
  80. if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
  81. FocusManager.instance.primaryFocus?.unfocus();
  82. }
  83. },
  84. child: Column(
  85. crossAxisAlignment: CrossAxisAlignment.start,
  86. children: [
  87. TextField(
  88. controller: _controller,
  89. focusNode: _focusNode,
  90. maxLines: null, // 允许多行输入
  91. minLines: 4, // 最小显示行数
  92. maxLength: widget.maxLength, // 最大字数限制(UI层限制)
  93. keyboardType: TextInputType.multiline,
  94. decoration: InputDecoration(
  95. hintText: widget.hintText,
  96. hintStyle: TextStyle(
  97. color: Colors.grey
  98. ),
  99. border: OutlineInputBorder(
  100. borderSide: BorderSide(
  101. color: "#12C2C2C2".color,
  102. width: 1.0,
  103. ),
  104. ),
  105. enabledBorder: OutlineInputBorder(
  106. borderSide: BorderSide(
  107. color: "#12C2C2C2".color,
  108. width: 1.0,
  109. ),
  110. ),
  111. focusedBorder: OutlineInputBorder(
  112. borderSide: BorderSide(
  113. color: _isValid ? "#12C2C2C2".color : Colors.red,
  114. width: 2.0,
  115. ),
  116. borderRadius: BorderRadius.all(Radius.circular(10))
  117. ),
  118. counterText: '', // 隐藏默认计数器
  119. ),
  120. onSubmitted: (_) => widget.onSubmitted?.call(),
  121. ),
  122. SizedBox(height: 8.0),
  123. Row(
  124. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  125. children: [
  126. Text(
  127. _lengthStatusText,
  128. style: TextStyle(color: _lengthStatusColor),
  129. ),
  130. if (!_isValid)
  131. Text(
  132. '字数不符合要求',
  133. style: TextStyle(color: Colors.red),
  134. ),
  135. ],
  136. ),
  137. ],
  138. ),
  139. );
  140. }
  141. }