Flutter:使用ThemeData在TextField或TextFormField标签内部边框中。

3
如何使我的TextField标签在TextField小部件处于活动状态时浮动到顶部,但仍保留在TextField边框内(而不是在其边缘)?
我想要的示例:

Before active

成为 enter image description here 这个
使用ThemeData上的inputDecorationTheme是可能的吗?还是我需要创建一个包装器小部件来完成这个?
非常希望从应用程序范围的ThemeData中控制它。

请检查我在这个问题上的答案,会对你有帮助。 我的回答 - Hamid Waezi
2个回答

7

很遗憾,我不知道如何使用默认工具完成它,但我用另一种方法来完成它,也许对你有帮助。

  1. 在您的小部件中创建FocusNode和边框颜色的变量:
// Use it to change color for border when textFiled in focus
FocusNode _focusNode = FocusNode();

// Color for border
Color _borderColor = Colors.grey;
  1. initState内为textField创建监听器,如果textField处于焦点状态,将边框颜色更改为橙色,否则更改为灰色:
@override
void initState() {
  super.initState();
  // Change color for border if focus was changed
  _focusNode.addListener(() {
    setState(() {
      _borderColor = _focusNode.hasFocus ? Colors.orange : Colors.grey;
    });
  });
}
  1. textField 创建带有边框的 Container,添加 focusNode 并设置装饰到 textField
Container(
  decoration: BoxDecoration(
    border: Border.all(color: _borderColor),
    borderRadius: BorderRadius.circular(4),
  ),
  child: TextField(
    focusNode: _focusNode,
    style: TextStyle(color: Colors.grey),
    keyboardType: TextInputType.number,
    decoration: InputDecoration(
      contentPadding: EdgeInsets.zero,
      border: InputBorder.none,
      labelText: "Amount",
      prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0),
      prefixIcon: Padding(
        padding: EdgeInsets.symmetric(vertical: 18, horizontal: 8),
        child: Text("₦", style: TextStyle(fontSize: 16, color: Colors.grey)),
      ),
    ),
  ),
),
  1. 不要忘记为focusNode调用dispose
@override
void dispose() {
  _focusNode.dispose();
  super.dispose();
}

完整代码:
class TextFieldDesignPage extends StatefulWidget {
  TextFieldDesignPage({Key? key}) : super(key: key);

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

class _TextFieldDesignPageState extends State<TextFieldDesignPage> {
  // Use it to change color for border when textFiled in focus
  FocusNode _focusNode = FocusNode();

  // Color for border
  Color _borderColor = Colors.grey;

  @override
  void initState() {
    super.initState();
    // Change color for border if focus was changed
    _focusNode.addListener(() {
      setState(() {
        _borderColor = _focusNode.hasFocus ? Colors.orange : Colors.grey;
      });
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          margin: EdgeInsets.all(8),
          decoration: BoxDecoration(
            border: Border.all(color: _borderColor),
            borderRadius: BorderRadius.circular(4),
          ),
          child: TextField(
            focusNode: _focusNode,
            style: TextStyle(color: Colors.grey),
            keyboardType: TextInputType.number,
            decoration: InputDecoration(
              contentPadding: EdgeInsets.zero,
              border: InputBorder.none,
              labelText: "Amount",
              prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0),
              prefixIcon: Padding(
                padding: EdgeInsets.symmetric(vertical: 18, horizontal: 8),
                child: Text("₦", style: TextStyle(fontSize: 16, color: Colors.grey)),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

结果:

在此输入图像描述


我可以问一下,这段代码具体是如何将标签保留在文本字段内的吗?我一直很难实现它,看不到任何明确将标签保留在字段内的东西,除了可能是包装容器... - RobbB
好的,我刚刚运行了您的代码,它可以工作。我意识到不同之处在于我使用的是TextFormField而不是TextField。我想知道是否可以使用文本表单字段来实现这个功能? - RobbB
1
@RobbB 是的,关键是我没有为TextField使用边框,我使用了包含TextFieldContainer的边框。我检查过了,使用TextFormField也可以正确工作。为了证明这一点,在示例代码中将TextField更改为TextFormField即可。 - Andrei R
1
我已经在这里提出了一个功能请求,并包含了这篇文章以帮助描述最佳操作。与直接构建到textFormField中的流畅特性相比,我将此解决方案称为hacky。希望你不介意 ;) - RobbB
1
@RobbB,你可以在TextFiledonChange参数中实现验证,并根据验证结果更改颜色。 以下是一个小例子: onChanged: (String text) { setState(() { _borderColor = text.length > 4 ? Colors.orange : Colors.red; }); }, 此外,你还可以使用TextEditingController进行高级控制。 如果你有问题,请提出具体的例子。 - Andrei R
显示剩余2条评论

2
class MyInputTextField extends StatefulWidget {
  final String? title;
  final String? helperText;
  final bool isSecure;
  final int maxLength;
  final String? hint;
  final TextInputType? inputType;
  final String? initValue;
  final Color? backColor;
  final Widget? suffix;
  final Widget? prefix;
  final TextEditingController? textEditingController;
  final String? Function(String? value)? validator;
  final Function(String)? onTextChanged;
  final Function(String)? onSaved;
  List<TextInputFormatter>? inputFormatters;

  static const int MAX_LENGTH = 500;

  MyInputTextField({
    this.title,
    this.hint,
    this.helperText,
    this.inputType,
    this.initValue = "",
    this.isSecure = false,
    this.textEditingController,
    this.validator,
    this.maxLength = MAX_LENGTH,
    this.onTextChanged,
    this.onSaved,
    this.inputFormatters,
    this.backColor,
    this.suffix,
    this.prefix,
  });

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

class _MyInputTextFieldState extends State<MyInputTextField> {
  late bool _passwordVisibility;
  late ThemeData theme;

  FocusNode _focusNode = FocusNode();

  Color _borderColor = getColors().primaryVariant;
  double _borderSize = 1;

  @override
  void initState() {
    super.initState();
    _passwordVisibility = !widget.isSecure;
    widget.textEditingController?.text = widget.initValue ?? "";

    _focusNode.addListener(() {
      setState(() {
        _borderSize = _focusNode.hasFocus ? 1.7 : 1;
      });
    });
  }

  @override
  void didChangeDependencies() {
    theme = Theme.of(context);
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Container(
          height: 55,
          decoration: BoxDecoration(
            border: Border.all(color: _borderColor, width: _borderSize),
            borderRadius: BorderRadius.circular(AppDimens.radiusSmall),
          ),
        ),
        Padding(
          padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
          child: TextFormField(
            focusNode: _focusNode,
            controller: widget.textEditingController,
            autocorrect: false,
            obscureText: !_passwordVisibility,
            keyboardType: widget.inputType,
            cursorColor: Colors.white,
            validator: (value) {
              String? f = widget.validator?.call(value);
              setState(() {
                _borderColor = f != null ? getColors().redError : getColors().primaryVariant;
              });
              return f;
            },
            style: theme.textTheme.bodyText1,
            maxLength: widget.maxLength,
            inputFormatters: widget.inputFormatters,
            maxLines: 1,
            onChanged: (text) {
              widget.onTextChanged?.call(text);
            },
            decoration: InputDecoration(
              counterText: "",
              hintStyle: theme.textTheme.subtitle1,
              floatingLabelStyle: theme.textTheme.headline6?.copyWith(color: getColors().textSubtitle),
              labelText: widget.title,
              helperText: widget.helperText,
              suffixIcon: getSuffixIcon(),
              prefixIcon: widget.prefix,
              contentPadding: EdgeInsets.zero,
              border: InputBorder.none,
            ),
          ),
        )
      ],
    );
  }

  Widget? getSuffixIcon() {
    return widget.isSecure ? getPasswordSuffixIcon() : widget.suffix;
  }

  Widget? getPasswordSuffixIcon() {
    return IconButton(
      hoverColor: Colors.transparent,
      focusColor: Colors.transparent,
      splashColor: Colors.transparent,
      padding: EdgeInsets.zero,
      icon: _passwordVisibility ? Icon(AppIcons.password_eye) : Icon(AppIcons.password_eye_blind),
      color: Colors.white,
      onPressed: () {
        setState(() {
          _passwordVisibility = !_passwordVisibility;
        });
      },
    );
  }

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

enter image description here

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接