Reputation: 859
I need to call the funciton via constructor of stateless widget. Since, I cannot set a state inside a stateless widget. I need to set it from parent of the LightButton
class which is Classroom
. I tried to create a funciton(func
) and pass it into the LightButton
class' constructor. And set the state via using the onButtonPressed
. The logic of this code is when clicking on LigthButton
the the text should switch from OFF
to ON
from LightBulb
class and the title()
should switch from Turn light on
to Turn light off
from LigtButton
class. I get two errors like the followings.
The following assertion was thrown building LightButton(dirty):
setState() or markNeedsBuild() called during build.
This Classroom widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
state: _ClassroomState#4c34c
The widget which was currently being built when the offending call was made was: LightButton
dirty
The relevant error-causing widget was
LightButton
package:hw_20170602012/widgets/widgets.dart:27
When the exception was thrown, this was the stack
#0 Element.markNeedsBuild.<anonymous closure>
package:flutter/…/widgets/framework.dart:4292
#1 Element.markNeedsBuild
package:flutter/…/widgets/framework.dart:4307
#2 State.setState
package:flutter/…/widgets/framework.dart:1264
#3 _ClassroomState.onButtonPressed
package:hw_20170602012/widgets/widgets.dart:11
#4 LightButton.title
package:hw_20170602012/widgets/widgets.dart:59
.
The second one is
══════ Exception caught by rendering library ═════════════════════════════════
A RenderFlex overflowed by 99300 pixels on the bottom.
The relevant error-causing widget was
Column
lib\main.dart:26
════════════════════════════════════════════════════════════════════════════════
Here is the code
import 'package:flutter/material.dart';
class LightBulb extends StatelessWidget {
bool isLit;
LightBulb(bool isLit) {
this.isLit = isLit;
}
Widget build(BuildContext context) {
return Container(
color: isLit ? Colors.green : Colors.red,
padding: EdgeInsets.all(5),
child: isLit ? Text('ON') : Text('OFF'),
);
}
}
class LightButton extends StatelessWidget {
Function func; // getting the value from constructor and send it below onPressed function.
LightButton(Function func) { //Constructor for getting the state from Classroom
this.func = func;
}
//title change
String title() {
if (func()) return "Turn light off"; //Funciton
return "Turn light on";
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 12),
color: Colors.red,
child: Container(
color: Colors.blue,
child: MaterialButton(
textColor: Colors.white,
onPressed: ()=>func(), //Function call happens here.
child: Text(
title(),
style: TextStyle(color: Colors.white),
),
),
),
);
}
}
class Classroom extends StatefulWidget {
@override
_ClassroomState createState() => _ClassroomState();
}
class _ClassroomState extends State<Classroom> {
bool isLightOn= false; //by default isLightOn is false,
//This method switchs the boolean condition and will be passed into the constructor of the LightButton function
onButtonPressed() {
setState(() {
return isLightOn = !isLightOn; //returns the oppositon of the current contion(true->false,false->true)
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
LightBulb(onButtonPressed), //If the function return true,text switchs to 'ON' else 'OFF'
LightButton(onButtonPressed), // If function
],
),
),
);
}
}
Upvotes: 0
Views: 108
Reputation: 54367
You can copy paste run full code below
Reason: title()
means execute function title
, in LightButton
call Text(title(),style: TextStyle(color: Colors.white),),
cause widget tree try to rebuild again
Step 1: Remove return
keyword in onButtonPressed()
onButtonPressed() {
setState(() {
isLightOn =
!isLightOn; //returns the oppositon of the current contion(true->false,false->true)
});
}
Step 2: Pass isLightOn
to LightButton
class LightButton extends StatelessWidget {
Function
func; // getting the value from constructor and send it below onPressed function.
bool isLightOn;
LightButton(Function func, bool isLightOn) {
//Constructor for getting the state from Classroom
this.func = func;
this.isLightOn = isLightOn;
}
//title change
String title() {
if (isLightOn) return "Turn light off"; //Funciton
return "Turn light on";
}
...
LightButton(onButtonPressed, isLightOn),
working demo
full code
import 'package:flutter/material.dart';
class LightBulb extends StatelessWidget {
bool isLit;
LightBulb(bool isLit) {
this.isLit = isLit;
}
Widget build(BuildContext context) {
return Container(
color: isLit ? Colors.green : Colors.red,
padding: EdgeInsets.all(5),
child: isLit ? Text('ON') : Text('OFF'),
);
}
}
class LightButton extends StatelessWidget {
Function
func; // getting the value from constructor and send it below onPressed function.
bool isLightOn;
LightButton(Function func, bool isLightOn) {
//Constructor for getting the state from Classroom
this.func = func;
this.isLightOn = isLightOn;
}
//title change
String title() {
if (isLightOn) return "Turn light off"; //Funciton
return "Turn light on";
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 12),
color: Colors.red,
child: Container(
color: Colors.blue,
child: MaterialButton(
textColor: Colors.white,
onPressed: () => func(), //Function call happens here.
child: Text(
title(),
style: TextStyle(color: Colors.white),
),
),
),
);
}
}
class Classroom extends StatefulWidget {
@override
_ClassroomState createState() => _ClassroomState();
}
class _ClassroomState extends State<Classroom> {
bool isLightOn = false; //by default isLightOn is false,
//This method switchs the boolean condition and will be passed into the constructor of the LightButton function
onButtonPressed() {
setState(() {
isLightOn =
!isLightOn; //returns the oppositon of the current contion(true->false,false->true)
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//LightBulb(onButtonPressed), //If the function return true,text switchs to 'ON' else 'OFF'
LightButton(onButtonPressed, isLightOn), // If function
],
),
),
);
}
}
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: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Classroom(),
);
}
}
Upvotes: 2
Reputation: 1143
Your problem is in LightBulb(onButtonPressed)
. You are passing a function to it whereas it is expecting a bool. Remember that you are not calling the onButtonPressed
here, so you can't assume that it is a bool it is a reference to the function. Replace LightBulb(onButtonPressed)
with LightBulb(isLightOn)
to fix this issue.
Upvotes: 0