Stateless widget to stateful widget ( using Create state) - flutter

[error][1]
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
var questionIndex = 0;
void answerQuestion() {
setState(() {
questionIndex = questionIndex + 1;
});
print(questionIndex);
}
#override
Widget build(BuildContext context) {
var question = [
'what\'s your favorite colour?',
'what\'s your favorite sports?',
];
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My app'),
),
body: Column(
children: [
Text(question[questionIndex]),
RaisedButton(
child: Text('answer1'),
onPressed: () => print('answer2'),
),
RaisedButton(
child: Text('answer2'),
onPressed: () => print('answer2'),
),
RaisedButton(
child: Text('answer3'),
onPressed: () {
print('answer3');
}),
],
),
),
);
}
}
error
I'm on going course in Udemy in that they got the output for the same code but for me it showing error like this **
** Exception caught by widgets library
** MyAppState#f6d27(lifecycle state: created, no widget, not mounted)**
[1]: https://i.stack.imgur.com/NFGhN.jpg

You need to create a private class.
class FilmList extends StatefulWidget {
const FilmList({Key? key}) : super(key: key);
#override
_FilmListState createState() => _FilmListState();//need to add
}
class _FilmListState extends State<FilmList> {
MovieQuery query = MovieQuery.year;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
child:Container(),
);}
}

Related

How to Maintain State of Drawer's Child Widget

I have a stateful widget, Counter, with a button and a counter that keeps track of how many times the button was pressed. This widget is in the drawer. When I close and open the drawer again, the counter is reset. How do I make it so that the counter is not reset upon closing and opening the drawer?
Here is the 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 MaterialApp(
home: Scaffold(
drawer: Drawer(
child: Counter(),
),
appBar: AppBar(),
body: Container(),
),
);
}
}
class Counter extends StatefulWidget {
const Counter({super.key});
#override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
#override
Widget build(BuildContext context) {
return Column(
children: [
Text(_count.toString()),
ElevatedButton(
onPressed: () {
setState(() {
_count = _count + 1;
});
},
child: Text('Increment Counter'),
)
],
);
}
}
To keep state of a variable within the Drawer(), the real solution would be to use a State Management library.
However, what you can do is create a global variable and pass it down the tree to Drawer():
import 'package:flutter/material.dart';
void main() {
runApp( MyApp());
}
class MyApp extends StatelessWidget {
var counter = 0;
MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
drawer: Drawer(
child: Counter(counter: counter,),
),
appBar: AppBar(),
body: Container(),
),
);
}
}
class Counter extends StatefulWidget {
int counter;
Counter({required this.counter,super.key});
#override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
#override
Widget build(BuildContext context) {
return Column(
children: [
Text(widget.counter.toString()),
ElevatedButton(
onPressed: () {
setState(() {
widget.counter = widget.counter + 1;
});
},
child: Text('Increment Counter'),
)
],
);
}
}

Flutter : setState outside

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)),
],
);
}

How to Refresh State from Navigator Pop in Flutter

I want to refresh the state when calling Navigator Pop / Navigator Pop Until.
While I was doing some research, I finally found this article Flutter: Refresh on Navigator pop or go back. From the code in the article, it can work fine.
But there is a problem when I use the widget tree, for example like the code below:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
Home Page - Parent Class
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
Button Widget - Widget Class
class ButtonWidget extends StatelessWidget{
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage())).then(onGoBack);
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
SecondPage
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}
Or is there another solution to refresh the state class when calling Navigator Pop / Navigator Pop Until?
re-write your Button's class like this:
class ButtonWidget extends StatelessWidget{
final Function onGoBack;
ButtonWidget({this.onGoBack})
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage())).then(onGoBack);
//to avoid any np exception you can do this: .then(onGoBack ?? () => {})
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
And add the onGoBack function as a parameter from the home page like this:
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(onGoBack: onGoBack),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
you must sent function on widget
class ButtonWidget extends StatelessWidget{
final Function(dynamic)? refresh;
const ButtonWidget({this.refresh})
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: ()async {
await Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage()));
if(refresh!=null){
refresh!("your params");
}
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
and you can use widget
ButtonWidget(
refresh:onGoBack
)
Try this, it just you are calling method out of scope
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(
refresh: onGoBack,
)
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
class ButtonWidget extends StatelessWidget {
final Function(dynamic)? refresh;
ButtonWidget({Key? key, this.refresh}) : super(key: key);
#override
Widget build(BuildContext context) {
print(refresh);
return RaisedButton(onPressed: () async {
await Navigator.push(
context, MaterialPageRoute(builder: (context) => SecondPage()))
.then((value) => refresh!("okay"));
});
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}

Flutter - How to trigger an animation inside a child widget from its parent widget [duplicate]

Let said I have a widget "mySonWidget" inside this widget I have a function "updateIconColor", I want to call that function from the father of "mySonWidget"
I did something similiar with callback but this is not the same scenario.
I saw people other widgets doing similar thing with controllers, but I don't know how create a custom controller.
How can I do it?
HELP
class mySonWidget extends StatefulWidget {
#override
_mySonWidgetState createState() => _mySonWidgetState();
}
class _mySonWidgetState extends State<mySonWidget> {
var _iconColor = Colors.red[500];
void updateIconColor() {
setState(() {
print('updateIconColor was called');
_iconColor = Colors.green;
});
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (Icon(Icons.star)),
color: _iconColor,
onPressed: () {},
),
);
}
}
father example:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(children: <Widget>[
mySonWidget(),
FlatButton(
onPressed: () {
/*..Call Function inside mySonWidget (updateIconColor) ..*/
},
child: Text(
"Change Color",
),
),
]),
),
);
}
}
You can copy paste run full code below
You can use GlobalKey can use _key.currentState to call updateIconColor()
code snippet
GlobalKey _key = GlobalKey();
...
mySonWidget(key: _key),
FlatButton(
onPressed: () {
final _mySonWidgetState _state = _key.currentState;
_state.updateIconColor();
},
...
class mySonWidget extends StatefulWidget {
mySonWidget({Key key}) : super(key: key);
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
GlobalKey _key = GlobalKey();
#override
Widget build(BuildContext context) {
return MaterialApp(
//theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
body: Column(children: <Widget>[
mySonWidget(key: _key),
FlatButton(
onPressed: () {
final _mySonWidgetState _state = _key.currentState;
_state.updateIconColor();
},
child: Text(
"Change Color",
),
),
]),
),
),
);
}
}
class mySonWidget extends StatefulWidget {
mySonWidget({Key key}) : super(key: key);
#override
_mySonWidgetState createState() => _mySonWidgetState();
}
class _mySonWidgetState extends State<mySonWidget> {
var _iconColor = Colors.red[500];
void updateIconColor() {
setState(() {
print('updateIconColor was called');
_iconColor = Colors.green;
});
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (Icon(Icons.star)),
color: _iconColor,
onPressed: () {},
),
);
}
}

Flutter: Widget State: Is this code safe?

The code below is an example to illustrate this question. The code below works, however the following line:
class WidgetCustom extends StatefulWidget {
has "WidgetCustom" underlined in green in vsCode, and when the cursor is positioned over it, it shows the message:
"This class (or a class this class inherits from) is marked as #immutable, but one or more of its instance fields are not final".
The code works fine.
Is it safe to use this code?
Is there a way to achieve this without the warning?
import 'package:flutter/material.dart';
class WidgetCustom extends StatefulWidget {
_WidgetCustomState _state;
WidgetCustom({#required int iCount}) {
_state = _WidgetCustomState(iCount);
}
#override
State<StatefulWidget> createState() {
return _state;
}
int get getIcount => _state.iCount;
}
class _WidgetCustomState extends State<WidgetCustom> {
int iCount;
_WidgetCustomState(this.iCount);
#override
Widget build(BuildContext context) {
return Container(
child: Row(children: <Widget>[
Column(
children: <Widget>[
RaisedButton(
child: const Text("Please tap me"),
onPressed: () {
setState(() => iCount = iCount + 1);
}),
SizedBox(height: 40),
Text("Tapped $iCount Times")
],
),
]));
}
}
Edited to add main.dart
import 'package:flutter/material.dart';
import 'widgetCustom.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Custom Widget Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WidgetCustom _widgetCustom;
String _sMessage = "Fab has not been pressed";
#override
void initState() {
super.initState();
_widgetCustom = WidgetCustom(iCount: 99);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(children: [
_widgetCustom,
SizedBox(height: 40),
Text(_sMessage),
]),
floatingActionButton: FloatingActionButton(
onPressed: _fabPressed,
tooltip: 'Get Value',
child: Icon(Icons.add),
),
);
}
_fabPressed() {
setState(() => _sMessage =
"Value from last button click = ${_widgetCustom.getIcount}");
}
}
Pass the initial value to the constructor when creating the widget as a final value, and then get it from the State class.
Updated code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.dark(),
home: MyHomePage(title: 'Custom Widget Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WidgetCustom _widgetCustom;
String _sMessage = "Fab has not been pressed";
int _value = 99;
#override
void initState() {
super.initState();
_widgetCustom = WidgetCustom(iCount: _value, function: _update);
}
void _update(int value) {
setState(() {
_value = value;
_widgetCustom = WidgetCustom(iCount: _value, function: _update);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Column(
children: [
_widgetCustom,
SizedBox(height: 40),
Text(_sMessage),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _fabPressed,
tooltip: 'Get Value',
child: Icon(Icons.add),
),
);
}
_fabPressed() {
setState(() => _sMessage = "Value from last button click = ${_value}");
}
}
class WidgetCustom extends StatefulWidget {
final int iCount;
final Function function;
WidgetCustom({#required this.iCount, this.function});
#override
State<StatefulWidget> createState() {
return _WidgetCustomState();
}
}
class _WidgetCustomState extends State<WidgetCustom> {
int _iCount;
#override
void initState() {
super.initState();
_iCount = widget.iCount;
}
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
Column(
children: <Widget>[
RaisedButton(child: const Text("Please tap me"), onPressed: (){
_iCount = _iCount + 1;
widget.function(_iCount);
}),
SizedBox(height: 40),
Text("Tapped $_iCount Times")
],
),
],
),
);
}
}