Event Listeners in flutter - flutter

Is there a way I can listen to a button click in flutter? I want to know if the button is clicked in another class that creates a object of that button.
What i want to do is let MyButtonRow know when MyButton is clicked, since it involves changing variables in MyButtonRow.
The functionality i am looking for is similar to .setEventListener in JavaScript
So here's the 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>[MyButtonTile()],));
}
}
class MyButtonTile extends StatefulWidget {
const MyButtonTile({Key? key}) : super(key: key);
#override
_MyButtonTileState createState() => _MyButtonTileState();
}
class _MyButtonTileState extends State<MyButtonTile> {
#override
Widget build(BuildContext context) {
return TextButton(onPressed: (){
//notify MyButtonRow about the click
}, child: Text("hello"));
}
}

Firstly you declare onTap function on your child widget and then just pass the onTap function from where you define the MyButtonTile
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>[MyButtonTile(onTap: (){
print("Notify me");
})],));
}
}
class MyButtonTile extends StatelessWidget {
final Function onTap;
MyButtonTile({this.onTap});
#override
Widget build(BuildContext context) {
return TextButton(onPressed:onTap,//notify MyButtonRow about the click
child: Text("hello"));
}
}

Related

how to give a choice for a parameter with an already created widget group(class)?

I have some some stless wrap widget:
class SomeWrap extends StatelessWidget {
// it's work, but i can put any widget, but I want only widget form class MyChoises
Widget MyValue
const SomeWrap({
required this.MyValue,
Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
// Here some settings for UI
// here my value as a widget
child: MyValue;
);
}
}
Here class MyChoises, that return couple widgets:
abstract class StatusTextOrder {
Text processing = Text('Processing',style: TextStyle(color:Colors.Yellow)));
Text delivered = Text('Delivered',style: TextStyle(color:Colors.Green)));
IconButton canceled = IconButton(icon: Text('Canceled', onPressed: ()=>{}))
}
What the correct way to use this "choices" for a value ?
usage:
SomeWrap(MyValue: StatusTextOrder.delivered)
Now into MyValue I can put any Widget, its not that im looking for.
I tried to use none abstract class, and put StatusTextOrder or Widget , but all of this gives me an errors.
Someone said that it will work :
import 'package:flutter/material.dart';
class StatusTextOrder {
static final processing =
Text('Processing', style: TextStyle(color: Colors.yellow));
static final delivered =
Text('Delivered', style: TextStyle(color: Colors.green));
static final canceled = IconButton(
onPressed: () {},
icon: Icon(
Icons.cancel,
color: Colors.red,
));
}
class Wrapper extends StatelessWidget {
StatusTextOrder widget;
Wrapper({Key? key, required this.widget}) : super(key: key);
#override
Widget build(BuildContext context) {
return Placeholder(
child: widget,
);
}
}
class ErrorPage extends StatelessWidget {
const ErrorPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(child:Row(
children: [
Wrapper(widget: StatusTextOrder.delivered),
],
)),
);
}
}
no, it gives errors:
The argument type 'StatusTextOrder' can't be assigned to the parameter type 'Widget?'.
The argument type 'Text' can't be assigned to the parameter type 'StatusTextOrder'.
As comment section included desire behavior, It can be
wrapper class,
//wrapper class
class SomeWrap extends StatelessWidget {
final StatusTextOrder statusTextOrder;
const SomeWrap({required this.statusTextOrder, Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return statusTextOrder;
}
}
//base class
abstract class StatusTextOrder extends Widget {
const StatusTextOrder({super.key});
}
/// concrete class
class Processing extends StatelessWidget implements StatusTextOrder {
const Processing({super.key});
#override
Widget build(BuildContext context) {
return const Text('processing');
}
}
And you need to use like
SomeWrap(statusTextOrder: Processing());
Also it can be
abstract class StatusTextOrder extends StatelessWidget {
const StatusTextOrder({super.key});
}
class Processing extends StatusTextOrder {
const Processing({super.key});
#override
Widget build(BuildContext context) {
return const Text('processing');
}
}
You can create another class with theses concrete Class as static variable and pass like old part.
old:
To use like StatusTextOrder.delivered, you need to make those variable as statics,
abstract class StatusTextOrder {
static Text processing = Text('Processing');
static Text delivered = Text('Delivered');
static IconButton canceled = IconButton(icon: Text('Canceled'), onPressed: () => {});
}
class SomeWrap extends StatelessWidget {
final Widget MyValue;
const SomeWrap({required this.MyValue, Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(child: MyValue);
}
}
You can find more about class-variables-and-methods

Calling a stateful widget from another stateful widget does not work as expected

Calling a statefulwidget from a button click of another widget does not do anything. What I am trying to do is execute a print statement just to see if the calling works
I have this ElevatedButton below which calls the Stateful Widget Contacts, I dont see any errors but I dont see the print statement printed out in the console.
ElevatedButton(
onPressed: () {
const Contacts(name: 'Jimmy');
},
child: const Text('Fetch API data'),
),
class Contacts extends StatefulWidget {
final String name;
const Contacts({Key? key, required this.name}) : super(key: key);
#override
_ContactsState createState() => _ContactsState();
}
class _ContactsState extends State<Contacts> {
#override
Widget build(BuildContext context) {
print('Test2');
return Center(child: Text(widget.name));
}
}
State objects will not be created unless added to the widget tree.
Maybe you could run the print statement in constructor? Try this way:
class Contacts extends StatefulWidget {
final String name;
const Contacts({Key? key, required this.name}) : super(key: key);
#override
_ContactsState createState() => _ContactsState();
}
class _ContactsState extends State<Contacts> {
_ContactsState () {
print('Test2');
}
#override
Widget build(BuildContext context) {
return Center(child: Text(widget.name));
}
}

Call Navigator from outside state or call child state method from parent

I ended up with a parent calling a child method, which is fine, but I can't call Navigator outside the state class. My goal is either to move the child method in it's state and somehow access it, or to call Navigator form outside the state in a Stateful widget.
What is the best approach to this problem?
import 'package:flutter/material.dart';
class ParentClass extends StatefulWidget {
const ParentClass({Key? key}) : super(key: key);
#override
_ParentClassState createState() => _ParentClassState();
}
class _ParentClassState extends State<ParentClass> {
ChildClass childclass = ChildClass();
#override
Widget build(BuildContext context) {
return Container(
child: ElevatedButton(
child: Text('Button'),
onPressed: () => {
childclass.callNavigator(),//or call callNavigatorState
}),
);
}
}
class ChildClass extends StatefulWidget {
const ChildClass({Key? key}) : super(key: key);
void callNavigator() {
//call navigator from here
}
#override
_ChildClassState createState() => _ChildClassState();
}
class _ChildClassState extends State<ChildClass> {
void callNavigatorState(){
//access from parent widget?
}
#override
Widget build(BuildContext context) {
return Container();
}
}
you can access a stateful's state, using Globalkey.currentState...
check this sample code:
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key}) : super(key: key);
final child = ChildWidget(key: GlobalKey());
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
child,
ElevatedButton(
onPressed: () {
(((child as ChildWidget).key as GlobalKey).currentState!
as _ChildWidgetState)
.someFunction();
},
child: Text("childWidget someFunction"))
],
),
);
}
}
class ChildWidget extends StatefulWidget {
const ChildWidget({Key? key}) : super(key: key);
#override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
void someFunction() {
print("childWidget someFunction");
}
#override
Widget build(BuildContext context) {
return Container();
}
}

Is there a way to access a field from the state of a StatefulWidget?

I have a field that changes in the state of a StatefulWidget but I want to access it in the widget itself.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Training();
}
}
class Training extends StatefulWidget {
const Training({Key? key}) : super(key: key);
String trainingToString(){
return('people selected: ' + //Here I would need to access the variable from _TrainingState);
}
#override
State<Training> createState() => _TrainingState();
}
class _TrainingState extends State<Training> {
int peopleSelected = 0;
void updatePeopleSelected(int peopleSelected){
setState((){
this.peopleSelected = peopleSelected;
}
}
#override
Widget build(BuildContext context) {
return Container();
}
}
So I have the field peopleSelected and a function to update it in _TrainingState and when I call Training.trainingToString() I want it to print this field but I can't access the field through Training.
Is there a way you can do it or what would be some alternatives?
you must to call this function you can use only for now
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){updatePeopleSelected()}
child: Container())
}

flutter child props is changing parent variable

I send a variable from a parent widget to its child. by parameters. I'm using that variable on the parent and child widget. for example, I'm using variable.name on the parent widget. When I change the variable on the child widget widget.variable.name = 'all' it's also updating the parent widget but I just wanna change that on the child widget.
You can make a temporary variable inside child state.
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int parentVal = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () {
setState(() {
parentVal++;
});
},
child: Text("parent val: $parentVal"),
),
ChildW(
childval: parentVal,
)
],
));
}
}
class ChildW extends StatefulWidget {
final int childval;
const ChildW({
Key? key,
required this.childval,
}) : super(key: key);
#override
State<ChildW> createState() => _ChildWState();
}
class _ChildWState extends State<ChildW> {
late int tempChildVal;
#override
void initState() {
super.initState();
tempChildVal = widget.childval;
}
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
setState(() {
tempChildVal++;
});
},
child: Text("child val: $tempChildVal"),
);
}
}