call method in one stateful widget from another stateful widget - Flutter

后端 未结 7 950
耶瑟儿~
耶瑟儿~ 2020-11-29 17:59

I have a flutter project that i am working on i cant put the whole code cause its more than 500 lines of code so i will try to ask my question as simply as i acn using the i

相关标签:
7条回答
  • 2020-11-29 18:28

    You can do that by use key of widget

    myWidget.dart

        class MyWidget extends StatefulWidget {
         
          const MyWidget ({Key key}) : super(key: key);
         
          @override
          State<StatefulWidget> createState()=> MyState();
        
      
        }
    
       class MyState extends State<MyWidget >{
            
              
                   
          Widget build(BuildContext context){ return ....}
        
          void printSample (){
             print("Sample text");
          }
            
     }
    

    now when use MyWidget declare GlobalKey as global key

      GlobalKey<MyState> _myKey = GlobalKey();
    

    and pass it when create widget

    MyWidget(
    key : _myKey,
    )
    

    by this key you can call any public method inside state

    _myKey.currentState.printSample();
    
    0 讨论(0)
  • 2020-11-29 18:28

    I found another solution by trial-and-error, but it worked.

    import 'main.dart' as main;
    

    Then add this line under the onPressed.

    main.MyAppState().printSample();
    
    0 讨论(0)
  • 2020-11-29 18:28

    I just found a simplest solution for this question

    Appearently, You can just create a file that contain only a method and you will be able to call it directly

    For Example, I want to create a showModalBottomSheet method in file named custom_show_bottom_sheet.dart :

    import 'package:flutter/material.dart';
    
    customShowBottomSheet(context, Widget child){
        showModalBottomSheet(
          isScrollControlled: true,
          context: context,
          builder: (BuildContext context) {
            return Wrap(
              children: <Widget>[
                child,
              ],
            );
          });
    }
    

    And you can simply call it like this:

    import 'package:flutter/material.dart';
    import '../custom_show_bottom_sheet.dart';
    
    class TestScreen extends StatelessWidget {
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: FloatingActionButton(
                onPressed: (){
                  customShowBottomSheet( //A method is called here
                      context,
                      Container(
                        height: 200,
                        child: Text("This is a test"),
                      )
                  );
                }),
          ),
        );
      }
    }
    

    Hope this be a help! Please let me know if I misunderstand your question or anything.

    0 讨论(0)
  • 2020-11-29 18:33

    Here HomePage is parent page and ChildPage is child page. There is one method called onSelectItem, which we need to call from child page.

    class HomePage extends StatefulWidget {
    
      @override HomePageState createState() => HomePageState();
    }
    
    class HomePageState extends State<HomePage> {
    
      onSelectItem(String param) {
        print(param);
      }
    
      @override Widget build(BuildContext context) {
    
      }
    }
    
    class ChildPage extends StatefulWidget {
      final HomePageState homePageState;
    
      ChildPage({Key key, @required this.homePageState}) : super(key: key);
    
      _ChildPageState createState() => _ChildPageState();
    }
    
    class _ChildPageState extends State<ChildPage> {
      @override Widget build(BuildContext context) {
    
        return RaisedButton(
          onPressed: () {
            widget.homePageState.onSelectItem("test");
          },
          child: const Text(
              'Click here',
              style: TextStyle(fontSize: 20)
          ),
        );
      }
    }
    

    So, by using the widget and parent class state we can call the parent class method.

    0 讨论(0)
  • 2020-11-29 18:34

    You can give this a try, it will call a method defined in Page2 (StatefulWidget) from Page1 (StatefulWidget) widget.

    class Page1 extends StatefulWidget {
      @override
      _Page1State createState() => _Page1State();
    }
    
    class _Page1State extends State<Page1> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: RaisedButton(
              child: Text("Call page 2 method"),
              onPressed: () => Page2().method(),
            ),
          ),
        );
      }
    }
    
    class Page2 extends StatefulWidget {
      method() => createState().methodInPage2();
    
      @override
      _Page2State createState() => _Page2State();
    }
    
    class _Page2State extends State<Page2> {
      methodInPage2() => print("method in page 2");
    
      @override
      Widget build(BuildContext context) => Container();
    }
    
    0 讨论(0)
  • 2020-11-29 18:36

    To call a function of a parent, you can use the callback pattern. In this example, a function (onColorSelected) is passed to the child. The child calls the function when a button is pressed:

    import 'package:flutter/material.dart';
    
    class Parent extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return ParentState();
      }
    }
    
    class ParentState extends State<Parent> {
      Color selectedColor = Colors.grey;
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: <Widget>[
            Container(
              color: selectedColor,
              height: 200.0,
            ),
            ColorPicker(
              onColorSelect: (Color color) {
                setState(() {
                  selectedColor = color;
                });
              },
            )
          ],
        );
      }
    }
    
    class ColorPicker extends StatelessWidget {
      const ColorPicker({this.onColorSelect});
    
      final ColorCallback onColorSelect;
    
      @override
      Widget build(BuildContext context) {
        return Row(
          children: <Widget>[
            RaisedButton(
              child: Text('red'),
              color: Colors.red,
              onPressed: () {
                onColorSelect(Colors.red);
              },
            ),
            RaisedButton(
              child: Text('green'),
              color: Colors.green,
              onPressed: () {
                onColorSelect(Colors.green);
              },
            ),
            RaisedButton(
              child: Text('blue'),
              color: Colors.blue,
              onPressed: () {
                onColorSelect(Colors.blue);
              },
            )
          ],
        );
      }
    }
    
    typedef ColorCallback = void Function(Color color);
    

    Internal Flutter widgets like buttons or form fields use exactly the same pattern. If you only want to call a function without any arguments, you can use the VoidCallback type instead defining your own callback type.


    If you want to notify a higher up parent, you can just repeat this pattern on every hierarchy level:

    class ColorPickerWrapper extends StatelessWidget {
      const ColorPickerWrapper({this.onColorSelect});
    
      final ColorCallback onColorSelect;
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: EdgeInsets.all(20.0),
          child: ColorPicker(onColorSelect: onColorSelect),
        )
      }
    }
    

    Calling a method of child widget from a parent widget is discouraged in Flutter. Instead, Flutter encourages you to pass down the state of a child as constructor parameters. Instead of calling a method of the child, you just call setState in the parent widget to update its children.


    One alternative approach are the controller classes in Flutter (ScrollController, AnimationController, ...). These are also passed to the children as constructor parameters, and they contain methods to control the state of the child without calling setState on the parent. Example:

    scrollController.animateTo(200.0, duration: Duration(seconds: 1), curve: Curves.easeInOut);
    

    The children are then required to listen to these changes to update their internal state. Of course, you can also implement your own controller class. If you need to, I recommend you to look at the source code of Flutter to understand how that works.


    Futures and streams are another alternative to pass down state, and could also be used to call a function of a child.

    But I really don't recommend it. If you need to call a method of a child widget, it is very like that your application architecture is flawed. Try to move the state up to the common ancestor!

    0 讨论(0)
提交回复
热议问题