0

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.

Container_Image_Text_Example

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
════════════════════════════════════════════════════════════════════════════════

Sri
  • 93
  • 8
  • It's a bit difficult to understand what your problem is and what you want to achieve. The title of your question states one problem but at the end you say you have a different problem. Take a look at https://stackoverflow.com/help/how-to-ask to help improve the changes of having your question answered. – J. S. Jan 02 '20 at 14:36
  • Thanks. I have made the changes. Hope it is better now. I am really not sure if this is an issue with the state or the widget itself. That's why I tried to be very generic in my question. I am a newbie to dart and flutter. – Sri Jan 02 '20 at 14:58
  • You accidentally removed the image you had before. – J. S. Jan 02 '20 at 15:04
  • Have you tried having your `Navigator.of(ctx).pop()` on a method inside the `Dialog` to close the `Dialog` after calling the `saveAction` `Function `you passed to the `Dialog`? – J. S. Jan 02 '20 at 15:08
  • I have added more changes to the code before trying your suggestion and it works fine to pop the dialog. But the container still stays the same after adding a text in the dialog. The container populates the text only after the next click on the action button. Is there a way to make it work at the first time itself? – Sri Jan 02 '20 at 15:29
  • Unfortunately without being able to run the code myself, I am not able to detect the issue by just looking at the available code. – J. S. Jan 02 '20 at 15:49
  • The best option was to use Providers package instead of passing the values through constructor – Sri May 19 '20 at 09:14

0 Answers0