繁体   English   中英

从另一个StatefulWidget的Stateful Widget调用函数

[英]Call function from Stateful Widget from another StatefulWidget

因此,基本上我有一个ProfilePage ,它是一个StatelessWidget ,在它的构建方法内部,我显示了一个名为MyForm的表单(它是一个StatefulWidget和一个名为FancyFab的窗口小部件(这是另一个StatefulWidget

这是一个如何在父窗口小部件上显示它们的示例:

@override
  Widget build(BuildContext globalContext) {
    return Scaffold(
      appBar: AppBar(title: Text('Profile')),
      floatingActionButton: FancyFab(),
      body: Center(
        child: FutureBuilder(
          future: initData(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return MyForm(data: snapshot.data);
            } else if (snapshot.hasError) {
              print(snapshot.error);
              return new Container(width: 0.0, height: 0.0);
            } else {
              return Center(child: CircularProgressIndicator());
            }
          },
        )
      )
  );
}

我的问题在于,我在MyFormState有一个saveData()函数,该函数从每个TextFormField控制器获取值并将其保存在数据库中。 我需要从我的FancyFab小部件中调用此函数,但找不到合适的方法。 甚至从我的FancyFab小部件中访问那些TextFormField控制器。 任何帮助或指导将不胜感激。

编辑

这是我实现FancyFab小部件的方式:

class FancyFab extends StatefulWidget {
  final String tooltip;
  final IconData icon;
  String photo;
  TextEditingController birthController;
  TextEditingController firstController;
  TextEditingController lastController;
  TextEditingController emailController;
  TextEditingController phoneController;
  TextEditingController associationController;
  TextEditingController countryController;

  final Function saveData;

  FancyFab({ 
  this.tooltip, 
  this.icon, 
  this.saveData,
  this.firstController,
  this.lastController,
  this.emailController,
  this.phoneController,
  this.associationController,
  this.countryController,
  this.birthController,
  this.photo});

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

class _FancyFabState extends State<FancyFab>
    with SingleTickerProviderStateMixin {
  bool isOpened = false;
  AnimationController _animationController;
  Animation<Color> _buttonColor;
  Animation<double> _animateIcon;
  Animation<double> _translateButton;
  Curve _curve = Curves.easeOut;
  double _fabHeight = 56.0;

  @override
  initState() {
    _animationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 500))
          ..addListener(() {
            setState(() {});
          });
    _animateIcon =
        Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
    _buttonColor = ColorTween(
      begin: Colors.pink,
      end: Colors.red,
    ).animate(CurvedAnimation(
      parent: _animationController,
      curve: Interval(
        0.00,
        1.00,
        curve: Curves.linear,
      ),
    ));
    _translateButton = Tween<double>(
      begin: _fabHeight,
      end: -14.0,
    ).animate(CurvedAnimation(
      parent: _animationController,
      curve: Interval(
        0.0,
        0.75,
        curve: _curve,
      ),
    ));
    super.initState();
  }

  @override
  dispose() {
    _animationController.dispose();
    super.dispose();
  }

  animate() {
    if (!isOpened) {
      _animationController.forward();
    } else {
      _animationController.reverse();
    }
    isOpened = !isOpened;
  }

  Widget save() {
    return Container(
      child: FloatingActionButton(
        heroTag: 'saveBtn',
        onPressed: () {

        },
        tooltip: 'Save',
        child: Icon(Icons.save),
      ),
    );
  }

  Widget image() {
    return Container(
      child: FloatingActionButton(
        heroTag: 'imageBtn',
        onPressed: () async {
          File file = await FilePicker.getFile(type: FileType.IMAGE); 

                  AlertDialog alert = AlertDialog(
                            title: Text('Uploading photo'),
                            titlePadding: EdgeInsets.all(20.0),
                            contentPadding: EdgeInsets.all(20.0),
                            elevation:10,
                            content: CircularProgressIndicator(),
                          );

                  final StorageReference storageRef = FirebaseStorage.instance.ref().child(file.path);

                  final String fileName = file.path;

                  final StorageUploadTask uploadTask = storageRef.putFile(
                    File(fileName),
                  ); 

                  final StorageTaskSnapshot downloadUrl = 
                  (await uploadTask.onComplete);
                  final String url = (await downloadUrl.ref.getDownloadURL());
                  print('URL Is $url');
                  setState(() {
                    widget.photo = url;
                  });
        },
        tooltip: 'Image',
        child: Icon(Icons.image),
      ),
    );
  }

  Widget toggle() {
    return Container(
      child: FloatingActionButton(
        backgroundColor: _buttonColor.value,
        onPressed: animate,
        heroTag: 'toggleBtn',
        tooltip: 'Toggle',
        child: AnimatedIcon(
          icon: AnimatedIcons.menu_close,
          progress: _animateIcon,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.end,
      children: <Widget>[
        Transform(
          transform: Matrix4.translationValues(
            0.0,
            _translateButton.value * 2.0,
            0.0,
          ),
          child: save(),
        ),
        Transform(
          transform: Matrix4.translationValues(
            0.0,
            _translateButton.value * 1.0,
            0.0,
          ),
          child: image(),
        ),
        toggle(),
      ],
    );
  }
}

据我所知,应用程序的数据流有一个小问题,例如,严格地基于基于功能性的观察,数据和触发器(FancyFab)应该在同一小部件​​中或可直接访问小部件。 但是,如果您想继续, 是一种非常原始的方法。

我设法通过在MyForm小部件中嵌套一个Scaffold来解决此问题。 然后树变了,我的FancyFab小部件现在是MyForm小部件的子级。 接下来,我将父级的saveData()函数和所有控制器传递给了子窗口小部件,这样我就可以调用提供适当数据的父级函数。 解决方法如下:

父小部件(MyForm)

class MyFormState extends State<MyForm> {

  User user;
  TextEditingController birthController = TextEditingController();
  TextEditingController firstController = TextEditingController();
  TextEditingController lastController = TextEditingController();
  TextEditingController emailController = TextEditingController();
  TextEditingController phoneController = TextEditingController();
  TextEditingController associationController = TextEditingController();
  TextEditingController countryController = TextEditingController();



    @override
  void initState() {
    super.initState();
    user = widget.data[1];
    firstController.text = user.firstName;
    lastController.text = user.lastName;
    countryController.text = user.country;
    birthController.text = user.dateBirth;
    emailController.text = user.email;
    phoneController.text = user.phone;
    associationController.text = user.association;
  }

 _updatePhoto(String text) {
    setState(() {
      user.photo = text;
    });
  }

  _saveData(data, BuildContext ctx) async {
    FirebaseUser fireUser= await FirebaseAuth.instance.currentUser();
    var uid = fireUser.uid;
    await Firestore.instance.collection('users').document(uid).updateData(data).then((val) {
     AlertDialog alert = AlertDialog(
                            title: Text('Confirmation'),
                            titlePadding: EdgeInsets.all(20.0),
                            // contentPadding: EdgeInsets.all(20.0),
                            elevation:10,
                            content: Text('Your profile has been saved.')

    );

    showDialog(context: ctx,
                    builder: (BuildContext context){
                      return alert;
    });

    })
    .catchError((err) {
      final snackBar = SnackBar(
      content: Text('There have been an error updating your profile' + err.toString()),
      elevation: 10,
    );
    Scaffold.of(ctx).showSnackBar(snackBar);
    });

  }



    @override 
  Widget build(BuildContext context) {
    return Scaffold(
            floatingActionButton: FancyFab(
              parentAction: _updatePhoto,
              saveData: _saveData,
              firstController: firstController,
              lastController: lastController,
              emailController: emailController,
              countryController: countryController,
              associationController: associationController,
              phoneController: phoneController,
              birthController: birthController,
              photo: user.photo),
            body:Form(
               //more UI
            )
           );
   }
}

子小部件(FancyFab)

class FancyFab extends StatefulWidget {
  final void Function(String value) parentAction;
  final void Function(dynamic data, BuildContext ctx) saveData;
  final String tooltip;
  final IconData icon;
  String photo;
  TextEditingController birthController;
  TextEditingController firstController;
  TextEditingController lastController;
  TextEditingController emailController;
  TextEditingController phoneController;
  TextEditingController associationController;
  TextEditingController countryController;


  FancyFab({ 
  this.parentAction,
  this.tooltip, 
  this.icon, 
  this.saveData,
  this.firstController,
  this.lastController,
  this.emailController,
  this.phoneController,
  this.associationController,
  this.countryController,
  this.birthController,
  this.photo});

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

然后,我可以在子窗口小部件状态上使用widget.parentFunction(data)调用父函数。

特别感谢@diegoveloper提供了一篇很棒的文章,解释了小部件交互的类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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