在 Flutter 中从 SecondScreen 调用 FirstScreen 的设置状态

Call set state of FirstScreen from SecondScreen in Flutter

我在 flutter 中有两个名为 'FirstScreen' 的屏幕,其中包含订单列表和 'SecondScreen' 用于某些操作。

我想在 'SecondScreen' 弹出时调用 'FirstScreen' 的设置状态,以便 'FirstScreen' 将重新加载挂单列表

SecondScreen 将接受或拒绝订单,FirstScreen 应从服务器重新加载数据,这是由 FirstScreen 中的方法 getOrders() 调用的。

首屏代码

import 'package:flutter/material.dart';
import 'package:nobleappshop/model/jobOrderItem.dart';
import 'package:nobleappshop/screens/SeconScreen.dart';
import 'package:nobleappshop/constants/constants.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class FirstScreen extends StatefulWidget {
  @override
  FirstScreenState createState() => FirstScreenState();
}
class FirstScreenState extends State<FirstScreen> {

  Future<List<JobOrders>> _getPendingOrder() async {
    var data = await http.get("$ApiServer/JobOrders/smOrdersPending");
    var jsonData = json.decode(data.body);
    List<JobOrders> joborderitemlist = [];
    for (var i in jsonData) {
      JobOrders jobOrders = JobOrders(
        Eid: i["Eid"],
        Uid: i["Uid"],
        Name: i["Name"],
        Contact: i["Contact"].toString(),
        OrderStat: i["OrderStat"],
      );
      joborderitemlist.add(jobOrders);
    }
    return joborderitemlist;
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('FirstScreen'),
      ),
      body: FutureBuilder(
        future: _getPendingOrder(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.data.length <= 0) {
              return Container(
                child: Center(
                  child: Text('You have not made any orders yet...'),
                ),
              );
            } else {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  return OrdersListWidget(
                    Eid: snapshot.data[index].Eid,
                    Uid: snapshot.data[index].Uid.toString(),
                    Name: snapshot.data[index].Name.toString(),
                    Contact: snapshot.data[index].Contact.toString(),
                    Status: snapshot.data[index].OrderStat.toString(),
                  );
                },
              );
            }
          } else {
            return Container(
              child: Center(
                child: CircularProgressIndicator(),
              ),
            );
          }
        },
      ),
    );
  }
}
class OrdersListWidget extends StatelessWidget {
  int Eid;
  String Uid;
  String Name;
  String Contact;
  String Status;
  OrdersListWidget(
      {@required this.Eid,
        @required this.Uid,
        @required this.Name,
        @required this.Contact,
        @required this.Status});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        ListTile(
          leading: Text('#$Eid'),
          title: Text(Name),
          subtitle: Text(Contact),
          trailing: Text(Status),
          onTap: () {
            showModalBottomSheet(
              context: context,
              isScrollControlled: true,
              builder: (context) => SingleChildScrollView(
                child: Container(
                  padding: EdgeInsets.only(
                      bottom: MediaQuery.of(context).viewInsets.bottom),
                  child: SecondScreen(OrderId: Eid),
                ),
              ),
            );
          },
        ),
        Divider(),
      ],
    );
  }
}

第二屏代码

import 'package:flutter/material.dart';
import 'package:nobleappshop/model/orderItem.dart';
import 'package:http/http.dart' as http;
import 'package:nobleappshop/widgets/iconTextWidget.dart';
import 'package:nobleappshop/widgets/scOrderItems.dart';
import 'package:nobleappshop/constants/constants.dart';

class SecondScreen extends StatefulWidget {

  int OrderId;
  SecondScreen({@required this.OrderId});

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

class _SecondScreenState extends State<SecondScreen> {

  Future<http.Response> _updateJobOrder() async {
//Run Update code here
  }
  double totalAmount = 0;
  String token;

  List<OrderItem> orderitemlist = [];

  Future<List<OrderItem>> _getMyOrders() async {
//Call for orderitemslist
    return orderitemlist;
  }

  @override
  void initState() {
    super.initState();
    _getMyOrders();
  }
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Color(0xff757575),
      child: Container(
        padding: EdgeInsets.all(8.0),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(20.0),
            topRight: Radius.circular(20.0),
          ),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[

            IconTextRowWidget(btnIcon: Icons.credit_card,btnText: 'Amount Due',btnSubText: '${totalAmount<10?10:totalAmount} QAR',),
            Row(
              children: <Widget>[
                Expanded(
                  child: FlatButton(
                    color: Colors.green,
                    onPressed: (){
                      // Here I would like to close my current screen and reload orderslist, so that it will load all other pending joborders
                      _updateJobOrder();
                      Navigator.pop(context);
                    },
                    child: Text('Approve',style: TextStyle(color: Colors.white),),
                  ),
                ),
                Expanded(
                  child: FlatButton(
                    color: Colors.blueGrey,
                    onPressed: (){
// Here I would like to close my current screen and reload orderslist, so that it will load all other pending joborders
                      _updateJobOrder();
                      Navigator.pop(context);
                    },
                    child: Text('Reject',style: TextStyle(color: Colors.white),),
                  ),
                ),
              ],
            ),
            SizedBox(height: 10,)
//            SizedBox(
//              height: 30.0,
//            ),
          ],
        ),
      ),
    );
  }
}

您可以声明一个 void 回调或函数作为第二屏幕的 属性 并从第一屏幕发送;这是一个例子;

class SecondScreen extends StatelessWidget {
  final VoidCallback setStateOfFirstScreen;

  const SecondScreen({Key key, this.setStateOfFirstScreen}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(icon: Icon(Icons.refresh), onPressed: setStateOfFirstScreen),
        ],
      ),
      body: Center(),
    );
  }
}

class FistScreen extends StatefulWidget {
  @override
  _FistScreenState createState() => _FistScreenState();
}

class _FistScreenState extends State<FistScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: FlatButton(
          child: Text("Go to the second screen"),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (c) => SecondScreen(
                  setStateOfFirstScreen: () => setState(() {}),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

当我检查你的代码时,我意识到你需要将函数发送给你的第一个小部件的孙子,

  1. 您需要在 OrdersListWidget 中声明一个函数,因为此小部件是访问第二个屏幕的唯一方式。
    class OrdersListWidget extends StatelessWidget {
      int Eid;
      String Uid;
      String Name;
      String Contact;
      String Status;
      final VoidCallback setStateOfFirstScreen;
    
      OrdersListWidget(
          {@required this.Eid,
          @required this.Uid,
          @required this.Name,
          @required this.Contact,
          @required this.Status,
          @required this.setStateOfFirstScreen});
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: <Widget>[
            ListTile(
              leading: Text('#$Eid'),
              title: Text(Name),
              subtitle: Text(Contact),
              trailing: Text(Status),
              onTap: () {
                showModalBottomSheet(
                  context: context,
                  isScrollControlled: true,
                  builder: (context) => SingleChildScrollView(
                    child: Container(
                      padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
                      child: SecondScreen(OrderId: Eid, setStateOfFirstScreen: setStateOfFirstScreen),
                    ),
                  ),
                );
              },
            ),
            Divider(),
          ],
        );
      }
    }
  1. 并将 setState 作为第一个页面的参数发送到 OrdersListWidget
    ListView.builder(
      itemCount: snapshot.data.length,
      itemBuilder: (BuildContext context, int index) {
        return OrdersListWidget(
          Eid: snapshot.data[index].Eid,
          Uid: snapshot.data[index].Uid.toString(),
          Name: snapshot.data[index].Name.toString(),
          Contact: snapshot.data[index].Contact.toString(),
          Status: snapshot.data[index].OrderStat.toString(),
          setStateOfFirstScreen: () => setState(() {}),
        );
      },
    );
  1. setStateOfFirstScreen 发送到 SecondScreen 并在那里使用它来设置第一个屏幕的状态;

    class SecondScreen extends StatefulWidget {
      final int OrderId;
      final VoidCallback setStateOfFirstScreen;
    
      SecondScreen({@required this.OrderId, @required this.setStateOfFirstScreen});
    
      @override
      _SecondScreenState createState() => _SecondScreenState();
    }
    
    class _SecondScreenState extends State<SecondScreen> {
      Future<http.Response> _updateJobOrder() async {
    //Run Update code here
      }
      double totalAmount = 0;
      String token;
    
      List<OrderItem> orderitemlist = [];
    
      Future<List<OrderItem>> _getMyOrders() async {
    //Call for orderitemslist
        return orderitemlist;
      }
    
      @override
      void initState() {
        super.initState();
        _getMyOrders();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Color(0xff757575),
          child: Container(
            padding: EdgeInsets.all(8.0),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(20.0),
                topRight: Radius.circular(20.0),
              ),
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                IconTextRowWidget(
                  btnIcon: Icons.credit_card,
                  btnText: 'Amount Due',
                  btnSubText: '${totalAmount < 10 ? 10 : totalAmount} QAR',
                ),
                Row(
                  children: <Widget>[
                    Expanded(
                      child: FlatButton(
                        color: Colors.green,
                        onPressed: () {
                          // Here I would like to close my current screen and reload orderslist, so that it will load all other pending joborders
                          _updateJobOrder();
                          Navigator.pop(context);
                          widget.setStateOfFirstScreen();
                        },
                        child: Text(
                          'Approve',
                          style: TextStyle(color: Colors.white),
                        ),
                      ),
                    ),
                    Expanded(
                      child: FlatButton(
                        color: Colors.blueGrey,
                        onPressed: () {
    // Here I would like to close my current screen and reload orderslist, so that it will load all other pending joborders
                          _updateJobOrder();
                          Navigator.pop(context);
                          widget.setStateOfFirstScreen();
                        },
                        child: Text(
                          'Reject',
                          style: TextStyle(color: Colors.white),
                        ),
                      ),
                    ),
                  ],
                ),
                SizedBox(
                  height: 10,
                )
    //            SizedBox(
    //              height: 30.0,
    //            ),
              ],
            ),
          ),
        );
      }
    }