I am currently trying to implement a TextField that should change the background Color-based on the state of the Text Field (unfocused, focused, error).
I have tried to implement this by using a List that manages only whether the TextField is selected or not. I use a GestureDetector to set that value. But this seems way too hacky to be a good solution, especially because tapping on the TextField isn't the only way to focus it.
At this point, I was hoping that there is a way to get the same information the TextField Widget uses to display the appropriate border style. But I am not sure if it is possible to access this information. A tip on how to do so would be highly appreciated.
I was also thinking that I could use the FocusScope for this, but I could not find a way to call .hasFocus on a single TextFormField, because it only shows me whether one TextFormField in the whole Form is selected and not which one.
Thank you!
You can either use FocusNode or Focus inside a FocusScope to achieve something like this. TextField itself uses a FocusNode to determine if it has focus or not and then animates the color changes when the focus state changes. Here is an example implementation using Focus and a Builder to rebuild only the TextFields which changed focus:
https://dartpad.dev/8488f470b166e4235b64d3ba568b6ba6?null_safety=true
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
/// This is the private State class that goes with MyStatefulWidget.
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget();
@override
Widget build(BuildContext context) {
return FocusScope(
debugLabel: 'Scope',
autofocus: true,
child: Form(
child: Column(
children: [
Focus(
debugLabel: 'TextField1',
child: Builder(
builder: (BuildContext context) {
final FocusNode focusNode = Focus.of(context);
final bool hasFocus = focusNode.hasFocus;
return TextField(
decoration: InputDecoration(
fillColor: hasFocus ? Colors.green : Colors.white,
filled: true
)
);
},
),
),
Focus(
debugLabel: 'TextField2',
child: Builder(
builder: (BuildContext context) {
final FocusNode focusNode = Focus.of(context);
final bool hasFocus = focusNode.hasFocus;
return TextField(
decoration: InputDecoration(
fillColor: hasFocus ? Colors.green : Colors.white,
filled: true
)
);
}
)
)
],
),
),
);
}
}
You can of course also directly use a FocusNode. For that you probably would have to wrap the TextFields into a StatefulWidget and then add a listener to the FocusNode used, so that you can trigger a rebuild (with setState) when the focus changes. But be aware that you need to manage the lifecycle of this FocusNode. Quote from the documentation:
Managing a FocusNode means managing its lifecycle, listening for changes in focus, and re-parenting it when needed to keep the focus hierarchy in sync with the widget hierarchy. This widget does all of those things for you. See FocusNode for more information about the details of what node management entails if you are not using a Focus widget and you need to do it yourself.
https://api.flutter.dev/flutter/widgets/Focus-class.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With