TextFormField 输入时错误消息未正确显示

huangapple go评论96阅读模式
英文:

TextFormField error message not displayed correctly when typing

问题

我有一个CustomTextFormField,它是TextFormField的一个包装,如下所示:

import 'package:flutter/material.dart';

class CustomTextFormField extends StatelessWidget {
  final TextEditingController controller;
  final String hintText;
  final String label;
  final bool obscureText;
  final FormFieldValidator<String>? validator;
  final ValueChanged<String>? onChanged;

  const CustomTextFormField({
    Key? key,
    required this.controller,
    required this.hintText,
    this.obscureText = false,
    required this.label,
    this.validator,
    this.onChanged,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      autovalidateMode: AutovalidateMode.onUserInteraction,
      controller: controller,
      obscureText: obscureText,
      validator: validator,
      onChanged: onChanged,
      decoration: InputDecoration(
        filled: true,
        fillColor: Theme.of(context).colorScheme.surfaceVariant,
        contentPadding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
        labelText: label,
        labelStyle: Theme.of(context).textTheme.labelSmall,
        hintText: hintText,
        hintStyle: Theme.of(context).textTheme.labelMedium,
        border: OutlineInputBorder(
          borderSide: BorderSide(width: 0.50, color: Theme.of(context).colorScheme.primary),
          gapPadding: 0,
          borderRadius: const BorderRadius.all(
            Radius.circular(10),
          ),
        ),
      ),
    );
  }
}
这在我的用户资料屏幕中使用如下:

class UserProfileScreen extends GetView<UserController> {
  UserProfileScreen({Key? key}) : super(key: key);

  final _formKey = GlobalKey<FormState>();
  final _usernameFormKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('用户资料'),
      ),
      drawer: CustomDrawer(),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Obx(() {
            UserModel user = controller.user.value!;
            return Column(
              mainAxisAlignment: MainAxisAlignment.start,
              children: <Widget>[
                const CircleAvatar(
                  radius: 50,
                  backgroundColor: Colors.grey,
                  child: Icon(
                    Icons.person,
                    size: 50,
                  ),
                ),
                const SizedBox(height: 20.0),
                Text(
                  user.username,
                  style: const TextStyle(
                    fontSize: 20.0,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 10.0),
                ElevatedButton(
                  onPressed: () {
                    showDialog(
                      context: context,
                      builder: (_) => AlertDialog(
                        title: const Text('新用户名'),
                        content: Form(
                          key: _usernameFormKey,
                          child: CustomTextFormField(
                            controller: controller.usernameController,
                            label: '用户名',
                            hintText: '输入您的用户名',
                            onChanged: (value) {
                              user = user.copyWith(username: value);
                              controller.user.value = user;
                            },
                            validator: FormValidators.validateUsername,
                          ),
                        ),
                        actions: [
                          TextButton(
                            child: const Text('取消'),
                            onPressed: () => Navigator.of(context).pop(),
                          ),
                          TextButton(
                            child: const Text('保存'),
                            onPressed: () {
                              if (_usernameFormKey.currentState!.validate()) {
                                controller.updateUser(user);
                                Navigator.of(context).pop();
                              }
                            },
                          ),
                        ],
                      ),
                    );
                  },
                  child: const Text("更改用户名"),
                ),
错误消息在TextFormField中没有文本时正确显示,但当用户开始输入时,垂直裁剪。请参考附带的截图以获取更清晰的信息。
我的应用程序主题:

import 'package:flutter/material.dart';
import 'package:mastermind_together/src/ui/theme/color_scheme.dart';
import 'package:mastermind_together/src/ui/theme/text_styles.dart';

class AppTheme {
  AppTheme._();

  static ThemeData lightTheme = ThemeData(
    colorScheme: lightThemeColors,
    useMaterial3: true,
    textTheme: textTheme,
    buttonTheme: ButtonThemeData(
      buttonColor: lightThemeColors.primary,
      textTheme: ButtonTextTheme.primary,
    ),
    canvasColor: lightThemeColors.surface,
  );

  static TextTheme textTheme = const TextTheme(
    displayLarge: h1,
    displayMedium: h2,
    bodyLarge: bodyMedium,
    bodyMedium: body,
    bodySmall: labelSmall,
    labelLarge: btnText,
    labelMedium: placeholderBodyMedium,
    labelSmall: labelText,
    headlineMedium: h3,
    titleMedium: bodyMedium,
  );
}
英文:

I have a CustomTextFormField which is a wrapper over a TextFormField as below:

import 'package:flutter/material.dart';

class CustomTextFormField extends StatelessWidget {
final TextEditingController controller;
final String hintText;
final String label;
final bool obscureText;
final FormFieldValidator&lt;String&gt;? validator;
final ValueChanged&lt;String&gt;? onChanged;
const CustomTextFormField({
Key? key,
required this.controller,
required this.hintText,
this.obscureText = false,
required this.label,
this.validator,
this.onChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
controller: controller,
obscureText: obscureText,
validator: validator,
onChanged: onChanged,
decoration: InputDecoration(
filled: true,
fillColor: Theme.of(context).colorScheme.surfaceVariant,
contentPadding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
labelText: label,
labelStyle: Theme.of(context).textTheme.labelSmall,
hintText: hintText,
hintStyle: Theme.of(context).textTheme.labelMedium,
border: OutlineInputBorder(
borderSide: BorderSide(width: 0.50, color: Theme.of(context).colorScheme.primary),
gapPadding: 0,
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
),
),
);
}
}

This is used in my User Profile screen as follows:

class UserProfileScreen extends GetView&lt;UserController&gt; {
UserProfileScreen({Key? key}) : super(key: key);
final _formKey = GlobalKey&lt;FormState&gt;();
final _usernameFormKey = GlobalKey&lt;FormState&gt;();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(&#39;User Profile&#39;),
),
drawer: CustomDrawer(),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Obx(() {
UserModel user = controller.user.value!;
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: &lt;Widget&gt;[
const CircleAvatar(
radius: 50,
backgroundColor: Colors.grey,
child: Icon(
Icons.person,
size: 50,
),
),
const SizedBox(height: 20.0),
Text(
user.username,
style: const TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10.0),
ElevatedButton(
onPressed: () {
showDialog(
context: context,
builder: (_) =&gt; AlertDialog(
title: const Text(&#39;New Username&#39;),
content: Form(
key: _usernameFormKey,
child: CustomTextFormField(
controller: controller.usernameController,
label: &#39;Username&#39;,
hintText: &#39;Enter your username&#39;,
onChanged: (value) {
user = user.copyWith(username: value);
controller.user.value = user;
},
validator: FormValidators.validateUsername,
),
),
actions: [
TextButton(
child: const Text(&#39;Cancel&#39;),
onPressed: () =&gt; Navigator.of(context).pop(),
),
TextButton(
child: const Text(&#39;Save&#39;),
onPressed: () {
if (_usernameFormKey.currentState!.validate()) {
controller.updateUser(user);
Navigator.of(context).pop();
}
},
),
],
),
);
},
child: const Text(&quot;Change Username&quot;),
),

[...]

The error message is properly displayed when there is no text in the TextFormField, but it is vertically trimmed when the user starts typing. Please see the attached screenshots for clarity.
[TextFormField 输入时错误消息未正确显示

Edit:
My App Theme:

import &#39;package:flutter/material.dart&#39;;
import &#39;package:mastermind_together/src/ui/theme/color_scheme.dart&#39;;
import &#39;package:mastermind_together/src/ui/theme/text_styles.dart&#39;;
class AppTheme {
AppTheme._();
static ThemeData lightTheme = ThemeData(
colorScheme: lightThemeColors,
useMaterial3: true,
textTheme: textTheme,
buttonTheme: ButtonThemeData(
buttonColor: lightThemeColors.primary,
textTheme: ButtonTextTheme.primary,
),
canvasColor: lightThemeColors.surface,
);
static TextTheme textTheme = const TextTheme(
displayLarge: h1,
displayMedium: h2,
bodyLarge: bodyMedium,
bodyMedium: body,
bodySmall: labelSmall,
labelLarge: btnText,
labelMedium: placeholderBodyMedium,
labelSmall: labelText,
headlineMedium: h3,
titleMedium: bodyMedium,
);
}
import &#39;package:flutter/material.dart&#39;;
import &#39;package:mastermind_together/src/ui/theme/color_scheme.dart&#39;;
const String fontFamily = &#39;Inter&#39;;
const Color textColor = darkerPrimaryColor;
const Color textPlaceholderColor = placeholderColor;
const Color btnTextColor = Colors.white; //TODO move to color_scheme
const Color linkColor = Colors.blue;
const TextStyle h1 = TextStyle(
color: textColor,
fontSize: 64,
fontFamily: fontFamily,
fontWeight: FontWeight.w700,
);
const TextStyle h2 = TextStyle(
color: textColor,
fontSize: 42,
fontFamily: fontFamily,
fontWeight: FontWeight.w400,
);
const TextStyle h3 = TextStyle(
color: textColor,
fontSize: 26,
fontFamily: fontFamily,
fontWeight: FontWeight.w700,
);
const TextStyle body = TextStyle(
color: textColor,
fontSize: 16,
fontFamily: fontFamily,
fontWeight: FontWeight.w400,
);
const TextStyle bodyMediumLink = TextStyle(
color: textColor,
fontSize: 16,
fontFamily: fontFamily,
fontWeight: FontWeight.w500,
decoration: TextDecoration.underline,
);
const TextStyle linkStyle = TextStyle(
color: linkColor,
fontSize: 16,
fontFamily: fontFamily,
fontWeight: FontWeight.w700,
decoration: TextDecoration.underline,
);
const TextStyle bodyMedium = TextStyle(
color: textColor,
fontSize: 16,
fontFamily: fontFamily,
fontWeight: FontWeight.w500,
);
const TextStyle placeholderBodyMedium = TextStyle(
color: textPlaceholderColor,
fontSize: 16,
fontFamily: fontFamily,
fontWeight: FontWeight.w400,
height: 1.6,
);
const TextStyle labelText = TextStyle(
color: textColor,
fontSize: 14,
fontFamily: fontFamily,
fontWeight: FontWeight.w500,
// height: 2.0,
);
const TextStyle cardTitle = TextStyle(
color: textColor,
fontSize: 26,
fontFamily: fontFamily,
fontWeight: FontWeight.w600,
);
const TextStyle labelSmall = TextStyle(
color: textColor,
fontSize: 10,
fontFamily: fontFamily,
fontWeight: FontWeight.w400,
height: 0.4,
);
const TextStyle btnText = TextStyle(
color: btnTextColor,
fontSize: 16,
fontFamily: fontFamily,
fontWeight: FontWeight.w700,
);

答案1

得分: 1

检查一下你的应用主题是否引起了这个问题。当我测试你的初始弹出对话框时,我没有遇到你所描述的问题。尝试将你在设置MaterialApp时设置主题的地方注释掉,看看问题是否消失。如果消失了,更仔细地查看你的主题,看看可能引起问题的原因。

英文:

Check to see if the theme for your app is causing this. When I tested your initial popup dialog I did not run into the problem that you described. Try commenting out your theme setting where you set up your MaterialApp and see if the problem goes away. If it does look closer at your theme to see what might be causing the issue.

答案2

得分: 0

I'm here to help with your Chinese translation. Here's the translation of the provided text:

"不要使用TextField的内置错误字段,可以将TextField包装在Column中的CustomTextFormField中,并在文本字段下方添加一个文本小部件。这样,您可以轻松控制错误小部件。"

英文:

Instead of using the inbuilt error field of TextField, you can wrap your TextField in CustomTextFormField in a column and add a text widget below the textfield. This way you can easily control the error widget.

答案3

得分: 0

似乎您的文本被截断,但对话框的填充有问题,请尝试调整内容填充和插入填充。

英文:

seems like your text is being cut of but the padding of the dialog box ,
try adjusting content padding and insetPadding

huangapple
  • 本文由 发表于 2023年7月31日 21:56:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76804338.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定