liuyulin
发布于 2025-12-12 / 25 阅读
0
0

Custom Right-Aligned TextField in Flutter

Custom Right-Aligned TextField in Flutter

Flutter’s built-in TextField works well for most use cases, but when using right alignment, I noticed a problem: when a user enters a space at the end of the text, the space does not appear immediately. It only shows up after the next character is typed. This creates a poor input experience, especially in fields where right alignment is required.

To solve this issue, I created a custom widget that behaves like a right-aligned input box but avoids the space-display bug.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
​
import '../res/styles.dart';
​
class RightEditTextFieldWidget extends StatefulWidget {
  RightEditTextFieldWidget(
      {Key key,
      @required this.textFieldName,
      @required this.hintText,
      @required this.maxLength,
      @required this.alignWidth,
      @required this.isPassword,
      @required this.controller,
      this.inputFormatters})
      : super(key: key);
​
  String textFieldName;
  String hintText;
  int maxLength;
  double alignWidth;
  List<TextInputFormatter> inputFormatters;
  bool isPassword;
  TextEditingController controller;
​
  @override
  _RightEditTextFieldWidgetState createState() =>
      _RightEditTextFieldWidgetState(textFieldName, hintText, maxLength,
          inputFormatters, alignWidth, isPassword, controller);
}
​
class _RightEditTextFieldWidgetState extends State<RightEditTextFieldWidget> {
  // 外部变量
  String _textfieldName;
  String _hintText;
  int _maxLength;
  List<TextInputFormatter> _inputFormatters;
  double _alignWidth;
  bool _isPassword;
  bool _isTextVisable;
  TextEditingController _controller;
​
  // 内部变量
  FocusNode _focusNode;
  String _index;
  String _hintTextCopy;
​
  _RightEditTextFieldWidgetState(
      this._textfieldName,
      this._hintText,
      this._maxLength,
      this._inputFormatters,
      this._alignWidth,
      this._isPassword,
      this._controller);
​
  @override
  void initState() {
    super.initState();
    _hintTextCopy = _hintText;
    _isTextVisable = !_isPassword;
    _focusNode = FocusNode();
    // _controller = TextEditingController();
  }
​
  @override
  void dispose() {
    _focusNode.dispose();
    // _controller.dispose();
    super.dispose();
  }
​
  @override
  Widget build(BuildContext context) {
    return
        Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        SizedBox(width: _alignWidth),
        Text(
          _textfieldName,
          style: TextStyles.text_b3_16,
        ),
        Expanded(
          child: GestureDetector(
            onTap: () {
              FocusScope.of(context).requestFocus(_focusNode);
              SystemChannels.textInput.invokeMethod<void>('TextInput.show');
            },
            child: Stack(
              alignment: Alignment.centerRight,
              children: <Widget>[
                Container(
                  // color: Colors.red,
                  // height: double.infinity,
                  // width: double.infinity,
                  child: Text(_hintText,
                      style: TextStyles.text_66_16,
                      // textDirection: TextDirection(
                      //   c
                      // )
                  ),
                ),
                IntrinsicWidth(
                  child: TextField(
                    style: TextStyles.text_b3_16,
                    focusNode: _focusNode,
                    // controller: _controller,
                    maxLength: _maxLength,
                    inputFormatters: _inputFormatters,
                    maxLines: 1,
                    readOnly: false,
                    autofocus: false,
                    obscureText: _isTextVisable,
                    decoration: InputDecoration(
                      // hintText: _hintText,
                      // hintStyle: TextStyles.text_66_16,
                      border: OutlineInputBorder(
                          // borderSide: BorderSide.none
                          ),
                      counterText: "",
                      contentPadding: EdgeInsets.all(0),
                    ),
                    onChanged: (v) {
                      setState(() {
                        _index = v;
                        if (v != null && v != "") {
                          _hintText = "";
                        } else {
                          _hintText = _hintTextCopy;
                        }
                      });
                    },
                  ),
                ),
              ],
            ),
          ),
        ),
        Visibility(
          visible: _isPassword,
          child: GestureDetector(
            onTap: () {
              setState(() {
                _isTextVisable = !_isTextVisable;
              });
            },
            child: Container(
                width: 24,
                height: 24,
                child: Image.asset(
                    _isTextVisable
                        ? "assets/images/comm/admin_pwd_no_see.png"
                        : "assets/images/comm/admin_pwd_see.png",
                    fit: BoxFit.fill)),
          ),
        ),
        SizedBox(width: _alignWidth),
      ],
    )
        // )
        ;
  }
​
  @override
  void didUpdateWidget(Widget oldWidget) {
    print("didUpdateWidget");
  }


评论