input.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. import 'dart:async';
  2. import 'package:ctjt_flutter/common/styles.dart';
  3. import 'package:ctjt_flutter/common/utils.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter/services.dart';
  6. import 'package:flutter_screenutil/flutter_screenutil.dart';
  7. import 'button.dart';
  8. /* ---------------------------------密码输入框-------------------------------- */
  9. class PWDInputGroup extends StatelessWidget {
  10. static var _defaultPadding = EdgeInsets.only(top: 75.h);
  11. PWDInputGroup(
  12. {Key? key,
  13. this.label = '密码:',
  14. this.padding,
  15. required this.controller})
  16. : super(key: key);
  17. final String label;
  18. final EdgeInsetsGeometry? padding;
  19. final TextEditingController controller;
  20. @override
  21. Widget build(BuildContext context) {
  22. return Padding(
  23. padding: null == this.padding ? _defaultPadding : this.padding!,
  24. child: Column(
  25. mainAxisSize: MainAxisSize.min,
  26. crossAxisAlignment: CrossAxisAlignment.start,
  27. children: [
  28. Text(this.label, style: Styles.formLabelStyle),
  29. PWDInput(
  30. controller: this.controller,
  31. )
  32. ],
  33. ),
  34. );
  35. }
  36. }
  37. class PWDInput extends StatefulWidget {
  38. PWDInput({
  39. Key? key,
  40. this.hintText = '6-16位数字、字母或符号',
  41. this.minLength = 6,
  42. this.maxLength = 16,
  43. required this.controller
  44. }) : super(key: key);
  45. final hintText;
  46. final minLength;
  47. final maxLength;
  48. final TextEditingController controller;
  49. @override
  50. _PWDInputState createState() => _PWDInputState();
  51. }
  52. class _PWDInputState extends State<PWDInput> {
  53. var _isCanSee = false;
  54. var _hideClear = true;
  55. @override
  56. Widget build(BuildContext context) {
  57. return TextFormField(
  58. controller: widget.controller,
  59. decoration: InputDecoration(
  60. // 用于设置文本框右侧按钮的装饰器
  61. hintText: widget.hintText,
  62. suffixIcon: SizedBox(
  63. // 设置按钮区域宽度
  64. width: Styles.iconSize! * 4.0,
  65. child: Row(
  66. // 水平布局
  67. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  68. children: <Widget>[
  69. Expanded(
  70. // 撑满剩余水平空间的布局容器
  71. child: Offstage(
  72. // 显示隐藏控制
  73. offstage: _hideClear,
  74. child: IButton(
  75. // 文本框清理按钮
  76. iconSize: Styles.iconSize!,
  77. icon: Icon(Icons.cancel, color: Styles.primaryColor),
  78. onPressed: () {
  79. widget.controller.clear();
  80. setState(() {
  81. _hideClear = true;
  82. });
  83. }),
  84. ),
  85. ),
  86. IButton(
  87. // 查看密码按钮
  88. iconSize: Styles.iconSize!,
  89. icon: _isCanSee
  90. ? Icon(Icons.visibility, color: Styles.primaryColor)
  91. : Icon(Icons.visibility_off, color: Colors.black54),
  92. onPressed: () {
  93. setState(() {
  94. _isCanSee = !_isCanSee;
  95. });
  96. }),
  97. ],
  98. ),
  99. ),
  100. ),
  101. maxLength: widget.maxLength,
  102. validator: (value) {
  103. // 校验
  104. return value!.isEmpty || value.length > widget.maxLength || value.length < widget.minLength
  105. ? '请输入由${widget.hintText}组成的密码'
  106. : null;
  107. },
  108. // 密码键盘
  109. keyboardType: TextInputType.visiblePassword,
  110. // 允许输入的字符
  111. inputFormatters: [
  112. FilteringTextInputFormatter.allow(Utils.passwordPattern)
  113. ],
  114. // 密码是否可见
  115. obscureText: !_isCanSee,
  116. // 每次输入改变时
  117. onChanged: (value) {
  118. setState(() {
  119. _hideClear = value.isEmpty;
  120. });
  121. },
  122. );
  123. }
  124. }
  125. /* --------------------------------验证码输入框------------------------------- */
  126. class VCodeInputGroup extends StatelessWidget {
  127. static var _defaultPadding = EdgeInsets.only(top: 75.h);
  128. VCodeInputGroup(
  129. {Key? key,
  130. this.label = '验证码:',
  131. this.padding,
  132. required this.controller,
  133. this.onPressed})
  134. : super(key: key);
  135. final String label;
  136. final EdgeInsetsGeometry? padding;
  137. final TextEditingController controller;
  138. final Function? onPressed;
  139. @override
  140. Widget build(BuildContext context) {
  141. return Padding(
  142. padding: null == this.padding ? _defaultPadding : this.padding!,
  143. child: Column(
  144. mainAxisSize: MainAxisSize.min,
  145. crossAxisAlignment: CrossAxisAlignment.start,
  146. children: [
  147. Text(this.label, style: Styles.formLabelStyle),
  148. VCodeInput(
  149. controller: this.controller,
  150. onPressed: this.onPressed,
  151. )
  152. ],
  153. ),
  154. );
  155. }
  156. }
  157. class VCodeInput extends StatefulWidget {
  158. VCodeInput({Key? key, required this.controller, this.onPressed}) : super(key: key);
  159. final TextEditingController controller;
  160. final Function? onPressed;
  161. @override
  162. _VCodeInputState createState() => _VCodeInputState();
  163. }
  164. class _VCodeInputState extends State<VCodeInput> {
  165. var _text = '发送验证码';
  166. var _seconds = 60;
  167. var _isDisabled = false;
  168. var _hideClear = true;
  169. @override
  170. Widget build(BuildContext context) {
  171. return TextFormField(
  172. controller: widget.controller,
  173. decoration: InputDecoration(
  174. hintText: '4位验证码',
  175. suffixIcon: SizedBox(
  176. width: Styles.buttonFontSize! * 5 + Styles.iconSize! * 3,
  177. child: Row(
  178. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  179. children: <Widget>[
  180. Expanded(
  181. child: Offstage(
  182. offstage: _hideClear,
  183. child: IButton(
  184. iconSize: Styles.iconSize!,
  185. icon: Icon(Icons.cancel, color: Styles.primaryColor),
  186. onPressed: () {
  187. widget.controller.clear();
  188. setState(() {
  189. _hideClear = true;
  190. });
  191. }),
  192. ),
  193. ),
  194. TButton(
  195. child: Text(_text, style: Styles.btnFontStyle),
  196. onPressed: _onPressed()),
  197. ],
  198. ),
  199. ),
  200. ),
  201. maxLength: 4,
  202. validator: (value) {
  203. return value!.isEmpty ? '请输入验证码' : null;
  204. },
  205. keyboardType: TextInputType.number,
  206. inputFormatters: [FilteringTextInputFormatter.allow(Utils.numberPattern)],
  207. onChanged: (value) {
  208. setState(() {
  209. _hideClear = value.isEmpty;
  210. });
  211. },
  212. );
  213. }
  214. VoidCallback _onPressed() {
  215. if (_isDisabled) {
  216. return () {};
  217. } else {
  218. return () {
  219. if (null != widget.onPressed) {
  220. widget.onPressed!();
  221. }
  222. _isDisabled = true;
  223. _seconds = 60;
  224. Timer.periodic(Utils.timeout, (timer) {
  225. setState(() {
  226. _text = _seconds.toString().padLeft(2, '0') + "秒后重试";
  227. });
  228. _seconds--;
  229. if (_seconds < 0) {
  230. setState(() {
  231. _text = '发送验证码';
  232. });
  233. timer.cancel(); // 取消定时器
  234. _isDisabled = false;
  235. }
  236. });
  237. };
  238. }
  239. }
  240. }
  241. /* --------------------------------手机号输入框------------------------------- */
  242. class CellInputGroup extends StatelessWidget {
  243. static var _defaultPadding = EdgeInsets.only(top: 75.h);
  244. CellInputGroup(
  245. {Key? key,
  246. this.label = '手机号:',
  247. this.padding,
  248. required this.controller})
  249. : super(key: key);
  250. final String label;
  251. final EdgeInsetsGeometry? padding;
  252. final TextEditingController controller;
  253. @override
  254. Widget build(BuildContext context) {
  255. return Padding(
  256. padding: null == this.padding ? _defaultPadding : this.padding!,
  257. child: Column(
  258. mainAxisSize: MainAxisSize.min,
  259. crossAxisAlignment: CrossAxisAlignment.start,
  260. children: [
  261. Text(this.label, style: Styles.formLabelStyle),
  262. CellInput(
  263. controller: this.controller,
  264. )
  265. ],
  266. ),
  267. );
  268. }
  269. }
  270. class CellInput extends StatefulWidget {
  271. CellInput({Key? key, required this.controller}) : super(key: key);
  272. final TextEditingController controller;
  273. @override
  274. _CellInputState createState() => _CellInputState();
  275. }
  276. class _CellInputState extends State<CellInput> {
  277. var _hideClear = true;
  278. @override
  279. Widget build(BuildContext context) {
  280. return TextFormField(
  281. controller: widget.controller,
  282. decoration: InputDecoration(
  283. hintText: '11位手机号码',
  284. suffixIcon: Offstage(
  285. offstage: _hideClear,
  286. child: IButton(
  287. iconSize: Styles.iconSize!,
  288. icon: Icon(Icons.cancel, color: Styles.primaryColor),
  289. onPressed: () {
  290. widget.controller.clear();
  291. setState(() {
  292. _hideClear = true;
  293. });
  294. }),
  295. )),
  296. maxLength: 11,
  297. validator: (value) {
  298. return Utils.testCellNo(value!) ? null : '请输入有效的手机号';
  299. },
  300. keyboardType: TextInputType.phone,
  301. inputFormatters: [FilteringTextInputFormatter.allow(Utils.numberPattern)],
  302. onChanged: (value) {
  303. setState(() {
  304. _hideClear = value.isEmpty;
  305. });
  306. },
  307. );
  308. }
  309. }
  310. /* ---------------------------------文本输入框-------------------------------- */
  311. class StrInputGroup extends StatelessWidget {
  312. static var _defaultPadding = EdgeInsets.only(top: 75.h);
  313. StrInputGroup(
  314. {Key? key,
  315. this.label = '名称:',
  316. this.hintText,
  317. this.maxLength,
  318. this.padding,
  319. required this.controller})
  320. : super(key: key);
  321. final String label;
  322. final String? hintText;
  323. final int? maxLength;
  324. final EdgeInsetsGeometry? padding;
  325. final TextEditingController controller;
  326. @override
  327. Widget build(BuildContext context) {
  328. return Padding(
  329. padding: null == this.padding ? _defaultPadding : this.padding!,
  330. child: Column(
  331. mainAxisSize: MainAxisSize.min,
  332. crossAxisAlignment: CrossAxisAlignment.start,
  333. children: [
  334. Text(this.label, style: Styles.formLabelStyle),
  335. StrInput(
  336. hintText: this.hintText,
  337. maxLength: this.maxLength,
  338. controller: this.controller,
  339. )
  340. ],
  341. ),
  342. );
  343. }
  344. }
  345. class StrInput extends StatefulWidget {
  346. StrInput({
  347. Key? key,
  348. this.hintText = '最长16个字符',
  349. this.maxLength = 16,
  350. this.inputFormatters,
  351. required this.controller,
  352. }) : super(key: key);
  353. final hintText;
  354. final maxLength;
  355. final List<TextInputFormatter>? inputFormatters;
  356. final TextEditingController controller;
  357. @override
  358. _StrInputState createState() => _StrInputState();
  359. }
  360. class _StrInputState extends State<StrInput> {
  361. var _hideClear = true;
  362. @override
  363. Widget build(BuildContext context) {
  364. return TextFormField(
  365. controller: widget.controller,
  366. decoration: InputDecoration(
  367. hintText: widget.hintText,
  368. suffixIcon: Offstage(
  369. offstage: _hideClear,
  370. child: IButton(
  371. iconSize: Styles.iconSize!,
  372. icon: Icon(Icons.cancel, color: Styles.primaryColor),
  373. onPressed: () {
  374. widget.controller.clear();
  375. setState(() {
  376. _hideClear = true;
  377. });
  378. }),
  379. )),
  380. maxLength: widget.maxLength,
  381. validator: (value) {
  382. return value!.isNotEmpty ? null : '不能为空值';
  383. },
  384. inputFormatters: widget.inputFormatters,
  385. onChanged: (value) {
  386. setState(() {
  387. _hideClear = value.isEmpty;
  388. });
  389. },
  390. );
  391. }
  392. }