How to call setsate function from a different widget?

Viewed 29

Well, I am coding a chatbot-like page in my app. But, I am stuck at calling setState function for page inside of chatBubble widget. Here is my page as MedicBot and chat question code as FirstQuestion. What I do want to do that whenever, user triggers radio tile's on tap condition. It should be trigger setState function in MedicBot, any suggestions?

import 'package:medicte/assets/back_button.dart';
import 'package:medicte/assets/first_question.dart';

class MedicBot extends StatefulWidget {
  const MedicBot({Key? key}) : super(key: key);

  @override
  State<MedicBot> createState() => _MedicBotState();
}

class _MedicBotState extends State<MedicBot> {
  late final List<Widget> _messages;
  late final List<dynamic> botMessages;
  FocusNode _focusNode = FocusNode();
  setMainState() {
    print('bum');
    this.setState(() {});
  }

  @override
  void initState() {
    print('bumbeyarag');
    botMessages = [
      _buildChatBubbles(
          widget: SizedBox.shrink(),
          text:
              'Do you have further medical information you can share? (e.g. lab results)',
          userControl: false),
      _buildChatBubbles(
          widget: FirstQuestion(
            focus: _focusNode,
            radioButtons: ['1-2 weeks', 'A Month', '1-3 Months', 'Other'],
            setMainState: setMainState,
          ),
          text: 'Where do you currently live?',
          userControl: false),
      _buildChatBubbles(
          widget: FirstQuestion(
            focus: _focusNode,
            radioButtons: [
              'Online Consultation',
              'Second Opinion',
              'A treatment cost',
              'Other'
            ],
            setMainState: setMainState,
          ),
          text: 'How soon do you want to get the treatment done?',
          userControl: false),
      _buildChatBubbles(
          widget: FirstQuestion(
            focus: _focusNode,
            radioButtons: ['Yes', 'No'],
            setMainState: () {
              setState(() {});
            },
          ),
          text: 'What service are you looking for?',
          userControl: false),
      _buildChatBubbles(
          widget: FirstQuestion(
            focus: _focusNode,
            radioButtons: [],
            setMainState: () {
              setState(() {});
            },
          ),
          text: 'Have you already spoken a doctor?',
          userControl: false),
      _buildChatBubbles(
          text: 'Which treatment are you interested in?',
          userControl: false,
          widget:
              const Text('Enter a treatment name (e.g Hair Transplant, IVF)')),
      _buildChatBubbles(
          text: 'You are inquiring for',
          userControl: false,
          widget: FirstQuestion(
            radioButtons: const ['Myself', 'For someone else'],
            focus: _focusNode,
            setMainState: () {
              setState(() {});
            },
          )),
    ];
    _messages = [
      const SizedBox(
        height: 1,
      ),
      const SizedBox(
        height: 10,
      )
    ];
    super.initState();
  }

  final TextEditingController _controller = TextEditingController();
  bool value = false;
  @override
  Widget build(BuildContext context) {
    if (botMessages.isNotEmpty) {
      _messages.insert(1, botMessages.removeLast());
    }
    return Scaffold(
        bottomSheet: Container(
          color: Colors.white30,
          child: Padding(
            padding: const EdgeInsets.only(bottom: 30, right: 15, left: 15),
            child: TextFormField(
              focusNode: _focusNode,
              controller: _controller,
              decoration: InputDecoration(
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(25),
                ),
                hintText: 'Type your message',
                suffixIcon: IconButton(
                  onPressed: () {
                    print(_controller.text);
                    print(_controller.value);
                    setState(() {
                      _messages.insert(
                          1,
                          _buildChatBubbles(
                              text: _controller.text,
                              userControl: true,
                              widget: const SizedBox.shrink()));
                      _controller.clear();
                    });
                  },
                  icon: const Icon(Icons.send),
                ),
              ),
            ),
          ),
        ),
        appBar: AppBar(
          leadingWidth: 101,
          backgroundColor: Colors.blue.shade300,
          leading: Row(
            children: [
              const BackWardButton(),
              ClipRRect(
                borderRadius: BorderRadius.circular(1000),
                child: Container(
                  color: Colors.white,
                  child: Image.asset(
                      'lib/images/Lovepik_com-401792159-medical-robot.png',
                      height: 53,
                      width: 53),
                ),
              ),
            ],
          ),
          title: const Text(
            "MedicBot",
            style: TextStyle(color: Colors.black54),
          ),
        ),
        body: SafeArea(
            minimum:
                const EdgeInsets.only(top: 2, left: 10, right: 10, bottom: 90),
            child: ListView.builder(
              itemCount: _messages.length,
              reverse: true,
              itemBuilder: ((context, index) {
                return _messages[index];
              }),
            )));
  }
}

class _buildChatBubbles extends StatelessWidget {
  bool userControl;
  String text;
  Widget widget;
  _buildChatBubbles(
      {required this.widget,
      required this.text,
      required this.userControl,
      super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(bottom: 10),
      child: Row(
        mainAxisAlignment:
            userControl ? MainAxisAlignment.end : MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          userControl
              ? const SizedBox.shrink()
              : Container(
                  margin: const EdgeInsets.only(right: 10),
                  child: const CircleAvatar(
                    radius: 20,
                    backgroundImage: AssetImage(
                        'lib/images/Lovepik_com-401792159-medical-robot.png'),
                  ),
                ),
          Container(
            constraints: BoxConstraints(
                maxHeight: MediaQuery.of(context).size.height * 0.4,
                maxWidth: MediaQuery.of(context).size.width * 0.6),
            padding: const EdgeInsets.all(10),
            decoration: BoxDecoration(
              color: userControl ? Colors.green.shade300 : Colors.blue.shade300,
              borderRadius: BorderRadius.circular(10),
              boxShadow: [
                BoxShadow(
                  color: Colors.grey.withOpacity(0.5),
                  spreadRadius: 1,
                  blurRadius: 7,
                  offset: const Offset(0, 3), // changes position of shadow
                ),
              ],
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  userControl ? 'You' : 'Medicte Bot',
                  style: const TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.w600,
                  ),
                ),
                const SizedBox(height: 5),
                Flexible(
                  child: Text(
                    text,
                    style: const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w400,
                    ),
                  ),
                ),
                widget
              ],
            ),
          ),
        ],
      ),
    );
    ;
  }
}

import 'package:flutter/material.dart';
import 'package:group_button/group_button.dart';
import 'package:medicte/pages/chat_ui.dart';

// ignore: must_be_immutable
class FirstQuestion extends StatefulWidget {
  List<String> radioButtons;
  FocusNode focus;
  void Function() setMainState;
  FirstQuestion(
      {required this.setMainState,
      required this.focus,
      required this.radioButtons,
      Key? key})
      : super(key: key);

  @override
  State<FirstQuestion> createState() => _FirstQuestionState();
}

class _FirstQuestionState extends State<FirstQuestion> {
  late GroupButtonController _radioController;

  // ignore: prefer_typing_uninitialized_variables
  late final _radioButtons;

  @override
  void initState() {
    _radioButtons = widget.radioButtons;
    _radioController = GroupButtonController(
      selectedIndexes: [0, 1, 2, 3],
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GroupButton(
        controller: _radioController,
        isRadio: true,
        options: const GroupButtonOptions(groupingType: GroupingType.column),
        buttons: _radioButtons,
        buttonIndexedBuilder: (selected, index, context) {
          return RadioTile(
            title: _radioButtons[index],
            selected: _radioController.selectedIndex,
            index: index,
            onTap: () {
              print(_radioButtons[index].toString());
              widget.setMainState();
              _radioController.selectIndex(index);

              /* Future.delayed(Duration(seconds: 1), () {
                widget.setMainState();
              }); */
            },
          );
        },
        onSelected: (val, i, selected) {
          print('object');
        });
  }
}

class RadioTile extends StatelessWidget {
  const RadioTile({
    Key? key,
    required this.selected,
    required this.onTap,
    required this.index,
    required this.title,
  }) : super(key: key);

  final String title;
  final int index;
  final int? selected;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(title),
      onTap: onTap,
      leading: Radio<int>(
        groupValue: selected,
        value: index,
        onChanged: (val) {
          print(val);
          onTap();
        },
      ),
    );
  }
}
1 Answers

Try something like this. This is the code snippet of an application of mine. I used StatefulBuilder as the parent of the widgets I want to update and I sent the setState parameter to the widget where I trigger.

import 'package:flutter/material.dart';

class CryptoassetsPage extends StatefulWidget {
  const CryptoassetsPage({Key? key}) : super(key: key);

  @override
  _CryptoassetsPageState createState() => _CryptoassetsPageState();
}

class _CryptoassetsPageState extends State<CryptoassetsPage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Theme.of(context).backgroundColor,
      child: SingleChildScrollView(
        child: StatefulBuilder(
            builder: (BuildContext context, StateSetter setState) {
          //My other class/widget
          return OrderOptions(setState);
        }),
      ),
    );
  }
}

class OrderOptions extends StatefulWidget {
  const OrderOptions(this.setState, {Key? key}) : super(key: key);

  final StateSetter setState;

  @override
  _OrderOptionsState createState() => _OrderOptionsState();
}

class _OrderOptionsState extends State<OrderOptions> {
  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        StateSetter setState = widget.setState;
        setState(() {});
      },
    );
  }
}
Related