text_field.dart 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import 'dart:async';
  2. import 'package:flutter/foundation.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/services.dart';
  5. import 'package:liftmanager/res/resources.dart';
  6. import 'package:rxdart/rxdart.dart';
  7. import 'package:keyboard_actions/keyboard_actions.dart';
  8. import 'load_image.dart';
  9. import 'my_button.dart';
  10. /// 登录模块的输入框封装
  11. class MyTextField extends StatefulWidget {
  12. const MyTextField(
  13. {Key key,
  14. @required this.controller,
  15. this.maxLength: 16,
  16. this.autoFocus: false,
  17. this.keyboardType: TextInputType.text,
  18. this.hintText: "",
  19. this.focusNode,
  20. this.isInputPwd: false,
  21. this.getVCode,
  22. this.config,
  23. this.keyName})
  24. : super(key: key);
  25. final TextEditingController controller;
  26. final int maxLength;
  27. final bool autoFocus;
  28. final TextInputType keyboardType;
  29. final String hintText;
  30. final FocusNode focusNode;
  31. final bool isInputPwd;
  32. final Function() getVCode;
  33. final KeyboardActionsConfig config;
  34. /// 用于集成测试寻找widget
  35. final String keyName;
  36. @override
  37. _MyTextFieldState createState() => _MyTextFieldState();
  38. }
  39. class _MyTextFieldState extends State<MyTextField> {
  40. bool _isShowPwd = false;
  41. bool _isShowDelete;
  42. bool _isClick = true;
  43. /// 倒计时秒数
  44. final int second = 30;
  45. /// 当前秒数
  46. int s;
  47. StreamSubscription _subscription;
  48. @override
  49. void initState() {
  50. super.initState();
  51. /// 获取初始化值
  52. _isShowDelete = widget.controller.text.isEmpty;
  53. /// 监听输入改变
  54. widget.controller.addListener(() {
  55. setState(() {
  56. _isShowDelete = widget.controller.text.isEmpty;
  57. });
  58. });
  59. }
  60. @override
  61. void dispose() {
  62. _subscription?.cancel();
  63. widget.controller?.removeListener(() {});
  64. widget.controller?.dispose();
  65. super.dispose();
  66. }
  67. Future _getVCode() async {
  68. bool isSuccess = await widget.getVCode();
  69. if (isSuccess != null && isSuccess) {
  70. setState(() {
  71. s = second;
  72. _isClick = false;
  73. });
  74. _subscription = Observable.periodic(Duration(seconds: 1), (i) => i)
  75. .take(second)
  76. .listen((i) {
  77. setState(() {
  78. s = second - i - 1;
  79. _isClick = s < 1;
  80. });
  81. });
  82. }
  83. }
  84. @override
  85. Widget build(BuildContext context) {
  86. if (widget.config != null && defaultTargetPlatform == TargetPlatform.iOS) {
  87. // 因Android平台输入法兼容问题,所以只配置IOS平台
  88. FormKeyboardActions.setKeyboardActions(context, widget.config);
  89. }
  90. ThemeData themeData = Theme.of(context);
  91. bool isDark = themeData.brightness == Brightness.dark;
  92. return Stack(
  93. alignment: Alignment.centerRight,
  94. children: <Widget>[
  95. TextField(
  96. style: TextStyle(fontSize: 20),
  97. onSubmitted: (v){
  98. FocusScope.of(context).requestFocus(widget.focusNode);
  99. },
  100. focusNode: widget.focusNode,
  101. maxLength: widget.maxLength,
  102. obscureText: widget.isInputPwd ? !_isShowPwd : false,
  103. autofocus: widget.autoFocus,
  104. controller: widget.controller,
  105. textInputAction: TextInputAction.done,
  106. keyboardType: widget.keyboardType,
  107. // 数字、手机号限制格式为0到9(白名单), 密码限制不包含汉字(黑名单)
  108. inputFormatters: (widget.keyboardType == TextInputType.number ||
  109. widget.keyboardType == TextInputType.phone)
  110. ? [WhitelistingTextInputFormatter(RegExp("[0-9]"))]
  111. : [BlacklistingTextInputFormatter(RegExp("[\u4e00-\u9fa5]"))],
  112. decoration: InputDecoration(
  113. contentPadding: const EdgeInsets.symmetric(vertical: 16.0),
  114. hintText: widget.hintText,
  115. hintStyle: TextStyle(
  116. fontSize: Dimens.font_sp14,
  117. fontWeight: FontWeight.normal,
  118. color: Colours.text_gray_c
  119. ),
  120. counterText: "",
  121. focusedBorder: UnderlineInputBorder(
  122. borderSide:
  123. BorderSide(color: Colours.text_gray_c, width: 0.8)),
  124. enabledBorder: UnderlineInputBorder(
  125. borderSide: BorderSide(
  126. color: Theme.of(context).dividerTheme.color,
  127. width: 0.8))),
  128. ),
  129. Row(
  130. mainAxisSize: MainAxisSize.min,
  131. children: <Widget>[
  132. _isShowDelete
  133. ? Gaps.empty
  134. : GestureDetector(
  135. child: LoadAssetImage(
  136. "login/icon_delete",
  137. key: Key('${widget.keyName}_delete'),
  138. width: 18.0,
  139. height: 18.0,
  140. ),
  141. onTap: () => widget.controller.text = "",
  142. ),
  143. !widget.isInputPwd ? Gaps.empty : Gaps.hGap15,
  144. !widget.isInputPwd
  145. ? Gaps.empty
  146. : GestureDetector(
  147. child: LoadAssetImage(
  148. _isShowPwd ? "login/icon_display" : "login/icon_hide",
  149. key: Key('${widget.keyName}_showPwd'),
  150. width: 18.0,
  151. height: 18.0,
  152. ),
  153. onTap: () {
  154. setState(() {
  155. _isShowPwd = !_isShowPwd;
  156. });
  157. },
  158. ),
  159. widget.getVCode == null ? Gaps.empty : Gaps.hGap15,
  160. widget.getVCode == null
  161. ? Gaps.empty
  162. : Theme(
  163. data: Theme.of(context).copyWith(
  164. buttonTheme: ButtonThemeData(
  165. padding: const EdgeInsets.symmetric(horizontal: 8.0),
  166. height: 26.0,
  167. minWidth: 76.0,
  168. materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
  169. ),
  170. ),
  171. child: FlatButton(
  172. onPressed: _isClick ? _getVCode : null,
  173. textColor: Colors.white,
  174. color: Colours.app_main,
  175. disabledTextColor:
  176. isDark ? Colours.dark_text : Colors.white,
  177. disabledColor:
  178. isDark ? Colours.dark_text_gray : Colours.text_gray_c,
  179. shape: RoundedRectangleBorder(
  180. borderRadius: BorderRadius.circular(22.0),
  181. side: BorderSide(
  182. color: _isClick
  183. ? themeData.primaryColor
  184. : Colors.transparent,
  185. width: 0.8,
  186. )),
  187. child: Text(
  188. _isClick ? "获取验证码" : "($s s)",
  189. style: TextStyle(fontSize: Dimens.font_sp12),
  190. ),
  191. ),
  192. )
  193. ],
  194. )
  195. ],
  196. );
  197. }
  198. }