import 'dart:async'; import 'package:ctjt_flutter/common/styles.dart'; import 'package:ctjt_flutter/common/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'button.dart'; /* ---------------------------------密码输入框-------------------------------- */ class PWDInputGroup extends StatelessWidget { static var _defaultPadding = EdgeInsets.only(top: 75.h); PWDInputGroup( {Key? key, this.label = '密码:', this.padding, required this.controller}) : super(key: key); final String label; final EdgeInsetsGeometry? padding; final TextEditingController controller; @override Widget build(BuildContext context) { return Padding( padding: null == this.padding ? _defaultPadding : this.padding!, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(this.label, style: Styles.formLabelStyle), PWDInput( controller: this.controller, ) ], ), ); } } class PWDInput extends StatefulWidget { PWDInput({ Key? key, this.hintText = '6-16位数字、字母或符号', this.minLength = 6, this.maxLength = 16, required this.controller }) : super(key: key); final hintText; final minLength; final maxLength; final TextEditingController controller; @override _PWDInputState createState() => _PWDInputState(); } class _PWDInputState extends State { var _isCanSee = false; var _hideClear = true; @override Widget build(BuildContext context) { return TextFormField( controller: widget.controller, decoration: InputDecoration( // 用于设置文本框右侧按钮的装饰器 hintText: widget.hintText, suffixIcon: SizedBox( // 设置按钮区域宽度 width: Styles.iconSize! * 4.0, child: Row( // 水平布局 mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( // 撑满剩余水平空间的布局容器 child: Offstage( // 显示隐藏控制 offstage: _hideClear, child: IButton( // 文本框清理按钮 iconSize: Styles.iconSize!, icon: Icon(Icons.cancel, color: Styles.primaryColor), onPressed: () { widget.controller.clear(); setState(() { _hideClear = true; }); }), ), ), IButton( // 查看密码按钮 iconSize: Styles.iconSize!, icon: _isCanSee ? Icon(Icons.visibility, color: Styles.primaryColor) : Icon(Icons.visibility_off, color: Colors.black54), onPressed: () { setState(() { _isCanSee = !_isCanSee; }); }), ], ), ), ), maxLength: widget.maxLength, validator: (value) { // 校验 return value!.isEmpty || value.length > widget.maxLength || value.length < widget.minLength ? '请输入由${widget.hintText}组成的密码' : null; }, // 密码键盘 keyboardType: TextInputType.visiblePassword, // 允许输入的字符 inputFormatters: [ FilteringTextInputFormatter.allow(Utils.passwordPattern) ], // 密码是否可见 obscureText: !_isCanSee, // 每次输入改变时 onChanged: (value) { setState(() { _hideClear = value.isEmpty; }); }, ); } } /* --------------------------------验证码输入框------------------------------- */ class VCodeInputGroup extends StatelessWidget { static var _defaultPadding = EdgeInsets.only(top: 75.h); VCodeInputGroup( {Key? key, this.label = '验证码:', this.padding, required this.controller, this.onPressed}) : super(key: key); final String label; final EdgeInsetsGeometry? padding; final TextEditingController controller; final Function? onPressed; @override Widget build(BuildContext context) { return Padding( padding: null == this.padding ? _defaultPadding : this.padding!, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(this.label, style: Styles.formLabelStyle), VCodeInput( controller: this.controller, onPressed: this.onPressed, ) ], ), ); } } class VCodeInput extends StatefulWidget { VCodeInput({Key? key, required this.controller, this.onPressed}) : super(key: key); final TextEditingController controller; final Function? onPressed; @override _VCodeInputState createState() => _VCodeInputState(); } class _VCodeInputState extends State { var _text = '发送验证码'; var _seconds = 60; var _isDisabled = false; var _hideClear = true; @override Widget build(BuildContext context) { return TextFormField( controller: widget.controller, decoration: InputDecoration( hintText: '4位验证码', suffixIcon: SizedBox( width: Styles.buttonFontSize! * 5 + Styles.iconSize! * 3, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Offstage( offstage: _hideClear, child: IButton( iconSize: Styles.iconSize!, icon: Icon(Icons.cancel, color: Styles.primaryColor), onPressed: () { widget.controller.clear(); setState(() { _hideClear = true; }); }), ), ), TButton( child: Text(_text, style: Styles.btnFontStyle), onPressed: _onPressed()), ], ), ), ), maxLength: 4, validator: (value) { return value!.isEmpty ? '请输入验证码' : null; }, keyboardType: TextInputType.number, inputFormatters: [FilteringTextInputFormatter.allow(Utils.numberPattern)], onChanged: (value) { setState(() { _hideClear = value.isEmpty; }); }, ); } VoidCallback _onPressed() { if (_isDisabled) { return () {}; } else { return () { if (null != widget.onPressed) { widget.onPressed!(); } _isDisabled = true; _seconds = 60; Timer.periodic(Utils.timeout, (timer) { setState(() { _text = _seconds.toString().padLeft(2, '0') + "秒后重试"; }); _seconds--; if (_seconds < 0) { setState(() { _text = '发送验证码'; }); timer.cancel(); // 取消定时器 _isDisabled = false; } }); }; } } } /* --------------------------------手机号输入框------------------------------- */ class CellInputGroup extends StatelessWidget { static var _defaultPadding = EdgeInsets.only(top: 75.h); CellInputGroup( {Key? key, this.label = '手机号:', this.padding, required this.controller}) : super(key: key); final String label; final EdgeInsetsGeometry? padding; final TextEditingController controller; @override Widget build(BuildContext context) { return Padding( padding: null == this.padding ? _defaultPadding : this.padding!, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(this.label, style: Styles.formLabelStyle), CellInput( controller: this.controller, ) ], ), ); } } class CellInput extends StatefulWidget { CellInput({Key? key, required this.controller}) : super(key: key); final TextEditingController controller; @override _CellInputState createState() => _CellInputState(); } class _CellInputState extends State { var _hideClear = true; @override Widget build(BuildContext context) { return TextFormField( controller: widget.controller, decoration: InputDecoration( hintText: '11位手机号码', suffixIcon: Offstage( offstage: _hideClear, child: IButton( iconSize: Styles.iconSize!, icon: Icon(Icons.cancel, color: Styles.primaryColor), onPressed: () { widget.controller.clear(); setState(() { _hideClear = true; }); }), )), maxLength: 11, validator: (value) { return Utils.testCellNo(value!) ? null : '请输入有效的手机号'; }, keyboardType: TextInputType.phone, inputFormatters: [FilteringTextInputFormatter.allow(Utils.numberPattern)], onChanged: (value) { setState(() { _hideClear = value.isEmpty; }); }, ); } } /* ---------------------------------文本输入框-------------------------------- */ class StrInputGroup extends StatelessWidget { static var _defaultPadding = EdgeInsets.only(top: 75.h); StrInputGroup( {Key? key, this.label = '名称:', this.hintText, this.maxLength, this.padding, required this.controller}) : super(key: key); final String label; final String? hintText; final int? maxLength; final EdgeInsetsGeometry? padding; final TextEditingController controller; @override Widget build(BuildContext context) { return Padding( padding: null == this.padding ? _defaultPadding : this.padding!, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(this.label, style: Styles.formLabelStyle), StrInput( hintText: this.hintText, maxLength: this.maxLength, controller: this.controller, ) ], ), ); } } class StrInput extends StatefulWidget { StrInput({ Key? key, this.hintText = '最长16个字符', this.maxLength = 16, this.inputFormatters, required this.controller, }) : super(key: key); final hintText; final maxLength; final List? inputFormatters; final TextEditingController controller; @override _StrInputState createState() => _StrInputState(); } class _StrInputState extends State { var _hideClear = true; @override Widget build(BuildContext context) { return TextFormField( controller: widget.controller, decoration: InputDecoration( hintText: widget.hintText, suffixIcon: Offstage( offstage: _hideClear, child: IButton( iconSize: Styles.iconSize!, icon: Icon(Icons.cancel, color: Styles.primaryColor), onPressed: () { widget.controller.clear(); setState(() { _hideClear = true; }); }), )), maxLength: widget.maxLength, validator: (value) { return value!.isNotEmpty ? null : '不能为空值'; }, inputFormatters: widget.inputFormatters, onChanged: (value) { setState(() { _hideClear = value.isEmpty; }); }, ); } }