skip to Main Content

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<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),
          ),
        ),
      ),
    );
  }
}

This is used in my User Profile screen as follows:

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('User Profile'),
      ),
      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('New Username'),
                        content: Form(
                          key: _usernameFormKey,
                          child: CustomTextFormField(
                            controller: controller.usernameController,
                            label: 'Username',
                            hintText: 'Enter your username',
                            onChanged: (value) {
                              user = user.copyWith(username: value);
                              controller.user.value = user;
                            },
                            validator: FormValidators.validateUsername,
                          ),
                        ),
                        actions: [
                          TextButton(
                            child: const Text('Cancel'),
                            onPressed: () => Navigator.of(context).pop(),
                          ),
                          TextButton(
                            child: const Text('Save'),
                            onPressed: () {
                              if (_usernameFormKey.currentState!.validate()) {
                                controller.updateUser(user);
                                Navigator.of(context).pop();
                              }
                            },
                          ),
                        ],
                      ),
                    );
                  },
                  child: const Text("Change Username"),
                ),
[…]

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.
[Issue when typing][1]

Edit:
My App Theme:

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,
  );
}

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

const String fontFamily = 'Inter';
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,
);

2

Answers


  1. 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.

    Login or Signup to reply.
  2. seems like your text is being cut of but the padding of the dialog box ,
    try adjusting content padding and insetPadding

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search