欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flutter自定义Widget实现自带删除键的TextField

程序员文章站 2022-05-30 17:36:53
...

        在项目开发中,我们经常会用到输入框来输入一些信息,Android原生开发时使用的是EditText,在Flutter中则使用的是TextField。使用他们来实现类似选中获取焦点、输入值后显示删除键、清除已输入值等功能,则需要在布局中组合一些别的View(原生)或Widget(Flutter),并在代码中控制相关逻辑。
        如果在一个页面中需要用到多个输入框,那么在布局文件以及代码逻辑中都将显得很冗余(因为要复制很多相似的代码),因此我们一般都会选择自定义组合View或Widget来实现这些功能,使得项目的布局和代码文件简洁、明了一些,同时也是为了使用方便。所以,笔者在学习Flutter时就在想,借着原生自定义组合View的思想,在Flutter中也实现一些类似的功能组件,也算是检验学习成果,毕竟理论与实践的结合才能掌握的更牢固!

首先看一下笔者实现的效果图哈!喜欢或者对自己有用,可以借鉴使用哦!
Flutter自定义Widget实现自带删除键的TextField
        效果还不错,这也是笔者写这篇文章的初心吧,下面是笔者实现的自定义Widget-ClearTextField:

ClearTextField.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

///自带删除键的ClearTextField
typedef void ITextFieldCallBack(String content);

enum ITextInputType {
  text,
  multiline,
  number,
  phone,
  datetime,
  emailAddress,
  url,
  password
}

class ClearTextField extends StatefulWidget {
  final ITextInputType keyboardType;
  final int maxLines;
  final int maxLength;
  final String labelText;
  final String hintText;
  final TextStyle hintStyle;
  final Icon deleteIcon;
  final InputBorder inputBorder;
  final Widget prefixIcon;
  final TextStyle textStyle;
  final ITextFieldCallBack fieldCallBack;
  final FormFieldValidator<String> validator;

  ClearTextField({
    Key key,
    ITextInputType keyboardType: ITextInputType.text,
    this.maxLines = 1,
    this.maxLength,
    this.labelText,
    this.hintText,
    this.hintStyle,
    this.deleteIcon,
    this.inputBorder,
    this.textStyle,
    this.prefixIcon,
    this.fieldCallBack,
    this.validator,
  })  : assert(maxLines == null || maxLines > 0),
        assert(maxLength == null || maxLength > 0),
        keyboardType = maxLines == 1 ? keyboardType : ITextInputType.multiline,
        super(key: key);

  @override
  _ClearTextFieldState createState() {
    return new _ClearTextFieldState();
  }
}

class _ClearTextFieldState extends State<ClearTextField> {
  String _inputText = "";
  bool _hasDeleteIcon = false;
  bool _hasFocus = false;
  bool _isNumber = false;
  bool _isPassword = false;

  ///输入类型
  TextInputType _getTextInputType() {
    switch (widget.keyboardType) {
      case ITextInputType.text:
        return TextInputType.text;
      case ITextInputType.multiline:
        return TextInputType.multiline;
      case ITextInputType.number:
        _isNumber = true;
        return TextInputType.number;
      case ITextInputType.phone:
        _isNumber = true;
        return TextInputType.phone;
      case ITextInputType.datetime:
        return TextInputType.datetime;
      case ITextInputType.emailAddress:
        return TextInputType.emailAddress;
      case ITextInputType.url:
        return TextInputType.url;
      case ITextInputType.password:
        _isPassword = true;
        return TextInputType.text;
      default:
        return null;
    }
  }

  ///输入框焦点控制
  FocusNode _focusNode = new FocusNode();

  @override
  void initState() {
    super.initState();
    _focusNode.addListener(_focusNodeListener);
  }

  Future<Null> _focusNodeListener() async {
    if (_focusNode.hasFocus) {
      setState(() {
        _hasFocus = true;
      });
    } else {
      setState(() {
        _hasFocus = false;
      });
    }
  }

  ///输入范围
  List<TextInputFormatter> _getTextInputFormatter() {
    return _isNumber
        ? <TextInputFormatter>[
            WhitelistingTextInputFormatter.digitsOnly,
          ]
        : null;
  }

  @override
  Widget build(BuildContext context) {
    TextEditingController _controller = new TextEditingController.fromValue(
        TextEditingValue(
            text: _inputText,
            selection: new TextSelection.fromPosition(TextPosition(
                affinity: TextAffinity.downstream,
                offset: _inputText.length))));
    TextField textField = new TextField(
      focusNode: _focusNode,
      controller: _controller,
      decoration: InputDecoration(
        hintStyle: widget.hintStyle,
        counterStyle: TextStyle(color: Colors.white),
        labelText: widget.labelText,
        hintText: widget.hintText,
        border: widget.inputBorder != null
            ? widget.inputBorder
            : OutlineInputBorder(
                borderRadius: BorderRadius.circular(10.0),
                borderSide: BorderSide(color: Colors.green),
              ),
        fillColor: Colors.transparent,
        filled: true,
        prefixIcon: widget.prefixIcon,
        suffixIcon: _hasDeleteIcon && _hasFocus
            ? new Container(
                width: 20.0,
                height: 20.0,
                child: new IconButton(
                  alignment: Alignment.center,
                  padding: new EdgeInsets.all(0.0),
                  iconSize: 18.0,
                  icon: widget.deleteIcon != null
                      ? widget.deleteIcon
                      : Icon(Icons.cancel),
                  onPressed: () {
                    setState(() {
                      _inputText = "";
                      _hasDeleteIcon = _inputText.isNotEmpty;
                      widget.fieldCallBack(_inputText);
                    });
                  },
                ),
              )
            : new Text(""),
      ),
      onChanged: (str) {
        setState(() {
          _inputText = str;
          _hasDeleteIcon = _inputText.isNotEmpty;
          widget.fieldCallBack(_inputText);
        });
      },
      onSubmitted: (str) {
        widget.fieldCallBack(_inputText);
        setState(() {
          _hasFocus = false;
        });
      },
      keyboardType: _getTextInputType(),
      maxLength: widget.maxLength,
      maxLines: widget.maxLines,
      style: widget.textStyle,
      obscureText: _isPassword,
      inputFormatters: _getTextInputFormatter(),
    );
    return textField;
  }
}

有读者可能会问如何使用呢?下面笔者给出使用该自定义Widget的demo代码:

main.dart

import 'package:first_flutter_app/widget/text/ClearTextField.dart';
import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ClearTextFieldPage(title: 'Flutter Demo ClearTextField'),
    );
  }
}

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

  final String title;

  @override
  _ClearTextFieldPageState createState() => _ClearTextFieldPageState();
}

class _ClearTextFieldPageState extends State<ClearTextFieldPage> {
  String _phoneNumber;
  String _authNumber;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              margin: new EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
              child: ClearTextField(
                keyboardType: ITextInputType.phone,
                prefixIcon: Icon(Icons.phone_android),
                labelText: '手机号码',
                hintText: '请输入手机号',
                hintStyle: TextStyle(color: Colors.grey),
                textStyle: TextStyle(color: Colors.black),
                fieldCallBack: (content) {
                  _phoneNumber = content;
                  print(_phoneNumber);
                },
              ),
            ),
            Container(
              margin: new EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
              child: ClearTextField(
                keyboardType: ITextInputType.password,
                prefixIcon: Icon(Icons.https),
                labelText: '密码',
                hintText: '请输入密码',
                hintStyle: TextStyle(color: Colors.grey),
                textStyle: TextStyle(color: Colors.black),
                fieldCallBack: (content) {
                  _authNumber = content;
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

大家可以运行一下,自己感受一下是否好使;
如有可改进的地方,还望不吝赐教,大家多多沟通学习,我也是Flutter学习者…