Flutter TextField(文本输入)使用填坑

TextField 是一个文本输入组件,一开始做登录页就用到了。但是,TextField 有一些坑官方还没有填,那么就只能通过一些俏皮的方案来解决了。当然,如果够强的话,也是可以写一个新的 widget 控件的 ~

1、限定了可输入长度,超过长度后的内容虽然不展示出来,但是点击删除键时,还是要删除已输入但是看不见的那部分
2、限定了输入类型(比如数字),虽然会弹出相应类型的键盘(比如数字键盘),但是还是能输入其他类型(比如字母、汉字)

以上两种坑合并解决方案如下,当然,如果想自己画一个数字键盘,也是可以解决输入类型问题 ~

主要是在 TextField 输入后回调 onChanged 方法时,对输入内容进行判断,如果符合判断条件就采用并缓存下来,如果不符合,就通过 TextEditingController 进行“回退”:

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class WidgetTestPage extends StatefulWidget {
  WidgetTestPage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  State<StatefulWidget> createState() => _WidgetTestPageState();
}

class _WidgetTestPageState extends State<WidgetTestPage> {
  TextEditingController _textFieldController = new TextEditingController();
  String _phone = "";

  bool _isNumberAndCount(String str) {
    return str.length <= 11 && new RegExp("^[0-9][0-9]*\$").hasMatch(str);
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          widget.title,
        ),
      ),
      body: TextField(
        keyboardType: TextInputType.number,
        controller: _textFieldController,
        decoration: InputDecoration(
          hintText: "请输入手机号码",
          hintStyle: TextStyle(color: Color(0xffbfbfbf), fontSize: 16),
          counterText: "",
          enabledBorder: UnderlineInputBorder(
            borderSide: BorderSide(color: Color(0xffebebeb), width: 1),
          ),
          focusedBorder: UnderlineInputBorder(
            borderSide: BorderSide(color: Color(0xffebebeb), width: 1),
          ),
        ),
        onChanged: (v) {
          if (_isNumberAndCount(v) || v == "") {
            setState(() {
              _phone = v;
            });
          } else {
            _textFieldController.text = _phone;
            _textFieldController.selection = TextSelection.fromPosition(
              // 保持光标在最后
              TextPosition(
                  affinity: TextAffinity.downstream, offset: _phone.length),
            );
          }
        },
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
  }
}

抽取成一个 UI Widget:

NumberTextField(
  limitCount: 11,
  controller: TextEditingController(),
  decoration: InputDecoration(
    hintText: "请输入手机号码",
    hintStyle: TextStyle(color: Color(0xffbfbfbf), fontSize: 16),
    counterText: "",
    enabledBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Color(0xffebebeb), width: 1),
    ),
    focusedBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Color(0xffebebeb), width: 1),
    ),
  ),
  onChanged: (v) {
    ... ...
  },
),
import 'package:flutter/material.dart';

/// 自定义数字输入框(字母)
/// [limitCount] 限制可输入长度
/// [canInputLetter] 能否输入英文字母
class NumberTextField extends StatefulWidget {
  final int limitCount;
  final bool canInputLetter;
  final TextStyle style;
  final TextEditingController controller;
  final InputDecoration decoration;
  final ValueChanged<String> onChanged;

  NumberTextField({
    Key key,
    this.limitCount = 0,
    this.canInputLetter = false,
    this.style,
    this.controller,
    this.decoration = const InputDecoration(),
    this.onChanged,
  })  : assert(controller != null),
        super(key: key);

  @override
  State<StatefulWidget> createState() => _NumberTextFieldState(limitCount, canInputLetter, controller);
}

class _NumberTextFieldState extends State<NumberTextField> {
  final int _limitCount;
  final bool _canInputLetter;
  final TextEditingController _textFieldController;
  String _number = '';

  _NumberTextFieldState(this._limitCount, this._canInputLetter, this._textFieldController);

  bool _isNumberAndCount(String str) {
    return (_limitCount <= 0 || str.length <= _limitCount) &&
        (_canInputLetter ? RegExp("^[a-z0-9A-Z]*\$").hasMatch(str) : RegExp("^[0-9]*\$").hasMatch(str));
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      style: widget.style,
      keyboardType: TextInputType.number,
      controller: _textFieldController,
      decoration: widget.decoration,
      /*inputFormatters: [FilteringTextInputFormatter.deny(
          // 过滤表情包,好像_isNumberAndCount已经过滤了,不行才放开
          RegExp("[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]"))],*/
      onChanged: (v) {
        if (_isNumberAndCount(v) || v == "") {
          setState(() {
            _number = v;
          });
          if (widget.onChanged != null) {
            widget.onChanged(v);
          }
        } else {
          _textFieldController.text = _number;
          _textFieldController.selection = TextSelection.fromPosition(
            // 保持光标在最后
            TextPosition(affinity: TextAffinity.downstream, offset: _number.length),
          );
        }
      },
    );
  }

  @override
  void dispose() {
    _textFieldController.dispose();
    super.dispose();
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值