When I type a text and hit 'ok' or click the back button to hide the keyboard the input's value vanishes
Adding a TextEditingController
class ChatCepBottomSheet extends StatelessWidget {
final TextEditingController _cepController = TextEditingController();
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TextFormField(
controller: _cepController,
),
SizedBox(height: 32),
Button(
buttonText: 'Search',
tapHandler: () {},
)
],
);
}
}
I expected that the typed text staid in the text controller
When keyboard opens it changes the screen behavior and when we close it it re renders the screen and due to that this field initialized again by empty constructor.
TextEditingController _cepController = TextEditingController();
Stateful or stateless it doesnt matter if you are in this kind of issue like keyboard opening etc
try defining final TextEditingController _cepController = TextEditingController(); outside of this class
What you are trying to do will not work with Flutter. You are using a stateless widget and trying to preserve state (data), which is impossible by definition. You need to rewrite your class using a stateful widget - https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html.
See an example below:
import 'package:flutter/material.dart';
class ChatCepBottomSheet extends StatefulWidget {
#override
_ChatCepBottomSheetState createState() => _ChatCepBottomSheetState();
}
class _ChatCepBottomSheetState extends State<ChatCepBottomSheet> {
final TextEditingController _cepController = TextEditingController();
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TextFormField(
controller: _cepController,
),
SizedBox(height: 32),
Button( //choose a button class or custom class
buttonText: 'Search',
tapHandler: () {},
)
],
);
}
}````
The declaration of the "Button" is wrong. Check the Docs for more information. Plus, you can't preserve the state in a StatelessWidget.
This will help:
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final TextEditingController _cepController = TextEditingController();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: Text('Demo')),
body: Column(
children: <Widget>[
TextFormField(
controller: _cepController,
),
SizedBox(height: 32),
FlatButton(
child: Text('Search'),
onPressed: () {},
)
],
)
);
}
}
I had a similar problem. Not sure this is the solution, as other answers above have already proposed a solution, but what worked for me was; Removing the texteditingcontroller and using an onChanged instead
Related
I'd like to create a screen in which many TextFIelds lined up vertically, and when the Enter key is pressed while editing the bottom TextField, a new TextField is added below it moving the focus too. I created a demo app referring to the example in the docs of FocusNode and it works basically but the keyboard bounces when moving the focus to a newly created TextField (see the gif below). How can I fix this unwanted behavior?
The gif of the demo app
The code of the demo app is here:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int focusedChild = 0;
List<Widget> children = <Widget>[];
List<FocusNode> childFocusNodes = <FocusNode>[];
#override
void initState() {
super.initState();
// Add the first child.
_addChild();
}
#override
void dispose() {
for (final FocusNode node in childFocusNodes) {
node.dispose();
}
super.dispose();
}
void _addChild() {
// Calling requestFocus here creates a deferred request for focus, since the
// node is not yet part of the focus tree.
childFocusNodes
.add(FocusNode(debugLabel: 'Child ${children.length}')..requestFocus());
children.add(
TextField(
focusNode: childFocusNodes.last,
textInputAction: TextInputAction.unspecified,
minLines: 1,
onSubmitted: (value) {
setState(() {
focusedChild = children.length;
_addChild();
});
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: children,
),
),
),
);
}
}
Screenshot
You need to use TextInputAction
TextInputAction.next: Moves the focus to the next focusable item.
TextInputAction.done: To close the keyboard.
class TestWidget extends StatelessWidget {
const TestWidget({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: const [
TextField(
decoration: InputDecoration(hintText: 'TextField #1 with next'),
textInputAction: TextInputAction.next, // Moves the focus to the next focusable item.
),
TextField(
decoration: InputDecoration(hintText: 'TextField #2 with next'),
textInputAction: TextInputAction.next, // Moves the focus to the next focusable item.
),
TextField(
decoration: InputDecoration(hintText: 'TextField #3 with done'),
textInputAction: TextInputAction.done, // Close the keyboard.
),
],
),
),
);
}
}
Update
Create a new text field on editing complete and change focus to the new one.
You need to use onEditingComplete function, instead of onSubmitted. Because onEditingComplete will not close (dismiss) the keyboard.
I rewrite your code, and remove generating a list of widgets. And replaced it with TextEditingController because it's a bad experience to keep UI (widgets) in a variable. So text fields generates by TextEditingController length.
I remove a list of FocusNode, and use FocusScope.of(context).nextFocus() to change the focus.
After creating a new TextEditingController function call delayed nextFocus() with delay, to give time to recreate the new UI.
here is the full code:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(home: MyStatefulWidget());
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final List<TextEditingController> _controllers = [
TextEditingController()
]; // with first controller
_addController() {
setState(() {
_controllers.add(TextEditingController());
});
Future.delayed(const Duration(milliseconds: 100), () {
// Add delay for recreate UI after setState
FocusScope.of(context).nextFocus();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: _controllers
.map((e) => TextField(
textInputAction: TextInputAction.next,
controller: e,
onEditingComplete: _addController,
))
.toList(),
),
),
),
);
}
}
How insert text to list from text field and then text field will clear when added by button?
List texts = []
Insert from text field to list after pressing onChanged funciton.
Let's try
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:so_test/screen/exapmple_page.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: MyStatefulWidget(),
),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool selected = false;
List<String> text = [];
TextEditingController _controller = TextEditingController();
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(color: Colors.white12),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
TextFormField(
controller: _controller,
),
TextButton(
onPressed: () {
setState(() {
if(_controller.text.length>0){
text.add(_controller.text);
_controller.clear();
} else{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("Text is empty"),
));
}
});
},
child: Text("add"),
),
Text(text.isNotEmpty?text.toString():""),
],
),
),
);
}
}
on the onTap or onPressed you could do something like this:
onTap:(){
texts.add(_textController.text);
_textController.clear();
}
Note: You have not provided enough information in this question, so I am assuming that your TextController name is _textController
try to send the data on onSubmit if you done typing
onSubmit:(String value){
print(value);
text.add(value);
}
Here you are doing 2 thing
1> Appending or adding value to the list
2> Clearing the text filed
Here you want to use TextEditingController This help to access the test from the textfield.
Declare TextTditingcontroller by : -
TextEditingController Input = TextEditingController();
NB : controller: Input inside your TextFormField
1> For adding to list
Add this inside your onSubmit or Ontap function
List.add("Input.text");
2> For clearing the text filed
setState(() {
inputController.text = "";
});
Put this inside your onSubmit Function.
Make sure you are using stateful widget
Thank you
You can use the TextEditingController.
You need to create an instance of it and pass it to the TextField in this way.
TextEditingController _instance = TextEditingController();
TextField(controller: _instance);
And then when you press your Button you should do something like
Button(
onPressed: (){
List.add(_instance.text);
_instance.text = '';
setState((){});
}
)
Note that the TextEditingController should be created once
I have the following widgets where each widget exists in their own file.
(There is alot more going on in each file. I have condensed it to keep it minimal to only see what's needed for this query).
I wish to capture values passed into a TextFormField within one widget and print out those values in another widget.
There is no visual state changes going on thus trying not to store these values via Provider which I felt would be silly for this usecase.
Thus the query is on how to pass down the value captured in a TextEditingController for each widget's instance and pass it down to another widget?
To reiterate, the following 3 classes, they exist in their own Dart file.
I was initially sticking with stateless widget for all 3 but from what I read up, advice is to user a stateful widget where TextEditingController is involved.
Thus the MyField widget is stateful.
MyField Widget - This is where the value is expected to get stored to controller based on what's been typed in.
class MyField extends StatefulWidget {
final String title;
final TextEditingController controller;
const MyField({this.controller, this.title});
#override
_MyFieldState createState() => _MyFieldState();
}
class _MyFieldState extends State<MyField> {
#override
Widget build(BuildContext context) {
return TextFormField(
controller: widget.controller,
);
}
}
MyForm Widget - This takes in 2 instances of above widget, each having its own controller.
This widget helps pass on the text values down to the MyButton widget.
class MyForm extends StatelessWidget {
final formKey = GlobalKey<FormState>();
final nameController = TextEditingController();
final passController = TextEditingController();
#override
Widget build(BuildContext context) {
return Form(
key: formKey,
child: Stack(
children: [
MyField(
title: 'name',
controller: nameController,
),
MyField(
title: 'pass',
controller: passController,
),
MyButton(
name: nameController.text,
pass: passController.text,
formKey: formKey)
],
),
);
}
}
MyButton Widget - This widget captures those text values and tries to print out the values and it currently comes out empty.
class MyButton extends StatelessWidget {
final formKey;
final String name;
final String pass;
const MyButton({Key key, this.formKey, this.name, this.pass}) : super(key: key);
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
// I want to be able to retrieve the text via the controllers for the 2 text fields.
// currently these values are empty which is the issue.
print('name: $name pass: $pass');
},
);
}
}
You can store the value in an object file and get or edit its value from any other file in the project.. for example in file named user.dart :
class user {
static String name;
static String pass;
}
then at any other place import the file and set or get its values as you want:
user.name = nameController.text
user.pass = passController.text
print('name: ' + user.name + 'pass: ' + user.pass);
if your problem is that you want to show the text before the button is clicked, I think you might make your widget stateful and then you can use change event in the Text field:
onChanged: (value) {
setState(() {
user.name = nameController.text;
});}
Here is my try.
Need to change from 'Stack' to 'Column' in MyForm class.
getting value from TextFormField using 'formKey'
(Although I used a formkey, but I hope to control value from outside of 'MyForm' than Getting a value by using 'formkey')
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _buildBody() {
return MyForm();
}
}
class MyButton extends StatelessWidget {
final formKey;
final String label;
const MyButton({Key key, this.formKey, this.label}) : super(key: key);
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
// I want to be able to retrieve the text via the controllers for the 2 text fields.
// currently these values are empty which is the issue.
print(
'name: ${formKey.currentWidget.child.children[0].controller.text} ');
print(
'pass: ${formKey.currentWidget.child.children[1].controller.text} ');
},
child: Text(label),
);
}
}
class MyForm extends StatelessWidget {
final formKey = GlobalKey<FormState>();
final nameController = TextEditingController();
final passController = TextEditingController();
#override
Widget build(BuildContext context) {
return Form(
key: formKey,
child: Column(
children: [
MyField(
title: 'name',
controller: nameController,
),
MyField(
title: 'pass',
controller: passController,
),
MyButton(label: 'Button', formKey: formKey)
],
),
);
}
}
class MyField extends StatefulWidget {
final String title;
final TextEditingController controller;
const MyField({this.controller, this.title});
#override
_MyFieldState createState() => _MyFieldState();
}
class _MyFieldState extends State<MyField> {
#override
Widget build(BuildContext context) {
return TextFormField(
controller: widget.controller,
);
}
}
Well if you are not using the user typed texts to update the UI state of MyButton widget you don't even need it you can just access the controllers texts in MyForm widget.
class MyForm extends StatelessWidget {
final formKey = GlobalKey<FormState>();
final nameController = TextEditingController();
final passController = TextEditingController();
#override
Widget build(BuildContext context) {
return Form(
key: formKey,
child: Column(
children: [
MyField(
title: 'name',
controller: nameController,
),
MyField(
title: 'pass',
controller: passController,
),
RaisedButton(
onPressed() {
print("${nameController.text}");
print("${passController.text}");
}
),
],
),
);
}
}
But if you want to update MyButton widget on the fly while the user is typing a text so MyForm widgets needs to be Statefull and must rebuild in every user type event.
//NOTE: Assuming `MyForm` is a Statefull widget
final nameController = TextEditingController();
final passController = TextEditingController();
#override
void initState() {
// listening the textfield.
nameController.addListener(_controllerListener);
passController.addListener(_controllerListener);
super.initState();
}
void _controllerListener(){
if(mounted)
setState((){});
}
#override
Widget build(BuildContext context) {
return Form(
key: formKey,
child: Stack(
children: [
MyField(
title: 'name',
controller: nameController,
),
MyField(
title: 'pass',
controller: passController,
),
MyButton(
name: nameController.text,
pass: passController.text,
onPressed: () {
print("${nameController.text} - ${passController.text}");
})
],
),
);
}
}
class MyButton extends StatelessWidget {
final String name;
final String pass;
final VoidCallback onPressed;
const MyButton({Key key, this.onPressed, this.name, this.pass}) : super(key: key);
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: this.onPressed,
// updating UI on type event.
child: Text('$name and $pass'),
);
}
}
please change MyForm class to below Class...
How It Works ?
your Button Should rebuild after each change on TextFormField so I used a Stream builder and a Stream
class MyForm extends StatelessWidget {
final formKey = GlobalKey<FormState>();
final nameController = TextEditingController();
final passController = TextEditingController();
StreamController<int> sc = StreamController<int>();
#override
Widget build(BuildContext context) {
return Form(
key: formKey,
onChanged: () {
sc.add(1);
},
child: Column(
children: [
MyField(
title: 'name',
controller: nameController,
),
MyField(
title: 'pass',
controller: passController,
),
StreamBuilder<int>(
stream: sc.stream,
builder: (context, snapshot) {
return MyButton(
name: nameController.text,
pass: passController.text,
formKey: formKey);
}
)
],
),
);
}
}
I'm having trouble accessing instances of objects (or States) in Flutter, from other classes. I've tried a lot of fiddling using similar questions on the web, and am currently using 'GlobalKey', but I just can't get it working.
I'm trying to make a simple Flutter app where the State of a Widget gets accessed from another class, on button press:
import 'viewer.dart' as viewer;
(...)
onPressed: () {
//Works
print("Doing something");
//Doesn't work
viewer.key.currentState.nextPage();
},
My viewer.dart file looks contains a PageController, and a class containing that controller:
final key = new GlobalKey<_RegistryState>();
final PageController _controller = PageController(
initialPage: 0,
);
class Registry extends StatefulWidget {
Registry({ Key key }) : super(key: key);
#override
_RegistryState createState() => _RegistryState();
}
class _RegistryState extends State<Registry> {
void next() {
print("Doing something!");
_controller.nextPage();
}
#override
Widget build(BuildContext context) {
return PageView(
//physics: NeverScrollableScrollPhysics(), //Disable user manually scrolling
controller: _controller,
children: [
registry_screens.ScreenSplash(),
registry_screens.ScreenName(),
Text("Bye"),
],
);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
}
The idea is that whenever the button gets pressed, the PageController moves to the next page (which is already there, I can scroll to it manually by swiping on the screen).
The app compiles fine, but when pressing the button I get the error 'NoSuchMethodError: invalid member on null: 'next''.
Am I using the correct approach for accessing instances of Widgets (or States)?
Flutter is a declarative framework. In this kind of environment, everytime that you want to change the view (or interface) you need to rebuild it. And if you rebuild what is holding the state, you would loose it. That's why it should not be responsible of holding the state of the program.
State management in Flutter is a broad subject with lots of options. As #DrSatan1 mentioned in the comments, in Flutter.dev you can find good documentation about state management using Provider, but you have lots of options with BLoC, ReduX, MobX, etc.
In your specific scenario, since it is simpler, you could accomplish that using a global object or Inherited Widget.
Global Object
globals.dart
currentPage=0;
In the Widget
import 'globals.dart' as global;
(...)
onPressed: () {
setState((){
globals.currentPage++;
});
},
viewer.dart
#override
Widget build(BuildContext context) {
return PageView(
//physics: NeverScrollableScrollPhysics(), //Disable user manually scrolling
currentPage: globals.currentPage, //instead of using PageController
children: [
registry_screens.ScreenSplash(),
registry_screens.ScreenName(),
Text("Bye"),
],
);
}
You could use the PageController as your global object. In that case you could pass the PageController down the widget tree. In this case, it would be better to use InheritedWidget instead.
InheritedWidget
As per docs, InheritedWidget is
Base class for widgets that efficiently propagate information down the
tree.
You can pass your PageController to all the widgets below the tree. Your viewer.dart would be:
(...)
#override
Widget build(BuildContext context) {
return MyInheritedWidget (
pageController: _controller,
child: PageView(
//physics: NeverScrollableScrollPhysics(), //Disable user manually scrolling
//controller: _controller, // Don't pass controller here
children: [
registry_screens.ScreenSplash(),
registry_screens.ScreenName(),
Text("Bye"),
],
);
);
}
(...)
// create the inherited widget wrapper. It could be done with [Builder][7] too, instead of a different Widget.
class MyInheritedWidget extends InheritedWidget {
final PageController pageController;
MyInheritedWidget({
Key key,
#required Widget child,
#required this.pageController,
}) : super(key: key, child: child);
#override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
}
(...)
After that you can access pageController in PageView or any Widget under it.
(...)
onPressed: () {
//Works
print("Doing something");
// Find closest InheritedWidget
MyInheritedWidget myInheritedWidget =
context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>()
// Get pageController from it
PageController controller = myInheritedWidget.pageController
// call nextPage()
nextPage();
},
(...)
Although both methods works in your specific scenario, you should check Flutter Docs about state management. Maybe you don't need the PageController at all.
It's generally a bad idea for state to be accessed externally. Instead, external classes should only interact with Widgets through the methods they expose.
I just made a video walking through the exact same onboarding setup you have using a PageView, which you can see here -- as I go through it step-by-step: https://www.youtube.com/watch?v=ji__FEKSnMw
In essence, it looks like this:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MainPage(),
debugShowCheckedModeBanner: false,
);
}
}
class MainPage extends StatefulWidget {
const MainPage({Key key}) : super(key: key);
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
PageController pageController = new PageController(initialPage: 0);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Container(
child: PageView(
controller: pageController,
physics: NeverScrollableScrollPhysics(),
children: [
Slide(
hero: Image.asset("./assets/hero-1.png"),
title: "Boost your traffic",
subtitle:
"Outreach to many social networks to improve your statistics",
onNext: nextPage),
Slide(
hero: Image.asset("./assets/hero-2.png"),
title: "Give the best solution",
subtitle:
"We will give best solution for your business isues",
onNext: nextPage),
Slide(
hero: Image.asset("./assets/hero-3.png"),
title: "Reach the target",
subtitle:
"With our help, it will be easier to achieve your goals",
onNext: nextPage),
Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Text(
'Be kind to yourself',
style: kTitleStyle,
),
),
)
])),
),
);
}
void nextPage() {
pageController.nextPage(
duration: const Duration(milliseconds: 200), curve: Curves.ease);
}
}
class Slide extends StatelessWidget {
final Widget hero;
final String title;
final String subtitle;
final VoidCallback onNext;
const Slide({Key key, this.hero, this.title, this.subtitle, this.onNext})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: hero),
Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Text(
title,
style: kTitleStyle,
),
SizedBox(
height: 20,
),
Text(
subtitle,
style: kSubtitleStyle,
textAlign: TextAlign.center,
),
SizedBox(
height: 35,
),
],
),
),
GestureDetector(
onTap: onNext,
child: Text(
"Skip",
style: kSubtitleStyle,
),
),
SizedBox(
height: 4,
)
],
),
);
}
}
I don't need to do many things with TextEditingController but want to show the initial text. And I feel like creating StatefulWidget is too much for that.
Here's what I want my code looks like
// In StatelessWidget
TextField(
controller: TextEditingController(),
)
But every tutorials and blog posts I've seen use TextEditingController in StatefulWidget and dispose them in the dispose method. But I can't dispose them if I use like the above
If you want to use TextEditingController, there is no way around except to use a StatefulWidget if you want to avoid memory leaks.
However, if you see alot of boilerplate in this approach, you can use HookWidget (flutter_hooks) which gives you access to TextEditingController in a simple way and disposes it for you,here is a comparison:
using StatefulWidget:
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
TextEditingController controller;
FocusNode focusNode;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: 200,
height: 200,
color: Colors.red,
child: TextField(
focusNode: focusNode,
controller: controller,
),
),
),
);
}
#override
void initState() {
controller = TextEditingController();
focusNode = FocusNode();
super.initState();
}
#override
void dispose() {
controller.dispose();
focusNode.dispose();
super.dispose();
}
}
using HookWidget:
class Test extends HookWidget {
#override
Widget build(BuildContext context) {
final focusNode = useFocusNode();
final controller = useTextEditingController();
return Scaffold(
body: Center(
child: Container(
width: 200,
height: 200,
color: Colors.red,
child: TextField(
focusNode: focusNode,
controller: controller,
),
),
),
);
}
}