метод вызова в одном виджетах с состоянием из другого виджета с состоянием - Flutter

У меня есть проект флаттера, над которым я работаю, я не могу поставить весь код на более чем 500 строк кода, поэтому я постараюсь задать свой вопрос так же просто, как использовать ac. раздел кода.

У меня есть виджет с состоянием и имеющий некоторые функции внутри этого виджета с сохранением состояния под классом, который расширяет extensions State<MusicPlayer>

файл lib\main.dart

просто возьмите простую функцию, например

class MyAppState extends State<MyApp>{
...
void printSample (){
  print("Sample text");
}
...

эта функция находится внутри виджета stateful внутри основного класса.

есть еще один файл lib\MyApplication.dart

этот файл также имеет виджет с состоянием, я могу сделать что-то, чтобы я мог вызвать функцию printSample() здесь.

class MyApplicationState extends State<MyApplication>{
...
@override
  Widget build(BuildContext context) {
    return new FlatButton(
      child: new Text("Print Sample Text"),
      onPressed :(){
       // i want to cal the function here how is it possible to call the 
       // function 
       // printSample()  from here??  
      }
    );
  }
...
}

Ответ 1

Чтобы вызвать функцию родителя, вы можете использовать шаблон обратного вызова. В этом примере функция (onColorSelected) передается onColorSelected. Ребенок вызывает функцию при нажатии кнопки:

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);

Виджеты внутреннего флаттера, такие как кнопки или поля формы, используют точно такой же шаблон. Если вы хотите только вызвать функцию без каких-либо аргументов, вы можете использовать тип VoidCallback вместо этого определяя свой собственный тип обратного вызова.


Если вы хотите уведомить более высокого родителя, вы можете просто повторить этот шаблон на каждом уровне иерархии:

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),
    )
  }
}

Вызов метода дочернего виджета из родительского виджета не рекомендуется в Flutter. Вместо этого Flutter рекомендует вам передать состояние дочернего элемента в качестве параметров конструктора. Вместо вызова метода для ребенка вы просто вызываете setState в родительском setState для обновления своих дочерних setState.


Один альтернативный подход - это классы controller в Flutter (ScrollController, AnimationController ,...). Они также передаются детям как параметры конструктора, и они содержат методы для управления состоянием дочернего setState без вызова setState в родительском setState. Пример:

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

Затем детям необходимо прослушать эти изменения, чтобы обновить их внутреннее состояние. Конечно, вы также можете реализовать свой собственный класс контроллера. Если вам нужно, я рекомендую вам посмотреть исходный код Flutter, чтобы понять, как это работает.


Фьючерсы и потоки являются еще одной альтернативой для передачи состояния, а также могут использоваться для вызова функции дочернего элемента.

Но я действительно не рекомендую. Если вам нужно вызвать метод дочернего виджета, это очень похоже на то, что ваша архитектура приложения ошибочна. Попробуйте переместить состояние до общего предка!

Ответ 2

Я нашел другое решение методом проб и ошибок, но оно сработало.

import 'main.dart' as main;

Затем добавьте эту строку под onPressed.

main.MyAppState().printSample();

Ответ 3

если вы хотите вызвать функцию printSample(), вы можете использовать:

class Myapp extends StatefulWidget{
...
    MyappState myAppState=new MyappState();
    @override
    MyappState createState() => myAppState;
    void printSample(){
        myAppState.printSample();
    }
}
class MyAppState extends State<MyApp>{
    void printSample (){
        print("Sample text");
    }
}

...............
Myapp _myapp = new Myapp();
myapp.printSample();
...

Ответ 4

Вы можете попробовать это, он вызовет метод, определенный в Page2 (StatefulWidget) из виджета Page1 (StatefulWidget).

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();
}