how to get a bool in a stateful widget to change a counter in it's parent stateful widget - flutter

I'm quite new to flutter and i'm struggling to get my head around passing variables up the widget tree. I've written a very simple code to demonstrate what i'm trying to achieve and I was hoping someone could please spell it out for me.
I have a parent Stateful widget with a counter in it:
class ParentWidget extends StatefulWidget {
const ParentWidget({Key? key}) : super(key: key);
#override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int Counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
SizedBox(
height: 100,
),
Button(),
],
),
),
);
}
}
then I have another Stateful Widget with the button and bool in it:
class Button extends StatefulWidget {
const Button({Key? key}) : super(key: key);
#override
State<Button> createState() => _ButtonState();
}
class _ButtonState extends State<Button> {
bool buttonPressed = false;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
buttonPressed = !buttonPressed;
print(buttonPressed);
});
},
child: Container(
color: kWhite,
height: 50,
width: 50,
),
);
}
}
I've looked at some of the other answers (using callbacks?) but am struggling to understand how it actually works and how I would implement it into my code
How do I pass the bool variable up the tree to change the counter?
thanks so much and any help would be greatly appreciated

Add the callback function in the Button widget that returns the state of the button pressed.
In Parent widget, add the argument for the callback function which returns the button pressed state.
class ParentWidget extends StatefulWidget {
const ParentWidget({Key? key}) : super(key: key);
#override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int Counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
const SizedBox(
height: 100,
),
Button(isPressed: (isPressed) => print(isPressed)), <-- updated
],
),
),
);
}
}
class Button extends StatefulWidget {
final Function(bool) isPressed; <-- updated
const Button({Key? key, required this.isPressed}) : super(key: key); <-- updated
#override
State<Button> createState() => _ButtonState();
}
class _ButtonState extends State<Button> {
bool buttonPressed = false;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
buttonPressed = !buttonPressed;
print(buttonPressed);
});
widget.isPressed(buttonPressed); <-- updated
},
child: Container(
color: Colors.white,
height: 50,
width: 50,
),
);
}
}

This is how to pass data to parent widget using a callback,
class ParentWidget extends StatefulWidget {
const ParentWidget({Key? key}) : super(key: key);
#override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int Counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
SizedBox(
height: 100,
),
Button(
// here you will get the bool
onBtnPressed: (val) {
print(val);
},
),
],
),
),
);
}
}
class Button extends StatefulWidget {
const Button({required this.onBtnPressed, Key? key}) : super(key: key);
// add this here, this function will act as the callback
final Function onBtnPressed;
#override
State<Button> createState() => _ButtonState();
}
class _ButtonState extends State<Button> {
bool buttonPressed = false;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
setState(() {
buttonPressed = !buttonPressed;
print(buttonPressed);
});
widget.onBtnPressed(buttonPressed);
},
child: Container(
color: kWhite,
height: 50,
width: 50,
),
);
}
}

Related

flutter - texteditingcontroller from another class

i am fairly new to flutter, can anyone help me? pls
I would like that once I click the RawMaterialButton(), what I wrote in the TextField() appears as text in the container() class.
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: chat(),
);
}
}
class chat extends StatefulWidget {
const chat({Key? key}) : super(key: key);
#override
_chatState createState() => _chatState();
}
class _chatState extends State<chat> {
bool changeClass = false;
changeClassValue() {
setState(() {
changeClass = !changeClass;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: changeClass
? container(
text: _textFieldState().textController.text,
)
: textField(
changeClassValue: changeClassValue,
),
);
}
}
class textField extends StatefulWidget {
textField({Key? key, required this.changeClassValue}) : super(key: key);
Function changeClassValue;
#override
_textFieldState createState() => _textFieldState();
}
class _textFieldState extends State<textField> {
final textController = TextEditingController();
#override
Widget build(BuildContext context) {
return Center(
child: Row(
children: [
Container(
width: 300.0,
height: 60.0,
color: Colors.red,
child: TextField(
controller: textController,
),
),
RawMaterialButton(
onPressed: () {
setState(() {
widget.changeClassValue();
print(textController.text);
});
},
child: Icon(Icons.send),
)
],
),
);
}
}
class container extends StatefulWidget {
container({Key? key, required this.text}) : super(key: key);
String text;
#override
_containerState createState() => _containerState();
}
class _containerState extends State<container> {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
width: double.infinity,
height: 60.0,
color: Colors.grey,
child: Text(widget.text),
),
);
}
}
hope someone can help me.
Thank you :) I write this piece because otherwise it won't let me upload itI write this piece because otherwise it won't let me upload itI write this piece because otherwise it won't let me upload it
You need to update the type of changeClassValue to ValueChanged<String> - now you can pass data between textField and chat states.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: chat(),
);
}
}
class chat extends StatefulWidget {
const chat({Key? key}) : super(key: key);
#override
_chatState createState() => _chatState();
}
class _chatState extends State<chat> {
bool changeClass = false;
String? text;
changeClassValue(String? newText) {
setState(() {
changeClass = !changeClass;
text = newText;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: changeClass
? container(
text: text ?? "",
)
: textField(
changeClassValue: changeClassValue,
),
);
}
}
class textField extends StatefulWidget {
textField({Key? key, required this.changeClassValue}) : super(key: key);
ValueChanged<String> changeClassValue;
#override
_textFieldState createState() => _textFieldState();
}
class _textFieldState extends State<textField> {
final textController = TextEditingController();
#override
Widget build(BuildContext context) {
return Center(
child: Row(
children: [
Container(
width: 300.0,
height: 60.0,
color: Colors.red,
child: TextField(
controller: textController,
),
),
RawMaterialButton(
onPressed: () {
widget.changeClassValue(textController.text);
},
child: Icon(Icons.send),
)
],
),
);
}
}
class container extends StatefulWidget {
container({Key? key, required this.text}) : super(key: key);
String text;
#override
_containerState createState() => _containerState();
}
class _containerState extends State<container> {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
width: double.infinity,
height: 60.0,
color: Colors.grey,
child: Text(widget.text),
),
);
}
}

flutter - change a variable from another class

I would like when I press on the RawMaterialButton, the textField () class changes to the container () class and appears on the screen,
with the code I have now when I press nothing happens ...
can anyone fix it? Thank you.
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: chat(),
);
}
}
class chat extends StatefulWidget {
const chat({Key? key}) : super(key: key);
#override
_chatState createState() => _chatState();
}
class _chatState extends State<chat> {
bool changeClass = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: changeClass ? container() : textField(changeClass: changeClass),
);
}
}
class textField extends StatefulWidget {
textField({Key? key, required this.changeClass}) : super(key: key);
bool changeClass = false;
#override
_textFieldState createState() => _textFieldState();
}
class _textFieldState extends State<textField> {
#override
Widget build(BuildContext context) {
return Center(
child: Row(
children: [
Container(
width: 300.0,
height: 60.0,
color: Colors.red,
),
RawMaterialButton(
onPressed: () {
setState(() {
widget.changeClass = true;
});
},
child: Icon(Icons.send),
)
],
),
);
}
}
class container extends StatefulWidget {
const container({Key? key}) : super(key: key);
#override
_containerState createState() => _containerState();
}
class _containerState extends State<container> {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
width: double.infinity,
height: 60.0,
color: Colors.grey,
),
);
}
}
hope someone can help me.
Thank you :)
I write this piece because otherwise it won't let me upload itI write this piece because otherwise it won't let me upload itI write this piece because otherwise it won't let me upload it
You are technically changing a local variable in the _textFieldState, so to solve the problem you have multiple options, one of them is to pass a function that change the state in the _chatState, this code would do so:
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: chat(),
);
}
}
class chat extends StatefulWidget {
const chat({Key? key}) : super(key: key);
#override
_chatState createState() => _chatState();
}
class _chatState extends State<chat> {
bool changeClass = false;
changeClassValue() {
setState(() {
changeClass = !changeClass;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: changeClass
? container()
: textField(changeClassValue: changeClassValue),
);
}
}
class textField extends StatefulWidget {
textField({Key? key, required this.changeClassValue}) : super(key: key);
Function changeClassValue;
#override
_textFieldState createState() => _textFieldState();
}
class _textFieldState extends State<textField> {
#override
Widget build(BuildContext context) {
return Center(
child: Row(
children: [
Container(
width: 300.0,
height: 60.0,
color: Colors.red,
),
RawMaterialButton(
onPressed: () {
setState(() {
widget.changeClassValue();
});
},
child: Icon(Icons.send),
)
],
),
);
}
}
class container extends StatefulWidget {
const container({Key? key}) : super(key: key);
#override
_containerState createState() => _containerState();
}
class _containerState extends State<container> {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
width: double.infinity,
height: 60.0,
color: Colors.grey,
),
);
}
}
where the output would look like:

change a variable from another class

i am quite a beginner with flutter. i hope someone can help me solve this problem...
I have this code, how can I make that when i press the RawMaterialButton of the textField() class, the changeClass variable of the chat() class changes from textField() to container() ?
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: chat(),
);
}
}
class chat extends StatefulWidget {
const chat({Key? key}) : super(key: key);
#override
_chatState createState() => _chatState();
}
class _chatState extends State<chat> {
var changeClass = textField();
#override
Widget build(BuildContext context) {
return Scaffold(
body: changeClass,
);
}
}
class textField extends StatefulWidget {
const textField({Key? key}) : super(key: key);
#override
_textFieldState createState() => _textFieldState();
}
class _textFieldState extends State<textField> {
#override
Widget build(BuildContext context) {
return Center(
child: Row(
children: [
Container(
width: 300.0,
height: 60.0,
color: Colors.red,
),
RawMaterialButton(
onPressed: () {
// on pressed change this row into container
},
child: Icon(Icons.send),
)
],
),
);
}
}
class container extends StatefulWidget {
const container({Key? key}) : super(key: key);
#override
_containerState createState() => _containerState();
}
class _containerState extends State<container> {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
width: double.infinity,
height: 60.0,
color: Colors.grey,
),
);
}
}
hope someone can help me
Thank you :)
Define a state variable changeClass in _chatState
In the build method check if the changeClass is true then return the container Widget otherwise return Row widget.
setState the changeClass = trueinonPressed`
_
import 'package:flutter/material.dart';
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: chat(),
);
}
}
class chat extends StatefulWidget {
const chat({Key? key}) : super(key: key);
#override
_chatState createState() => _chatState();
}
class _chatState extends State<chat> {
bool changeClass = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: changeClass
? container()
: textField(
changeClass: changeClass,
callback: () {
setState(() {
changeClass = true;
});
},
),
);
}
}
class textField extends StatefulWidget {
textField({Key? key, required this.changeClass, required this.callback})
: super(key: key);
bool changeClass = false;
VoidCallback callback;
#override
_textFieldState createState() => _textFieldState();
}
class _textFieldState extends State<textField> {
#override
Widget build(BuildContext context) {
return Center(
child: Row(
children: [
Flexible(
child: Container(
width: 300.0,
height: 60.0,
color: Colors.red,
),
),
RawMaterialButton(
onPressed: widget.callback,
child: Icon(Icons.send),
)
],
),
);
}
}
class container extends StatefulWidget {
const container({Key? key}) : super(key: key);
#override
_containerState createState() => _containerState();
}
class _containerState extends State<container> {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
width: double.infinity,
height: 60.0,
color: Colors.grey,
),
);
}
}

Invoking setState on child Stateful from parent Stateful widget

When I am invoking setState in child stateful widget. it is showing an error or warning. Is there any way to call Stateful widget inside Stateful widget without causing an error or any good way to do the same?
Here is my sample code :
parent.dart
class Parent extends StatefulWidget {
#override
_ParentState createState() => _ParentState();
}
class _ParentState extends State<Parent> {
var title = "Parent";
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: <Widget>[
Text(title),
Child(init:true), // <-- Calling Child Widget
],
),
),
);
}
}
child.dart
class Child extends StatefulWidget {
final bool init; // <- Showing warning on removing 'final'
// This class (or a class that this class inherits from) is marked as '#immutable', but one or more of its instance fields aren't final: Child.init
Child({
Key? key,
required this.init,
}) : super(key: key);
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
#override
Widget build(BuildContext context) {
return Container(
color: widget.init ? Colors.red : Colors.blue,
child: TextButton(
onPressed: () {
setState(
() {
// widget.init = false;
// want to change 'wiget.init' but its final
// removing final causing warning
},
);
},
child: Text("Click me"),
),
);
}
}
You can pass function that changes init variable.
class Parent extends StatefulWidget {
#override
_ParentState createState() => _ParentState();
}
class _ParentState extends State<Parent> {
var title = "Parent";
var init = true;
void setInitFalse(){
setState((){
init = false;
})
}
bool getInit(){
return init;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: <Widget>[
Text(title),
Child(init: getInit(), setInitFalse: setInitFalse()),
],
),
),
);
}
}
And then in child
class Child extends StatefulWidget {
final Function init; // <- Showing warning on removing 'final'
// This class (or a class that this class inherits from) is marked as '#immutable', but one or more of its instance fields aren't final: Child.init
final Function setInitFalse;
Child({
Key? key,
required this.init,
required this.setInitFalse
}) : super(key: key);
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
#override
Widget build(BuildContext context) {
return Container(
color: widget.init() ? Colors.red : Colors.blue,
child: TextButton(
onPressed: () {
widget.setInitFalse();
},
child: Text("Click me"),
),
);
}
}

statfulWidget with key concept

i am studying key in flutter. and in explanation, when i want swap widget in statefulWidget i need to add key value. because when flutter check element structure if type, state are not same they don't response. this is how i understand.
void main() => runApp(new MaterialApp(home: PositionedTiles()));
class PositionedTiles extends StatefulWidget {
#override
State<StatefulWidget> createState() => PositionedTilesState();
}
class PositionedTilesState extends State<PositionedTiles> {
List<Widget> tiles = [
StatefulColorfulTile(key: UniqueKey()), // Keys added here
StatefulColorfulTile(key: UniqueKey()),
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(children: tiles),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.sentiment_very_satisfied), onPressed: swapTiles),
);
}
swapTiles() {
setState(() {
tiles.insert(1, tiles.removeAt(0));
});
}
}
class StatefulColorfulTile extends StatefulWidget {
StatefulColorfulTile({Key key}) : super(key: key); // NEW CONSTRUCTOR
#override
ColorfulTileState createState() => ColorfulTileState();
}
class ColorfulTileState extends State<ColorfulTile> {
Color myColor;
#override
void initState() {
super.initState();
myColor = UniqueColorGenerator.getColor();
}
#override
Widget build(BuildContext context) {
return Container(
color: myColor,
child: Padding(
padding: EdgeInsets.all(70.0),
));
}
}
but i saw this code.
Widget build(BuildContext context) {
return Column(
children: [
value
? const SizedBox()
: const Placeholder(),
GestureDetector(
onTap: () {
setState(() {
value = !value;
});
},
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
!value
? const SizedBox()
: const Placeholder(),
],
);
}
this code is also use statefulWidget. in this code when user taps Box it's changed but i think there're no key value and in element structure there are different type(one is SizedBox and the other is placeHolder) so i think there aren't changed. why they're changed? what i misunderstand?