1. ホーム
  2. flutter

[解決済み] あるステートフルウィジェットのメソッドを別のステートフルウィジェットから呼び出す - Flutter

2023-01-13 12:29:07

質問

私は今取り組んでいるflutterプロジェクトを持っています。500行以上のコードがあるため、コード全体を載せることはできません。

私はステートフルウィジェットを持っていて、そのステートフルウィジェットの中でいくつかの関数を持っていて、そのクラスは State<MusicPlayer>

ファイル lib\main.dart

のような単純な関数を取るだけです。

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

この関数は、メインクラス内のステートフルウィジェットの中にあります。

もう一つのファイル 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??  
      }
    );
  }
}

どのように解決するのですか?

親の関数を呼び出すには、コールバックパターンを使用します。この例では、ある関数( 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);

ボタンやフォームフィールドのようなFlutterの内部ウィジェットもまったく同じパターンを使用します。引数なしで関数を呼び出すだけなら 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 を呼び出すだけで、子ウィジェットを更新することができます。


もうひとつの方法として controller クラスです ( ScrollController , AnimationController , ...). これらはコンストラクタのパラメータとして子プロセスにも渡され、 子プロセスの状態を制御するためのメソッドを含んでおり、 そのメソッドを呼び出すことなく setState を親に呼び出すことなく、子の状態を制御するためのメソッドが含まれています。例

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

そして、子プロセスはこれらの変更をリッスンして内部の状態を更新することが要求されます。もちろん、独自のコントローラクラスを実装することも可能です。必要であれば、Flutterのソースコードを見て、その仕組みを理解することをお勧めします。


FuturesとStreamは状態を受け渡すための別の選択肢であり、子の関数を呼び出すために使用することもできます。

しかし、私は本当にそれをお勧めしません。もし、子ウィジェットのメソッドを呼び出す必要があるなら、それはアプリケーションアーキテクチャに欠陥がある可能性が高いです。 共通の祖先まで状態を移動させてみてください!