5
votes

I have an app that is using ThemeData.dark(). When I tap on a text field, the label and text field turn a shade of green that I'd like to change.

enter image description here

What aspect of the theme do I have to change to get a different color?

Edit: I implemented the answer and still wasn't getting the label to be blue. So I started working backward in my code, removing various elements of the TextField and found that the color wasn't being carried forward if there was a labelStyle applied. This doesn't work:

return Container(
  child: TextField(
    controller: widget.textFieldController,
    inputFormatters: [
      LengthLimitingTextInputFormatter(5),
      ThousandsFormatter(
        allowFraction: true,
      ),
    ],
    keyboardType: TextInputType.numberWithOptions(
      signed: false,
    ),
    decoration: InputDecoration(
      labelText: widget.labelText,
      hintText: widget.hintText,
      labelStyle: TextStyle(
        fontSize: 15,
        fontWeight: FontWeight.w700,
      ),
    ),
  ),
);

If I remove the labelStyle, the it works fine:

return Container(
  child: TextField(
    controller: widget.textFieldController,
    inputFormatters: [
      LengthLimitingTextInputFormatter(5),
      ThousandsFormatter(
        allowFraction: true,
      ),
    ],
    keyboardType: TextInputType.numberWithOptions(
      signed: false,
    ),
    decoration: InputDecoration(
      labelText: widget.labelText,
      hintText: widget.hintText,
    ),
  ),
);

I do want to be able to apply the labelStyle so that I can change the fontSize and fontWeight. Is this a bug in Flutter, or is there something else that I'm missing.

Edit: For the sake of simplicity, I created a new project with just one TextField on it and nothing else. Just to eliminate any other possible causes. I followed the instructions in the proposed answer and the label is still blue when the field does not have focus.

Text Field Without Focus enter image description here

What I need to do is get it so that the label of the field without focus is the same default grey color as the underline.

This is the code that I implemented. I don't think that I missed anything.

  darkTheme: ThemeData(
    brightness: Brightness.dark,
    buttonColor: Colors.deepPurple.shade600,
    inputDecorationTheme: InputDecorationTheme(
      labelStyle: TextStyle(
        color: Colors.blue,
      ),
      focusedBorder: UnderlineInputBorder(
        borderSide: BorderSide(
          style: BorderStyle.solid,
          color: Colors.blue,
        ),
      ),
    ),
    appBarTheme: AppBarTheme(
      color: Colors.deepPurple.shade600,
    ),
  ),

return Scaffold(
  appBar: AppBar(
    // Here we take the value from the MyHomePage object that was created by
    // the App.build method, and use it to set our appbar title.
    title: Text(widget.title),
  ),
  body: Padding(
    padding: const EdgeInsets.all(20.0),
    child: TextField(
      decoration: InputDecoration(
        labelText: 'First Name',
        labelStyle:
            Theme.of(context).inputDecorationTheme.labelStyle.copyWith(
                  fontSize: 15,
                  fontWeight: FontWeight.w700,
                ),
      ),
    ),
  ),
);
1

1 Answers

4
votes

You will have to define your custom theme in which you have to do ThemeData brightness to dark.

If you will see the ThemeData class you will find out that it does nothing but only sets brightness to dark for ThemeData.dark().

The properties that you are looking for is border and labelStyle inside the InputDecorationTheme. There are three properties for border namely focusedBorder when your TextInput is focused, enabledBorder when your TextInput is enabled in the form you are showing and border when you just want to set the default border.

The way you can do this is like this:

ThemeData data = ThemeData(
      brightness: Brightness.dark,
      inputDecorationTheme: InputDecorationTheme(
        labelStyle: TextStyle(color: Colors.blue),
        focusedBorder: UnderlineInputBorder(
          borderSide: BorderSide(
               style: BorderStyle.solid, 
               color: Colors.blue
          ),
        )
      )
    );

There is another InputBorder attribute called OutlineInputBorder, which usually is used when you want to define all the borders for the TextInput.

EDIT:

In TextField Widget there is a method called _getEffectiveDecoration(), which is responsible for setting the decoration for the TextField.

Here is a snippet of that method:

final InputDecoration effectiveDecoration = (widget.decoration ?? const InputDecoration())
      .applyDefaults(themeData.inputDecorationTheme)
      .copyWith(
        enabled: widget.enabled,
        hintMaxLines: widget.decoration?.hintMaxLines ?? widget.maxLines,
      );

In the above snippet it can be clearly seen that firstly the decoration that you provide for your TextField is set and then the defaults are applied which are taken from your Theme. What applyDefaults does is that, that it checks whether a particular property is already applied to the TextField or not, if yes, then that property will override the default property, if no, then it will apply the default styling for that property provided by the Theme.

So in your case, what you want is that, that you want to apply a combination of both that is applied in theme and that you have passed.

For that you will have to write your widget like this:

return Container(
  child: TextField(
    controller: widget.textFieldController,
    inputFormatters: [
      LengthLimitingTextInputFormatter(5),
      ThousandsFormatter(
        allowFraction: true,
      ),
    ],
    keyboardType: TextInputType.numberWithOptions(
      signed: false,
    ),
    decoration: InputDecoration(
      labelText: widget.labelText,
      hintText: widget.hintText,
      labelStyle: Theme.of(context)
        .inputDecorationTheme
        .labelStyle
        .copyWith(
          fontSize: 15,
          fontWeight: FontWeight.w700,
        ),
      ),
    ),
);