简体   繁体   中英

TextFormField "error message" breaks the shadow applied to the Text Field

I made a TextField builder and customized it and added a shadow to it using "Material" widget And when an error message is shown to the user in the app the TextField gets pushed up but the shadow itself stays Where it was (code and picture included below)

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

class TextFieldBuilder extends StatefulWidget {
  TextFieldBuilder({
    Key key,
    this.icon,
    this.hint,
    this.obscure,
    this.height,
    this.fontSize,
    this.iconSize,
    this.fillColor,
    this.hintFontSize,
    this.iconColor,
    this.validatorFunction,
    this.textInputType,
    this.initialValue,
    this.onSavedFunc,
  }) : super(key: key);
  final IconData icon;
  final String hint;
  final bool obscure;
  final height, fontSize, iconSize, fillColor, hintFontSize;
  final iconColor;
  final validatorFunction;
  final textInputType;
  final initialValue;
  final onSavedFunc;
  @override
  _TextFieldBuilderState createState() => _TextFieldBuilderState();
}

class _TextFieldBuilderState extends State<TextFieldBuilder> {
  var _data;
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Material(
        color: Colors.transparent,
        borderRadius: BorderRadius.circular(9),
        child: Container(
          decoration:
              BoxDecoration(borderRadius: BorderRadius.circular(9), boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.15),
              blurRadius: 4,
              offset: Offset(1, 3),
            )
          ]),
          child: TextFormField(
            autovalidateMode: AutovalidateMode.onUserInteraction,
            initialValue: widget.initialValue ?? null,
            keyboardType: widget.textInputType ?? null,
            onSaved: widget.onSavedFunc ??
                (String value) {
                  _data = value.trim();
                  if (widget.hint != password &&
                      widget.hint != 'Confirm Password') {
                    print('${widget.hint} is $_data');
                  }
                },
            validator: widget.validatorFunction,
            style: TextStyle(
              color: Color(textColor),
              fontSize: widget.fontSize ?? 18,
            ),
            obscureText: widget.obscure ?? false,
            decoration: InputDecoration(
              contentPadding: EdgeInsets.symmetric(vertical: 1.0),
              prefixIcon: Icon(
                widget.icon ?? Icons.error,
                size: widget.iconSize ?? 35,
                color: widget.iconColor ?? Color(iconColor),
              ),
              filled: true,
              fillColor: Color(textFieldColor),
              hintText: widget.hint ?? placeholder,
              hintStyle: TextStyle(
                color: Color(textColor),
                fontSize: widget.fontSize ?? 18,
                height: widget.height ?? 0.9,
              ),
              border: OutlineInputBorder(
                borderSide: BorderSide.none,
                borderRadius: BorderRadius.circular(9),
              ),
              focusColor: Color(textFieldColor),
            ),
          ),
        ),
      ),
    );
  }
}

I tried wrapping both widgets with a container but it did not seem to help在此处输入图像描述

Combine your TextField with a Text and place both inside a Column . You will be able to replicate the error display without messing up the shadow. Remember to hide the default error message as well.

You can use the elevation and shadowColor property of Material to save some code lines btw. Something like:

Material(
    color: Colors.transparent,
    borderRadius: BorderRadius.circular(9),
    elevation: 4,
    shadowColor: Colors.black.withOpacity(0.15),
    // ... other lines
);

Example code:

// ... other lines

class _TextFieldBuilderState extends State<TextFieldBuilder> {
  var _data;
  String _errorText = '';

  @override
  Widget build(BuildContext context) {
    return Container(

      //!! Place both Widgets inside a Column
      child: Column( 
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Material(
            color: Colors.transparent,
            borderRadius: BorderRadius.circular(9),
            child: Container(
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(9),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withOpacity(0.15),
                      blurRadius: 4,
                      offset: Offset(1, 3),
                    )
                  ]),
              child: TextFormField(
                autovalidateMode: AutovalidateMode.onUserInteraction,
                initialValue: widget.initialValue ?? null,
                keyboardType: widget.textInputType ?? null,
                onSaved: widget.onSavedFunc ??
                    (String value) {
                      _data = value.trim();
                      if (widget.hint != password &&
                          widget.hint != 'Confirm Password') {
                        print('${widget.hint} is $_data');
                      }
                    },

                //!! Set the errorText value here, the Future delayed is to avoid calling [setState] during [build]
                validator: (value) {
                  Future.delayed(Duration.zero, () { 
                  // calling [setState] during [build]
                    setState(() {
                      _errorText = widget.validatorFunction(value) ?? '';
                    });
                  });
                  return _errorText;
                },
                style: TextStyle(
                  color: Color(textColor),
                  fontSize: widget.fontSize ?? 18,
                ),
                obscureText: widget.obscure ?? false,
                decoration: InputDecoration(
                  contentPadding: EdgeInsets.symmetric(vertical: 1.0),
                  prefixIcon: Icon(
                    widget.icon ?? Icons.error,
                    size: widget.iconSize ?? 35,
                    color: widget.iconColor ?? Color(iconColor),
                  ),
                  filled: true,
                  fillColor: Color(textFieldColor),

                  //!! Hide the default error message here
                  errorStyle: TextStyle(fontSize: 0), 
                  hintText: widget.hint ?? placeholder,
                  hintStyle: TextStyle(
                    color: Color(textColor),
                    fontSize: widget.fontSize ?? 18,
                    height: widget.height ?? 0.9,
                  ),
                  border: OutlineInputBorder(
                    borderSide: BorderSide.none,
                    borderRadius: BorderRadius.circular(9),
                  ),
                  focusColor: Color(textFieldColor),
                ),
              ),
            ),
          ),

          //!! Display the error message here
          if (_errorText.isNotEmpty)
            Text(
              _errorText,
              style: TextStyle(color: Colors.red),
            )
        ],
      ),
    );
  }
}
  • Material color must be transparent -> color: Colors.transparent, Like @Bach Said,
  • TextFormField error style font size should be 0 as @Bach said too, and the height property should be 1 -> errorStyle: TextStyle(fontSize: 0, height: 1)

and show the error message in another widget

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM