I have a container on my page which should have either image or text depending on the one that is given in the Custom Dialog widget. I have created this widget in a separate Stateless Class. I am calling this from the page where my container is created.
Custom Dialog
class CustomDialog extends StatelessWidget {
TextEditingController textController;
BuildContext context;
Function saveAction;
CustomDialog({
this.context,
this.textController,
this.saveAction,
});
_getText(String text) {
return Text(
text,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black, fontSize: 16),
);
}
_buildIconHolder(IconData icon) {
return Container(
width: 60,
height: 60,
decoration:
BoxDecoration(shape: BoxShape.circle, color: Colors.yellowAccent),
child: Icon(icon, size: 40, color: Colors.blue),
);
}
_buildImagePickerElements() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_getText("Add Image"),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildIconHolder(Icons.folder_open),
_getText("or"),
_buildIconHolder(Icons.camera_alt),
],
),
],
);
}
_buildTextInput() {
return Card(
color: Colors.orange[600],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: EdgeInsets.all(10),
child: TextField(
controller: textController,
decoration: InputDecoration(
border: InputBorder.none, hintText: "hint text here"),
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
textInputAction: TextInputAction.next,
maxLines: 4,
),
),
);
}
_buildPrimaryButton(Function fn) {
return InkWell(
child: GestureDetector(
child: Container(
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.all(Radius.circular(10))),
child: Text("Save",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white)),
),
onTap: () => {
fn,
Navigator.of(ctx).pop();
),
);
}
_getDialogElements() {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_buildImagePickerElements(),
SizedBox(height: 10),
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.only(right: 10),
child: Divider(color: Colors.purple, thickness: 2),
),
),
_getText("or"),
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 10),
child: Divider(color: Colors.purple, thickness: 2),
),
),
],
),
SizedBox(height: 10),
_getText("Describe Below"),
SizedBox(height: 10),
_buildTextInput(),
SizedBox(height: 10),
_buildPrimaryButton(saveAction),
],
);
}
Widget build(BuildContext context) {
return AlertDialog(
backgroundColor: Colors.blueGrey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
),
content: SingleChildScrollView(
child: Container(width: 400.0, child: _getDialogElements()),
),
);
}
}
HomePage
import 'package:custom_dialog/custom_dialog.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController _controller = new TextEditingController();
String _field = "";
clicked(BuildContext ctx) {
// setState(() {
if (_controller.text.isNotEmpty && _controller.text != null) {
_field = _controller.text;
}
// Navigator.of(ctx).pop();
// });
}
_makeContainerAText() {
return Container(
width: 40,
height: 60,
child: Text(_field),
);
}
_makeContainerAActionBtn() {
return Container(
width: 40,
height: 60,
child: FloatingActionButton(
backgroundColor: Colors.yellow,
onPressed: () {
setState(() {
print("Action button pressed");
showDialog(
context: context,
builder: (BuildContext context) => CustomDialog(
context: context,
textController: _controller,
saveAction: clicked(context),
),
);
});
},
child: Icon(
Icons.add,
color: Colors.purple,
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Container Home Page"),
),
body: Center(
child: Stack(
children: <Widget>[
InkWell(
splashColor: Colors.orange[400],
highlightColor: Colors.purple,
child: Material(
elevation: 10,
borderRadius: BorderRadius.all(Radius.circular(10)),
child: DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.orange[600],
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: Padding(
padding: EdgeInsets.all(25),
child: validate
? _makeContainerAText()
: _makeContainerAActionBtn(),
),
),
),
)
],
),
),
);
}
}
In short, I want the container to look like the one given below in the link after adding text or image.
I cannot use setState in the custom dialog class since it is stateless. If I make it stateful, then I am unable to see it on the screen when I click on the container that executes the show dialog. I tried to use the setState in the clicked()
method but ended up with the error below.
════════ Exception caught by animation library ═════════════════════════════════
The following assertion was thrown while notifying status listeners for AnimationController:
setState() or markNeedsBuild() called during build.
This _ModalScope<dynamic> 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.
The widget on which setState() or markNeedsBuild() was called was: _ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#f69dd]
state: _ModalScopeState<dynamic>#32d94
The widget which was currently being built when the offending call was made was: Builder
dirty
When the exception was thrown, this was the stack
#0 Element.markNeedsBuild.<anonymous closure>
package:flutter/…/widgets/framework.dart:3896
#1 Element.markNeedsBuild
package:flutter/…/widgets/framework.dart:3911
#2 State.setState
package:flutter/…/widgets/framework.dart:1168
#3 _ModalScopeState._routeSetState
package:flutter/…/widgets/routes.dart:664
#4 ModalRoute.setState
package:flutter/…/widgets/routes.dart:784
...
The AnimationController notifying status listeners was: AnimationController#073ac(⏮ 0.000; paused; for _DialogRoute<dynamic>)
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
setState() or markNeedsBuild() called during build.
The relevant error-causing widget was
MaterialApp
lib/main.dart:9
════════════════════════════════════════════════════════════════════════════════