I have something like that, I tried so many ways and can't call the function like I want.
class PageTest extends StatefulWidget {
PageTest({Key? key}) : super(key: key);
#override
State<PageTest> createState() => PageTestState();
}
class PageTestState extends State<PageTest> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: topMyBar(),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [PageTestList()],
),
),
floatingActionButton: floatingButton(),
);
}
Widget floatingButton() {
return FloatingActionButton.extended(
onPressed: () {
CALL pageTestListFunction() AND SETSTATE ON _PageTestListState;
},
backgroundColor: AppColors.status_ready,
label: Text(
'OK',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
));
}
}
-- END HERE --
class PageTestList extends StatefulWidget {
const PageTestList({Key? key}) : super(key: key);
#override
State<PageTestList> createState() => _PageTestListState();
}
class _PageTestListState extends State<PageTestList> {...
Future<bool> pageTestListFunction() async {...}
}
Is there a way to call the function from PageTestList when onPressed on floatingActionButton is called and then setState on PageTestList?
Thank's!
Use a global key in your widget.
class PageTest extends StatefulWidget {
const PageTest({Key? key}) : super(key: key);
#override
State<PageTest> createState() => PageTestState();
}
class PageTestState extends State<PageTest> {
final _globalkey = GlobalKey<PageTestListState>();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: topMyBar(),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [PageTestList(key:_globalkey)],
),
),
floatingActionButton: floatingButton(),
);
}
Widget floatingButton() {
return FloatingActionButton.extended(
onPressed: () {
//CALL pageTestListFunction() AND SETSTATE ON _PageTestListState;
_globalkey.currentState?.pageTestListFunction();
},
backgroundColor: AppColors.status_ready,
label: const Text(
'OK',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
));
}
}
class PageTestList extends StatefulWidget {
const PageTestList({Key? key}) : super(key: key);
#override
State<PageTestList> createState() => PageTestListState();
}
class PageTestListState extends State<PageTestList> {
var color = Colors.red;
void pageTestListFunction() async {
setState(() {
color = Colors.green;
});
}
#override
Widget build(BuildContext context) {
return Container(
color: color,
width: 100,
height: 100,
);
}
}
Related
I was trying to code a TikTakToe game in FLutter but failed at the point where I tried to make a button which resets the fields.
class TikTakToe extends StatefulWidget {
const TikTakToe({Key? key}) : super(key: key);
#override
State<TikTakToe> createState() => _TikTakToeState();
}
class _TikTakToeState extends State<TikTakToe> {
int currentindex = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.teal[100],
appBar: AppBar(
title: const Text("Tik Tak Toe"),
backgroundColor: Colors.teal[400],
),
...
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
ElevatedButton(
onPressed: () {
setState(() {
gameOver = true;
});
}, child: const Icon(Icons.refresh))
],
),
],
),
),
),
);
}
}
bool gameOver = false;
class Field extends StatefulWidget {
const Field({Key? key, required this.fieldnumber}) : super(key: key);
final int fieldnumber;
#override
State<Field> createState() => _FieldState();
}
class _FieldState extends State<Field> {
String playersign = "";
#override
Widget build(BuildContext context) {
return TextButton(
child: Text(
gameOver ? "" : signlist[widget.fieldnumber],
style: const TextStyle(fontSize: 60),
),
style: TextButton.styleFrom(
shape: const RoundedRectangleBorder(
side: BorderSide(color: Color.fromARGB(255, 88, 221, 208), width: 2),
borderRadius: BorderRadius.all(Radius.zero),
),
enableFeedback: false,
primary: Colors.amber[800],
fixedSize: const Size(120.0, 120.0),
backgroundColor: Colors.white,
),
onPressed: () {
setState(() {
... Winner evaluation
}
}
}
);
},
);
}
}
Now I have the problem that the buttons (Fields) are actually resetting but only after clicking on them and not instant after clicking the reset button In the TikTakToe class.
The only thing that worked was adding
(context as Element).reassamble(); to the onPressed of the Elevated button
setState(() {
gameOver = true;
(context as Element).reassemble();
});
but I got this warning:
The member 'reassemble' can only be used within instance members of subclasses of 'package:flutter/src/widgets/framework.dart'.
Thanks!
Change gameover variable place into _FieldState class.
class Field extends StatefulWidget {
const Field({Key? key, required this.fieldnumber}) : super(key: key);
final int fieldnumber;
#override
State<Field> createState() => _FieldState();
}
class _FieldState extends State<Field> {
String playersign = "";
bool gameover = false;
#override
Widget build(BuildContext context) {
return TextButton(
child: Text(
gameover ? "" : signlist[widget.fieldnumber],
style: const TextStyle(fontSize: 60),
),: const TextStyle(fontSize: 60),
),
You need to put gameOver variable inside of Field widget and dont forget to use camelCase in naming variables, on the other hand you have to pass onPressed to TextButton if you dont want to be clickable just pass onPressed: null
class Field extends StatefulWidget {
const Field({Key key}) : super(key: key);
#override
State<Field> createState() => _FieldState();
}
class _FieldState extends State<Field> {
String playerSign = "";
bool gameOver = false; // put var inside
#override
Widget build(BuildContext context) {
return Column(
children: [
TextButton(
onPressed: null,
child: Text(
gameOver ? "" : signlist[widget.fieldnumber],
style: const TextStyle(fontSize: 60),
),
),
TextButton(
onPressed: () {
setState(() {
setState(() {
gameOver = true;
});
});
},
child: const Text(
"reset",
style: TextStyle(fontSize: 60),
),
),
],
);
}
}
suggest to read this doc
I'm new to Flutter and I just want to understand something about stateful widget. Here's a simple code that works perfectly just by switching the text color from red to blue when clicking on a button :
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Color myColor = Colors.red;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("My app")),
body: Column(
children: [
Text(
"Just a simple text",
style: TextStyle(color: myColor),
),
FloatingActionButton(
onPressed: () {
setState(() {
myColor =
(myColor == Colors.red) ? Colors.blue : Colors.red;
});
print(myColor);
},
child: Icon(Icons.home)),
],
));
}
}
My question is : if I get the column outside the stateful widget and call it as a component, how and where should I rewrite the setState function ? I begin with this code and I don't know how to continue :
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Color myColor = Colors.red;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("My app")),
body: HomePage());
}
}
Column HomePage()
{
return Column(
children: [
Text(
"Just a simple text",
style: TextStyle(color: myColor), // SHOULD I NOW INJECT myColor AS A PARAMETER OF HomePage ?
),
FloatingActionButton(
onPressed: () {print("WHERE TO PUT THE setState FUNCTION NOW ???")},
child: Icon(Icons.home)),
],
);
}
Your HomePage() is just a function that returns a Column, so you can just include it within the _MyWidgetState class to be able to access the state directly, and call the setState method, like that:
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Color myColor = Colors.red;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("My app")),
body: HomePage());
}
Column HomePage(){
return Column(
children: [
Text(
"Just a simple text",
style: TextStyle(color: myColor), // SHOULD I NOW INJECT myColor AS A PARAMETER OF HomePage ?
),
FloatingActionButton(
onPressed: () {
setState(() {
myColor = Colors.amber;
});
},
child: Icon(Icons.home)),
],
);
}
}
Here's a example class for how to pass data from one class to another class
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'main1.dart';
void main() {
runApp(MaterialApp(
home: Modalbtn(),
));
}
class Modalbtn extends StatefulWidget {
#override
_ModalbtnState createState() => _ModalbtnState();
}
class _ModalbtnState extends State<Modalbtn> {
String value = "0";
// Pass this method to the child page.
void _update(String newValue) {
setState(() => value = newValue);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children: [StatefulModalbtn(update: _update)],
),
);
});
},
icon: Icon(Icons.add),
iconSize: 20,
),
Text(
value,
style: TextStyle(fontSize: 40),
),
],
),
),
);
}
}
import 'package:flutter/material.dart';
class StatefulModalbtn extends StatelessWidget {
final ValueChanged<String> update;
StatefulModalbtn({required this.update});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => update("100"), // Passing value to the parent widget.
child: Text('Update (in child)'),
);
}
}
If you insist of having the HomePage() function outside the class you could do this for example:
class MyWidget extends StatefulWidget {
MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Color myColor = Colors.red;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("My app")),
body: HomePage(myColor, changeColor));
}
void changeColor(Color color) {
setState((){
myColor = color;
});
}
}
Column HomePage(Color color, ValueSetter<Color> change)
{
return Column(
children: [
Text(
"Just a simple text",
style: TextStyle(color: color),
),
FloatingActionButton(
onPressed: () { change(Colors.blue);},
child: Icon(Icons.home)),
],
);
}
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),
),
);
}
}
I have this class called VarianKemasan which has a function called totalBelanjaKemasan
class VarianKemasan extends StatefulWidget {
final productDetail;
const VarianKemasan({Key? key, this.productDetail}) : super(key: key);
#override
_VarianKemasanState createState() => _VarianKemasanState();
}
class _VarianKemasanState extends State<VarianKemasan> {
totalBelanjaKemasan() {
Text(
"${GlobalFunctions().rupiah(widget.productDetail['price'] * _parseCounter())}");
}
and wanna call the value that function has into a Text widget in another class
class ProductDetailPage extends StatefulWidget {
final productDetail;
const ProductDetailPage({Key? key, this.productDetail}) : super(key: key);
#override
_ProductDetailPageState createState() => _ProductDetailPageState();
}
class _ProductDetailPageState extends State<ProductDetailPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFFFFFFF),
body: Container(
child: Text(
"called value here",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Color(0xff31708F)),
)
how can I do that?
Try below code hope its help to you. refer my answer here and here also for that used widget.productDetail
your VarianKemasan Class:
class VarianKemasan extends StatefulWidget {
final product = 'Product Data';
#override
_VarianKemasanState createState() => _VarianKemasanState();
}
class _VarianKemasanState extends State<VarianKemasan> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("App Bar"),
),
body: Center(
child: Container(
child: TextButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
productDetail: widget.product,
),
),
),
child: Text(
'Ok',
),
),
),
),
);
}
}
Your ProductDetailPage class
class ProductDetailPage extends StatefulWidget {
final productDetail;
ProductDetailPage({
Key? key,
required this.productDetail,
}) : super(
key: key,
);
#override
_ProductDetailPageState createState() => _ProductDetailPageState();
}
class _ProductDetailPageState extends State<ProductDetailPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("App Bar"),
),
body: Center(
child: Container(
child: Text(
widget.productDetail,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Color(0xff31708F)),
),
),
),
);
}
}
I am trying to run method doAnimation from another widget by clicking on a FloatingActionButton.
Please tell me how to do this with this simple example. I know how to do this using the Provider package, but the code is cumbersome. How can I do this using Flutter's native methods?
Or, most likely, it can be done nicely with the Provider, but I don't know how.
A similar question has already been asked, but the second version of flutter and dart has already been released.
State management difficulties are probably the biggest newbies problem.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: MyAnimation(),
floatingActionButton: FloatingActionButton(
onPressed: () {
//TODO! error is here
_MyAnimationState().doAnimation();
//MyAnimation().createState().doAnimation(); // ?
},
child: Icon(Icons.play_arrow),
),
);
}
}
class MyAnimation extends StatefulWidget {
const MyAnimation({Key? key}) : super(key: key);
#override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height = 250;
bool _isOpen = true;
void doAnimation() {
_isOpen = !_isOpen;
setState(() {
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
doAnimation(); // works as it should
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}
This error occurs when I try to use the class methods in the usual way.
This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.
This is actually quite simple and doesn't require any kind of package. You can do this with the help of global keys. First create a global key like this GlobalKey<_MyAnimationState> _key = GlobalKey<_MyAnimationState>();. Then pass this key while using MyAnimation class like this MyAnimation(key: _key). Now use this key in the onPressed function to call the doAnimation method like this _key.currentState!.doAnimation();
Here is the complete implementation.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey<_MyAnimationState> _key = GlobalKey<_MyAnimationState>(); // declaration of the key
#override
Widget build(BuildContext context) {
return Scaffold(
body: MyAnimation(key: _key), // passing the key
floatingActionButton: FloatingActionButton(
onPressed: () {
_key.currentState!.doAnimation(); // calling the method from child widget
},
child: Icon(Icons.play_arrow),
),
);
}
}
class MyAnimation extends StatefulWidget {
const MyAnimation({Key? key}) : super(key: key);
#override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height = 250;
bool _isOpen = true;
void doAnimation() {
_isOpen = !_isOpen;
setState(() {
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
doAnimation(); // works as it should
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}
You can try to write the "doAnimation()" in the initState() instead the use of the floatingActionButton in order to trigger this action when the widget be initialized.
double _height;
bool _isOpen;
#override
void initState() {
super.initState();
bool _isOpen = true;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
}
Then use the ElevatedButton as the setter of the bool and setState to re-rendered the widgets:
ElevatedButton(
onPressed: () {
setState(() {
_isOpen = !_isOpen;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
Your code will look like this:
class MyAnimation extends StatefulWidget {
#override
_MyAnimationState createState() => _MyAnimationState();
}
class _MyAnimationState extends State<MyAnimation> {
double _height;
bool _isOpen;
#override
void initState() {
super.initState();
bool _isOpen = true;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: AnimatedContainer(
padding: EdgeInsets.all(20),
duration: Duration(milliseconds: 250),
width: 250,
height: _height,
color: Colors.lightBlueAccent,
child: Center(
child: Text(
'My Test String',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
),
),
),
ElevatedButton(
onPressed: () {
setState(() {
_isOpen = !_isOpen;
if (_isOpen) {
_height = 250;
} else {
_height = 0;
}
});
},
child: (_isOpen)? Text('Close Widget') : Text('Open Widget'))
],
);
}
}
You can also use the Provider to set the _isOpen value with setter function and avoid all these validations on the widget buttons.