如何从指向状态 class 函数的无状态 Widget 调用函数?

How to call a function from stateless Widget that points to state class function?

我正在尝试创建一个具有快速回复功能的响应式聊天机器人。我想在按下函数调用时创建一个按钮,调用另一个 class 的函数。我尝试使用回调。但我认为我做错了什么。请帮助我。

typedef void mycallback(String label);

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

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

class _HomeScreenState extends State<HomeScreen> {
  User? user = FirebaseAuth.instance.currentUser;
  UserModel loggedInUser = UserModel();
  late DialogFlowtter dialogFlowtter;
  final TextEditingController messageController = TextEditingController();

  @override
  void initState() {
    super.initState();
    DialogFlowtter.fromFile().then((instance) => dialogFlowtter = instance);
  }

  @override
  Widget build(BuildContext context) {
    var themeValue = MediaQuery.of(context).platformBrightness;
    Body(
      hi: sendMessage,
    );
    return Scaffold(
      backgroundColor: themeValue == Brightness.dark
          ? HexColor('#262626')
          : HexColor('#FFFFFF'),
      appBar: AppBar(
        //app bar ui
        ),
        actions: [
          //list if widget in appbar actions
          PopupMenuButton(
            icon: Icon(Icons.menu), 
            color: Colors.blue,
            itemBuilder: (context) => [
              PopupMenuItem<int>(
                value: 0,
                child: Text(
                  "Log out",
                  style: TextStyle(color: Colors.white),
                ),
              ),
            ],
            onSelected: (item) => {logout(context)},
          ),
        ],
      ),
      body: SafeArea(
        child: Column(
          children: [
            Expanded(child: Body(messages: messages)),
            Container(
              padding: const EdgeInsets.symmetric(
                horizontal: 10,
                vertical: 5,
              ),
              child: Row(
                children: [
                  Expanded(
                    child: TextFormField(
                      controller: messageController,
                      style: TextStyle(
                          color: themeValue == Brightness.dark
                              ? Colors.white
                              : Colors.black,
                          fontFamily: 'Poppins'),
                      decoration: new InputDecoration(
                        enabledBorder: new OutlineInputBorder(
                            borderSide: new BorderSide(
                                color: themeValue == Brightness.dark
                                    ? Colors.white
                                    : Colors.black),
                            borderRadius: BorderRadius.circular(15)),
                        hintStyle: TextStyle(
                          color: themeValue == Brightness.dark
                              ? Colors.white54
                              : Colors.black54,
                          fontSize: 15,
                          fontStyle: FontStyle.italic,
                        ),
                        labelStyle: TextStyle(
                            color: themeValue == Brightness.dark
                                ? Colors.white
                                : Colors.black),
                        hintText: "Type here...",
                      ),
                    ),
                  ),
                  IconButton(
                    color: themeValue == Brightness.dark
                        ? Colors.white
                        : Colors.black,
                    icon: Icon(Icons.send),
                    onPressed: () {
                      sendMessage(messageController.text);
                      messageController.clear();
                    },
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }


  void sendMessage(String text) async {
    if (text.isEmpty) return;
    setState(() {
     //do main function
    });
     }
 
}

class 我想调用函数的地方

class Body extends StatelessWidget {
  final List<Map<String, dynamic>> messages;
  final mycallback? hi;
  const Body({
    Key? key,
    this.messages = const [],
    this.buttons = const [],
    this.hi,
    this.onPressed,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      itemBuilder: (context, i) {
        var obj = messages[messages.length - 1 - i];
        Message message = obj['message'];
        bool isUserMessage = obj['isUserMessage'] ?? false;
        String label = obj['label'];
        return Row(
          mainAxisAlignment:
              isUserMessage ? MainAxisAlignment.end : MainAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            _MessageContainer(
              message: message,
              isUserMessage: isUserMessage,
            ),
            ElevatedButton(
              child: Text(label),
              onPressed: () => {hi ?? (label)},//This is where i want to call
              style: ElevatedButton.styleFrom(
                  primary: Colors.blueAccent,
                  padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
                  textStyle: TextStyle(fontWeight: FontWeight.bold)),
            ),
          ],
        );
      },
      separatorBuilder: (_, i) => Container(height: 10),
      itemCount: messages.length,
      reverse: true,
      padding: const EdgeInsets.symmetric(
        horizontal: 10,
        vertical: 20,
      ),
    );
  }
}

代码运行没有错误,但当我按下按钮时没有任何反应。

这就是我实现类似功能的方式。您基本上是在小部件内要求一个 void 作为参数。几乎像 TextButton 或其他类似的小部件。

您也可以将其与两个有状态宽度一起使用,因为您是在将函数从一个借用到另一个。

此外,我认为提供程序会做得更好,因此我建议您研究一下。 (我没有足够的经验) https://pub.dev/packages/provider

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int x = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('An app'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('$x'),
            TestWidget(onTap: () {
              setState(() {
             x++;
             });
              
            })
          ],
        ),
      ),
    );
  }
}

class TestWidget extends StatelessWidget {
  final VoidCallback onTap;
  const TestWidget({Key? key, required this.onTap}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
          padding: const EdgeInsets.all(20),
          color: Colors.blue,
          child: Text('test')),
    );
  }
}

我发现了错误。 在 class 主屏幕中,我错过了这一行。

 child: Body(
              messages: messages,
              hi: (text) => {sendMessage(text)}, //this line
            )

添加此行后,回调正常!