简体   繁体   中英

How do I call a method from a stateful widget inside of a stateful widget

I am trying to clean up my code and want to place one of my methods from a stateful widget inside of a different class that is also a stateful widget but whenever I try to call the method it does not recognize it unless the class that I am calling it from it a stateless widget. I was wondering what the best way to get around this would be without changing the class?

Here is a simple example of my problem, I am trying to call exampleStatefulWidget.testWidget() inside of MyHomePage which is a stateful widget.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
ExampleStatefulWidget exampleStatefulWidget = ExampleStatefulWidget();
ExampleStatelessWidget exampleStatelessWidget = ExampleStatelessWidget();

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Test'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
        exampleStatefulWidget.testWidget(), // Can not call method that is inside of a stateful widget
        exampleStatelessWidget.testWidget(); // Will call method but only if inside of a stateless widget
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

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

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

class _ExampleStatefulWidgetState extends State<ExampleStatefulWidget> {
  MyHomePage myHomePage = MyHomePage();

  Widget testWidget() {
    return Container(); // Do Something
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

class ExampleStatelessWidget extends StatelessWidget {
  const ExampleStatelessWidget({ Key? key }) : super(key: key);

  Widget testWidget() {
    return Container(); // Do Something
  }
  
  @override
  Widget build(BuildContext context) {
    return Container(
      
    );
  }
}

ExampleStatefulWidget and _ExampleStatefulWidgetState are different class, you can create instance of _ExampleStatefulWidgetState instead. And use the method.

_ExampleStatefulWidgetState exampleStatefulWidget =
    _ExampleStatefulWidgetState();

In this case, uses will be like

_MyHomePageState

class _MyHomePageState extends State<MyHomePage> {
  Widget? widgetFromMethod;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Test'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            if (widgetFromMethod != null) widgetFromMethod!,
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          exampleStatelessWidget
              .testWidget(); // Will call method but only if inside of a stateless widget
          final gotWidget = exampleStatefulWidget.testWidget();

          setState(() {
            widgetFromMethod = gotWidget;
          });
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

_ExampleStatefulWidgetState

class _ExampleStatefulWidgetState extends State<ExampleStatefulWidget> {
  MyHomePage myHomePage = MyHomePage();

  Widget testWidget() {
    return Container(
      color: Colors.purple,
      width: 100,
      height: 100,
      child: Text("generated method from statefull"),
    ); // Do Something
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

if _ExampleStatefulWidgetState are on separate file, make it public removing _ . it will be ExampleStatefulWidgetState

Calling a printLog method of SecondWidget (Child) from FirstWidget(Parent)

Note : This is not recommended. Use any state management lib to achive this (flutter_bloc, provider etc)

import 'package:flutter/material.dart';

class FirstWidget extends StatefulWidget {
  @override
  _FirstWidgetState createState() => _FirstWidgetState();
}

class _FirstWidgetState extends State<FirstWidget> {
  final key = GlobalKey<_SecondWidgetState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          alignment: Alignment.center,
          child: Column(
            children: [
              ElevatedButton(
                onPressed: () {
                  key.currentState?.printLog();
                },
                child: Text("Click"),
              ),
              SecondWidget(key)
            ],
          ),
        ),
      ),
    );
  }
}

class SecondWidget extends StatefulWidget {
  SecondWidget(Key key) : super(key: key);

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

class _SecondWidgetState extends State<SecondWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(padding: EdgeInsets.all(20), child: Container());
  }

  void printLog() {
    print("I am called");
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM