简体   繁体   English

如何从 flutter 中的父小部件访问所有孩子的 state?

[英]How to access all of child's state from Parent Widget in flutter?

I have a parent widget called createRoutineScreen and it has 7 similar children widget called RoutineFormCard.我有一个名为 createRoutineScreen 的父小部件,它有 7 个类似的名为 RoutineFormCard 的子小部件。 RoutineFormCard is a form and which has a state _isPostSuccesful of boolean type to tell whether the form is saved to database or not. RoutineFormCard 是一个表单,它有一个 state _isPostSuccesful 类型为 boolean 来判断表单是否保存到数据库。 Now, I have to move to the other screen from createRoutine only when all of it's 7 children has _isPostSuccesful true.现在,只有当所有 7 个孩子的 _isPostSuccesful 为 true 时,我才必须从 createRoutine 移至另一个屏幕。 How can I access all of children's state from createRoutineScreen widget?如何从 createRoutineScreen 小部件访问所有儿童的 state?

My Code is:我的代码是:

 class CreateRoutineScreen extends StatefulWidget {


  final String userID;

  CreateRoutineScreen({this.userID});
  //TITLE TEXT
  final Text titleSection = Text(
      'Create a Routine',
      style: TextStyle(
        color: Colors.white,
        fontSize: 25,
      )
  );

  final List<Map> weekDays = [
    {"name":"Sunday", "value":1},
    {"name":"Monday", "value":2},
    {"name":"Tuesday", "value":3},
    {"name":"Wednesday", "value":4},
    {"name":"Thursday", "value":5},
    {"name":"Friday", "value":6},
    {"name":"Saturday", "value":7},
  ];

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



class _CreateRoutineScreenState extends State<CreateRoutineScreen> {


  Routine routine;
  Future<List<dynamic>> _exercises;
  dynamic selectedDay;
  int _noOfRoutineSaved;
  List _keys = [];


   Future<List<dynamic>>_loadExercisesData()async{
    String url = BASE_URL+ "exercises";
    var res = await http.get(url);
    var exercisesList = Exercises.listFromJSON(res.body);
    //var value = await Future.delayed(Duration(seconds: 5));
    return exercisesList;
  }


  @override
  void initState(){
    super.initState();
    _exercises = _loadExercisesData();
    _noOfRoutineSaved = 0;
    for (int i = 0; i< 7; i++){
      _keys.add(UniqueKey());
    }
  }

  void _changeNoOfRoutineSaved(int a){
    setState(() {
      _noOfRoutineSaved= _noOfRoutineSaved + a;
    });
  }



  @override
  Widget build(BuildContext context) {
    print(_noOfRoutineSaved);
    return Scaffold(
        appBar: AppBar(
          title:Text("Create a Routine"),
          centerTitle: true,
          actions: <Widget>[
            FlatButton(
              child: Text("Done"),
              onPressed: (){
              },
            ),
          ],
        ),
        body: Container(
          color: Theme.of(context).primaryColor,
          padding: EdgeInsets.only(top:5.0,left: 10,right: 10,bottom: 10),
          child: FutureBuilder(
            future: _exercises,
            builder: (context, snapshot){
              if(snapshot.hasData){
                return ListView.builder(
                  itemCount: widget.weekDays.length,
                  itemBuilder: (context,index){
                    return RoutineFormCard(
                      weekDay: widget.weekDays[index]["name"],
                      exerciseList: snapshot.data,
                      userID : widget.userID,
                      changeNoOfRoutineSaved:_changeNoOfRoutineSaved,
                      key:_keys[index]
                    );
                  },
                );
              }
            else if(snapshot.hasError){
              return SnackBar(
              content: Text(snapshot.error),
              );
            }
            else{
              return Center(
                child: CircularProgressIndicator(
                  backgroundColor: Colors.grey,
                )
              );
            }
          }, 
        )
      ),
    );
  }
}

And my child widget is:我的孩子小部件是:

class RoutineFormCard extends StatefulWidget {

  final Function createRoutineState;
  final String weekDay;
  final List<dynamic> exerciseList;
  final String userID;
  final Function changeNoOfRoutineSaved;

  RoutineFormCard({this.createRoutineState, 
    this.weekDay, this.exerciseList, this.changeNoOfRoutineSaved,
    this.userID, Key key}):super(key:key);

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

class _RoutineFormCardState extends State<RoutineFormCard> {

  bool _checkBoxValue= false;
  List<int> _selectedExercises;
  bool _inAsyncCall;
  bool   _successfulPost;

  @override
  void initState(){
    super.initState();
    _selectedExercises = [];
    _inAsyncCall = false;
    _successfulPost= false;


  }

  void onSaveClick()async{

    setState(() {
     _inAsyncCall = true; 
    });

    String url = BASE_URL + "users/routine";

    List selectedExercises = _selectedExercises.map((item){
      return widget.exerciseList[item].value;
    }).toList();

    String dataToSubmit = jsonEncode({
      "weekDay":widget.weekDay,
      "userID": widget.userID==null?"5e9eb190b355c742c887b88d":widget.userID,
      "exercises": selectedExercises
    });

    try{
      var res =await  http.post(url, body: dataToSubmit,
        headers: {"Content-Type":"application/json"});

        if(res.statusCode==200){
          print("Succesful ${res.body}");
          widget.changeNoOfRoutineSaved(1);
          setState(() {
           _inAsyncCall = false;
           _successfulPost = true; 
          });

        }
        else{
            print("Not succesful ${res.body}");
            setState(() {
             _inAsyncCall = false; 
            });
        }



    }catch(err){
        setState(() {
          _inAsyncCall = false; 
        });
        print(err);

    }

  }


  Widget saveAndEditButton(){
    if(_inAsyncCall){
      return CircularProgressIndicator();
    }
    else if(_successfulPost)
    {
      return IconButton(
        icon: Icon(Icons.edit, color: Colors.black,),
        onPressed: (){
          widget.changeNoOfRoutineSaved(-1);
          setState(() {
           _successfulPost = false; 
          });
        },
      );
    }
    else{
      return FlatButton(child: Text("Save"),
            onPressed: !_checkBoxValue&&_selectedExercises.length==0?null:onSaveClick,);
    }
  }

  //Card Header
  Widget cardHeader(){
    return  AppBar(
      title: Text(widget.weekDay, style: TextStyle(
        fontFamily: "Raleway",
        fontSize: 20,
        color: Colors.black,),
        ),
      actions: <Widget>[
        saveAndEditButton()    
      ],
      backgroundColor: Colors.lime[400],
    );
  }


  Widget cardBody(){
    return Column(
      children: <Widget>[
          Padding(
              padding: const EdgeInsets.all(8.0),
              child: Row(
                children: <Widget>[
                  Text("Rest Day"),
                  Checkbox(
                    value: _checkBoxValue,
                    onChanged: (value){
                      setState(() {
                        _checkBoxValue = value;
                      });
                    },
                  )
                ],
              ),
            ),

            _checkBoxValue?Container():
            SearchableDropdown.multiple(
            hint: "Select Exercise",
            style: TextStyle(color: Colors.black),
            items: widget.exerciseList.map<DropdownMenuItem>((item){
              return DropdownMenuItem(
                child: Text(item.name), value: item
              );
            }).toList(),
            selectedItems: _selectedExercises,
            onChanged: (values){
              setState(() {
              _selectedExercises = values;
              });
            },
            isExpanded: true,
            dialogBox: true,
          ),
      ],
    );
  }


  @override
  Widget build(BuildContext context) {
    print("<><><><><><><><><><><>${widget.weekDay} called");
    return Card(
      elevation: 8.0,
      child: Form(
        key: GlobalKey(),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
          cardHeader(),
          _successfulPost?Container():cardBody()
          ],
        ),
      ),
    );
  }
} 

As you can see, I've tried callBack from parent widget which increases or decrease no of form saved from each of the child widget.如您所见,我已经尝试从父小部件回调,它增加或减少从每个子小部件保存的表单数量。 It does the work but, when one form is saved, parent state is modified and all other children got rebuild which is unnecessary in my opionion.它可以完成工作,但是当保存一个表单时,父 state 会被修改,并且所有其他孩子都得到了重建,这在我看来是不必要的。 What's the best way to do it?最好的方法是什么?

Try to use GlobalKey instead of UniqueKey for each RoutineFormCard .尝试对每个RoutineFormCard使用GlobalKey而不是UniqueKey It will help you to access the state of each RoutineFormCard .它将帮助您访问每个 RoutineFormCard 的RoutineFormCard You can do it like this:你可以这样做:

// 1. In the top of your CreateRoutineScreen file, add this line (make your RoutineFormCardState class public before)
final List<GlobalKey<RoutineFormCardState>> routineFormCardKeys = <GlobalKey<RoutineFormCardState>>[
  GlobalKey<RoutineFormCardState>(),
  GlobalKey<RoutineFormCardState>(),
  GlobalKey<RoutineFormCardState>(),
  GlobalKey<RoutineFormCardState>(),
  GlobalKey<RoutineFormCardState>(),
  GlobalKey<RoutineFormCardState>(),
  GlobalKey<RoutineFormCardState>(),
];

// 2. Then construct your RoutineFormCard using the right key
RoutineFormCard(
  weekDay: widget.weekDays[index]["name"],
  exerciseList: snapshot.data,
  userID : widget.userID,
  changeNoOfRoutineSaved:_changeNoOfRoutineSaved,
  key: routineFormCardKeys[index]
);

// 3. Now you can create a method in CreateRoutineScreen which will check the state of all RoutineFormCard
bool _allRoutineFormCardsCompleted() {
  bool result = true;
  for (int i = 0; i < 7; i++)
    result = result && routineFormCardKeys[i].currentState.isPostSuccessful;

  return result;
}


// 4. Finally use the result of the previous method where you want to move on another page

I'm sharing a quick idea to solve your problem, I've not tested it, but I'm ready to improve the answer if needed我正在分享一个解决您问题的快速想法,我尚未对其进行测试,但我已准备好在需要时改进答案

Hope this will help!希望这会有所帮助!

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

相关问题 如何从其子 Widget 更新 Parent Widget 的状态,同时在 Flutter 中更新 Child 的状态? - How to update the state of Parent Widget from its Child Widget while also updating the Child's state in Flutter? Flutter - 如何从父级调用子级小部件的方法 - Flutter - how to call child widget's method from parent 如何在Flutter中访问父级中的子控件的数据? - How to access data of child widget in parent in flutter? Flutter:从子小部件设置父小部件状态 - Flutter: set parent widget state from child widget 在父窗口小部件中访问子窗口小部件的变量(Flutter with Dart) - Access child widget's variable in parent widget (Flutter with Dart) Flutter - 如何从子小部件调用父小部件函数,同时还使用变量保持状态? - Flutter - How do I call a Parent widget function from child widget while also maintaining the state with a variable? Flutter - 无法从父小部件更改子状态 - Flutter - Can't change child state from parent widget 如何在 flutter 中将 set state 值更改从父窗口小部件传递给子窗口小部件? - How to pass set state value changes from parent to child widget in flutter? 如何从子小部件调用父小部件中的 function | Flutter - How to Call a function in parent widget from child widget | Flutter 如何将数据从子状态小部件传递到 Flutter 中的父小部件 - How to pass data from a child Stateful widget to Parent Widget in Flutter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM