I need to realise row of TextField widgets. I did it. But now I want to get actual value TextEditingController from State my TextField. How I can do this?
Its my Stateful widget:
class _UnRecognition extends StatefulWidget {
final String text;
const _UnRecognition({Key? key, required this.text}) : super(key: key);
#override
State<StatefulWidget> createState() => _UnRecognitionState();
}
class _UnRecognitionState extends State<_UnRecognition> {
final TextEditingController editWordController = TextEditingController();
#override
void initState() {
editWordController.text = widget.text;
super.initState();
}
#override
Widget build(BuildContext context) {
return IntrinsicWidth(
child: TextField(
controller: editWordController,
),
);
}
Its, where i want to use my variable:
void _SomeMethodOutsideWidget() {
for (var obj in ListOfWidget) {
if (obj is _UnRecognition) {
**this I get access obj.editWordController.text**
}
}
}
you need to learn the providers: https://pub.dev/packages/provider
basically it is used to retrieve values in the contexts of Statefull Widgets
you can find many tutorial of state managment provider on youtube
Related
In flutter,
How can a parent widget know if a child among many children widgets has received focus? For example, Can we know if a child in a Row widget's children has received focus?
Can I detect this focus before the child widget receives it?
It actually depends on your take and which architecture you wanna follow.
This snippet that I'm posting uses NotificationListener, a custom notification and a custom child widget. This might work for an application like a print or a callback, but you might need to change the architecture and use a state management tool to achieve greater things.
Parent Widget class:
class MyParentWidget extends StatelessWidget {
const MyParentWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return NotificationListener<FocusNotification>(
onNotification: (notification) {
print("New widget focused: ${notification.childKey.toString()}");
return true;
},
child: Row(
children: List.generate(
5,
(index) => MyChildWidget(
Key('widget-$index'),
),
),
),
);
}
}
Child Widget class:
class MyChildWidget extends StatefulWidget {
const MyChildWidget(Key key) : super(key: key);
#override
_MyChildWidgetState createState() => _MyChildWidgetState();
}
class _MyChildWidgetState extends State<MyChildWidget> {
final node = FocusNode();
#override
initState() {
node.addListener(() {
if (node.hasFocus) {
final notification = FocusNotification(widget.key!);
notification.dispatch(context);
}
});
super.initState();
}
#override
dispose() {
node.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return TextField(
focusNode: node,
);
}
}
Custom Notification class:
class FocusNotification extends Notification {
const FocusNotification(this.childKey);
final Key childKey;
}
I want to change the value of the text field in MyButton, such that, each time the button is clicked, the value is changed. I have set the value as a attribute in MyButton and passed a function from MyButtonRow to MyButton that will be executed everytime it is clicked. In that function, I want to change the attribute "myString" of MyButton, so it will automatically update the text field.
Code:
class MyButtonRow extends StatefulWidget {
const MyButtonRow({Key? key}) : super(key: key);
#override
_MyButtonRowState createState() => _MyButtonRowState();
}
class _MyButtonRowState extends State<MyButtonRow> {
#override
Widget build(BuildContext context) {
return Container(width: MediaQuery.of(context).size.width,
child: Row(children: <Widget>[MyButton(onTap: (){
print("Notify me");
//I want to change the myText attribute of MyButton here
}, myText: "Hello",)],));
}
}
class MyButton extends StatefulWidget {
final Function onTap;
final String myText;
const MyButton({Key? key, required this.onTap, required this.myText}) : super(key: key);
#override
_MyButtonState createState() => _MyButtonState();
}
class _MyButtonState extends State<MyButton> {
var onTap;
var myString;
#override
void initState() {
onTap = widget.onTap;
myString = widget.myText;
super.initState();
}
#override
Widget build(BuildContext context) {
return TextButton(onPressed:onTap,
child: Text(myString));
}
}
**EDIT**
Both the answers, by #Yeasin Sheikh and #Jav T were correct.
But this brought me to another question, "Is there a way i can access that attribute of MyButton in MyButtonRow"
Issue is that you are passing the newValue as a constructor parameter and assigning it to a local variable which is retained in state. Whenever a rebuild is called, the initState function is never called again, just the first time, I would recommend that instead of using:
#override
Widget build(BuildContext context) {
return TextButton(onPressed:onTap,
child: Text(myString));
}
You go ahead and use:
#override
Widget build(BuildContext context) {
return TextButton(onPressed:onTap,
child: Text(widget.myText));
}
In this case, the value will be updated whenever the parent rebuilds your widget. Make sense?
However, you cannot change the attributes of a widget after it is built - How to access/change an attribute of a Widget in Flutter
You can create a method or assign method like inside _MyButtonState's build
onPressed: () {
onTap();
setState(() {
myString = "newValue";
});
},
To use MyButton's myText that is coming though constructor, use widget.myText as #Jav T descried.
It is not necessary to make this StatefulWidget in this case, you can simply use StatelessWidget for MyButton.
class MyButton extends StatelessWidget {
final Function onTap;
final String myText;
const MyButton({
Key? key,
required this.onTap,
required this.myText,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: () => onTap(),
child: Text(myText),
);
}
}
I am designing a custom textfield
class MyTextField extends StatefulWidget {
final String labelText;
final TextEditingController textEditingController;
String get text {
// Expected compilation error: "Undefined name '_textEditingController'"
return _textEditingController.text;
}
MyTextField({
Key key,
this.labelText,
this.textEditingController,
.....
.....
}) : super(key: key);
}
class _MyTextFieldState extends State<MyTextField> {
TextEditingController _textEditingController = TextEditingController();
#override
void initState() {
super.initState();
_textEditingController = widget.editingController ?? TextEditingController();
}
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
controller: _textEditingController,
....,
....,
),
)
}
}
I am getting a compilation error Undefined name '_textEditingController' and it is expected as _textEditingController is defined in different class.
Now my question is how I can access _textEditingController property there?
Hope from the above code snippets helps you to understand what I am trying to achieve.
I think this should do what you want. Declare the Controller in the Widget, since you can still access Widget members from State. Just make sure to check if _textEdittingController has a value before using it in your getter.
class MyTextField extends StatefulWidget {
TextEditingController _textEditingController = TextEditingController();
final String labelText;
String get title {
// Error area
return _textEditingController.text;
}
MyTextField({
Key key,
this.labelText,
}) : super(key: key);
_MyTextFieldState createState() => _MyTextFieldState();
}
class _MyTextFieldState extends State<MyTextField> {
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
controller: widget._textEditingController,
),
);
}
}
It should be other way around. Not from state to widget, the data flow should be from widget to state. So declare the below code inside MyTextField widget.
TextEditingController _textEditingController = TextEditingController();
Then you can access the _textEditingController from the state class like below:
widget._textEditingController
I have problems understanding how to pass input information from a extended child widget back to its parent widget. I tried to create a setter in the parent widget but i can not call it through the "ParentWidget.of(context).setterName".
What is the best way to pass the user input information from a child widget back to a parent?
Thanks for your help
class SignInMobilePortrait extends StatefulWidget {
#override
_SignInMobilePortraitState createState() => _SignInMobilePortraitState();
}
class _SignInMobilePortraitState extends State<SignInMobilePortrait> {
//text field state
String _email = '';
set email(String value) => setState(() => _email = value);
...
LoginCredentials(),
...
}
class LoginCredentials extends StatelessWidget {
LoginCredentials({
Key key,
}) : super(key: key);
Widget build(BuildContext context) {
return Container(
...
onChanged: (value) {
//CHANGE EMAIL VALUE HERE;
},
...
}
A correct way to do this is to pass TextEditingController from SignInMobilePortrait down to LoginCredentials:
class _SignInMobilePortraitState extends State<SignInMobilePortrait> {
final _emailController = TextEditingController();
LoginCredentials(_emailController),
...
// Access _emailController.text somewhere
}
class LoginCredentials extends StatelessWidget {
final TextEditingController controller;
LoginCredentials({
Key key,
#required this.controller,
}) : super(key: key);
Widget build(BuildContext context) {
return TextField(
...
controller: controller,
}
I'm wondering what the recommended way of passing data to a stateful widget, while creating it, is.
The two styles I've seen are:
class ServerInfo extends StatefulWidget {
Server _server;
ServerInfo(Server server) {
this._server = server;
}
#override
State<StatefulWidget> createState() => new _ServerInfoState(_server);
}
class _ServerInfoState extends State<ServerInfo> {
Server _server;
_ServerInfoState(Server server) {
this._server = server;
}
}
This method keeps a value both in ServerInfo and _ServerInfoState, which seems a bit wasteful.
The other method is to use widget._server:
class ServerInfo extends StatefulWidget {
Server _server;
ServerInfo(Server server) {
this._server = server;
}
#override
State<StatefulWidget> createState() => new _ServerInfoState();
}
class _ServerInfoState extends State<ServerInfo> {
#override
Widget build(BuildContext context) {
widget._server = "10"; // Do something we the server value
return null;
}
}
This seems a bit backwards as the state is no longer stored in _ServerInfoSate but instead in the widget.
Is there a best practice for this?
Don't pass parameters to State using it's constructor.
You should only access the parameters using this.widget.myField.
Not only editing the constructor requires a lot of manual work ; it doesn't bring anything. There's no reason to duplicate all the fields of Widget.
EDIT :
Here's an example:
class ServerIpText extends StatefulWidget {
final String serverIP;
const ServerIpText ({ Key? key, this.serverIP }): super(key: key);
#override
_ServerIpTextState createState() => _ServerIpTextState();
}
class _ServerIpTextState extends State<ServerIpText> {
#override
Widget build(BuildContext context) {
return Text(widget.serverIP);
}
}
class AnotherClass extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: ServerIpText(serverIP: "127.0.0.1")
);
}
}
Best way is don't pass parameters to State class using it's constructor. You can easily access in State class using widget.myField.
For Example
class UserData extends StatefulWidget {
final String clientName;
final int clientID;
const UserData(this.clientName,this.clientID);
#override
UserDataState createState() => UserDataState();
}
class UserDataState extends State<UserData> {
#override
Widget build(BuildContext context) {
// Here you direct access using widget
return Text(widget.clientName);
}
}
Pass your data when you Navigate screen :
Navigator.of(context).push(MaterialPageRoute(builder: (context) => UserData("WonderClientName",132)));
Another answer, building on #RémiRousselet's anwser and for #user6638204's question, if you want to pass initial values and still be able to update them in the state later:
class MyStateful extends StatefulWidget {
final String foo;
const MyStateful({Key key, this.foo}): super(key: key);
#override
_MyStatefulState createState() => _MyStatefulState(foo: this.foo);
}
class _MyStatefulState extends State<MyStateful> {
String foo;
_MyStatefulState({this.foo});
#override
Widget build(BuildContext context) {
return Text(foo);
}
}
For passing initial values (without passing anything to the constructor)
class MyStateful extends StatefulWidget {
final String foo;
const MyStateful({Key key, this.foo}): super(key: key);
#override
_MyStatefulState createState() => _MyStatefulState();
}
class _MyStatefulState extends State<MyStateful> {
#override
void initState(){
super.initState();
// you can use this.widget.foo here
}
#override
Widget build(BuildContext context) {
return Text(foo);
}
}
Flutter's stateful widgets API is kinda awkward: storing data in Widget in order to access it in build() method which resides in State object 🤦 If you don't want to use some of bigger state management options (Provider, BLoC), use flutter_hooks (https://pub.dev/packages/flutter_hooks) - it is a nicer and cleaner substitute for SatefullWidgets:
class Counter extends HookWidget {
final int _initialCount;
Counter(this._initialCount = 0);
#override
Widget build(BuildContext context) {
final counter = useState(_initialCount);
return GestureDetector(
// automatically triggers a rebuild of Counter widget
onTap: () => counter.value++,
child: Text(counter.value.toString()),
);
}
}
#Rémi Rousselet, #Sanjayrajsinh, #Daksh Shah is also better. but I am also defined this is in from starting point.that which parameter is which value
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
String name = "Flutter Demo";
String description = "This is Demo Application";
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainActivity(
appName: name,
appDescription: description,
),
);
}
}
class MainActivity extends StatefulWidget {
MainActivity({Key key, this.appName, this.appDescription}) : super(key: key);
var appName;
var appDescription;
#override
_MainActivityState createState() => _MainActivityState();
}
class _MainActivityState extends State<MainActivity> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.appName),
),
body: Scaffold(
body: Center(
child: Text(widget.appDescription),
),
),
);
}
}
The best practice is to define the stateful widget class as immutable which means defining all dependencies (arrival parameter) as final parameters. and getting access to them by widget.<fieldName> in the state class. In case you want to change their values like reassigning you should define the same typed properties in your state class and re-assign them in the initState function. it is highly recommended not to define any not-final property in your stateful widget class and make it a mutable class. something like this pattern:
class SomePage extends StatefulWidget{
final String? value;
SomePage({this.value});
#override
State<SomePage> createState() => _SomePageState();
}
class _SomePageState extends State<SomePage> {
String? _value;
#override
void initState(){
super.initState();
setState(() {
_value = widget.value;
});
}
#override
Widget build(BuildContext context) {
return Text(_value);
}
}
To pass data to stateful widget, first of all, create two pages. Now from the first page open the second page and pass the data.
class PageTwo extends StatefulWidget {
final String title;
final String name;
PageTwo ({ this.title, this.name });
#override
PageTwoState createState() => PageTwoState();
}
class PageTwoStateState extends State<PageTwo> {
#override
Widget build(BuildContext context) {
return Text(
widget.title,
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w700),
),
}
}
class PageOne extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialButton(
text: "Open PageTwo",
onPressed: () {
var destination = ServicePage(
title: '<Page Title>',
provider: '<Page Name>',
);
Navigator.push(context,
MaterialPageRoute(builder: (context) => destination));
},);
}
}