ListView.Builder с ScrollController с пагинацией перестроить два раза флаттер - PullRequest
0 голосов
/ 23 сентября 2019

флаттер У меня проблема, когда я использую два StateFullWidgets из TabController, он перестраивается два раза, когда я прокручиваю каждый StateFullWidget, отображающий ListView.Builder с ScrollController флаттером.Мне нужно восстановить только один раз.Here is the reproducible code.

Экран вкладок

class OrdersScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => OrderScreenState();
}

class OrderScreenState extends State<OrdersScreen>
    with SingleTickerProviderStateMixin {
  TabController _tabController;
  final List<Color> tabColors = <Color>[Color(0xff185397), Colors.black54];
  List<Widget> _orderScreens = [ToDeliverScreen(), DeliveredScreen()];
  @override
  void initState() {
    _tabController = TabController(vsync: this, length: 2);
    super.initState();
  }

  void _updateTabItemColor(int index) {
    setState(() {
      if (index == 0) {
        tabColors[0] = Color(0xff185397);
        tabColors[1] = Colors.black54;
      } else {
        tabColors[0] = Colors.black54;
        tabColors[1] = Color(0xff185397);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: PreferredSize(
          preferredSize: Size.fromHeight(kToolbarHeight),
          child: Container(
            color: Colors.white,
            child: SafeArea(
              child: Column(
                children: <Widget>[
                  Container(),
                  TabBar(
                    indicatorColor: Color(0xff185397),
                    onTap: (int index) {
                      _updateTabItemColor(index);
                    },
                    controller: _tabController,
                    tabs: [
                      tabItem('TO DELIVER', tabColors[0]),
                      tabItem('DELIVERED', tabColors[1])
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
        body: TabBarView(
          controller: _tabController,
          children: _orderScreens,
        ),
      ),
    );
  }

  Widget tabItem(String text, Color color) {
    return InkWell(
      child: Container(
        padding: EdgeInsets.symmetric(vertical: 16.0),
        child: Text(
          text,
          style: TextStyle(
              color: color, fontWeight: FontWeight.bold, fontSize: 16.0),
        ),
      ),
    );
  }
}

Первый элемент вкладки

class ToDeliverScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => ToDeliverScreenState();
}

class ToDeliverScreenState extends State<ToDeliverScreen> {


  ToDeliverBloc _toDeliverBloc;
  ScrollController _scrollController = ScrollController();
  bool isLoading = false;
  bool isInitPage = true;
  int page = 2;
  List<Order> orders = [];
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();


  @override
  void initState() {
    _toDeliverBloc = BlocProvider.of<ToDeliverBloc>(context);
    this._getMoreData(1);
    super.initState();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        _getMoreData(page);
        this.page++;
        print(page);
      }
    });
  }

  _getMoreData(int page) async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });

      Map<String, dynamic> params = {'page': page, 'type': '0'};
      _toDeliverBloc.inOrdersSink.add(LoadToDeliverCommand(params));

      setState(() {
        isLoading = false;
      });

    }
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      //resizeToAvoidBottomPadding: false,
      body: StreamBuilder(
        stream: _toDeliverBloc.outProgressOrders,
        builder: (context, AsyncSnapshot<List<Order>> snapshot) {

          if (snapshot.connectionState == ConnectionState.waiting)
            return Center(
              child: CircularProgressIndicator(backgroundColor: Color(0xff185397),),
            );
          else if (snapshot.connectionState == ConnectionState.none) {
            return Center(
              child: Text(
                'No data',
                style: TextStyle(fontSize: 16.0),
              ),
            );
          } else {
            if(snapshot.data!=null){
              orders.addAll(snapshot.data);
              if (orders.length > 0) {
                return ListView.builder(
                    itemCount: orders.length+1,
                    controller: _scrollController,
                    itemBuilder: (BuildContext context, int index) {
                      if(index == orders.length)
                        return _buildProgressIndicator();
                      else{
                        return _orderItem(context, orders[index]);
                      }
                    });
              } else {
                return Center(
                  child: Text(
                    'No data',
                    style: TextStyle(fontSize: 16.0),
                  ),
                );
              }
            }
          }
        },
      ),
    );
  }

  Widget _orderItem(BuildContext context, Order order) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
      child: GestureDetector(
          onTap: () {
            _toDeliverBloc.inOrdersSink.add(ToDeliverItemCommand(order));
            //Navigator.pushNamed(context, "/order-detail");
          },
          child: Card(
            elevation: 2.0,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Row(
                      mainAxisSize: MainAxisSize.max,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          '${order.customerName}',
                          style: TextStyle(
                              color: Colors.black,
                              fontSize: 16.0,
                              fontWeight: FontWeight.bold),
                        ),
                        Text(
                          '${formatDate(order.orderDate)}',
                          style: TextStyle(
                              fontSize: 16.0,
                              fontWeight: FontWeight.bold,
                              color: Colors.black54),
                        ),
                      ],
                    )),
                Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        Text('Order #${order.orderId}',
                            style: TextStyle(
                                fontSize: 14.0,
                                fontWeight: FontWeight.normal,
                                color: Colors.black54)),
                        SizedBox(height: 8),
                        Text('Total \$${order.totalAmount}',
                            style: TextStyle(
                                fontSize: 14.0,
                                fontWeight: FontWeight.normal,
                                color: Colors.black87)),
                      ],
                    )),
                ButtonTheme.bar(
                  // make buttons use the appropriate styles for cards
                  child: Container(
                      padding:
                          EdgeInsets.symmetric(horizontal: 16, vertical: 16),
                      color: const Color(0xffF2F2F4),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        mainAxisSize: MainAxisSize.max,
                        children: <Widget>[
                          Row(
                            mainAxisSize: MainAxisSize.min,
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: <Widget>[
                              Icon(
                                Icons.directions_car,
                                color: Colors.black54,
                              ),
                              SizedBox(
                                width: 8,
                              ),
                              Text(
                                order.deliveryStatus == '0'
                                    ? 'pending deliver'
                                    : order.deliveryStatus == '1'
                                        ? 'delivering'
                                        : 'delivered',
                                style: TextStyle(
                                    fontSize: 14,
                                    color: Colors.black54,
                                    fontWeight: FontWeight.normal),
                              )
                            ],
                          ),
                          Text(
                            order.paymentStatus == '0' ? 'unpaid' : 'paid',
                            style: TextStyle(
                                fontSize: 14,
                                color: Colors.redAccent,
                                fontWeight: FontWeight.bold),
                          )
                        ],
                      )),
                ),
              ],
            ),
          )),
    );
  }

  Widget _buildProgressIndicator() {
    return new Padding(
      padding: const EdgeInsets.all(8.0),
      child: new Center(
        child: new Opacity(
          opacity: isLoading ? 1.0 : 00,
          child: new CircularProgressIndicator(backgroundColor: Color(0xff185397),),
        ),
      ),
    );
  }
}    

второй элемент вкладки

class DeliveredScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => DeliveredScreenState();
}

class DeliveredScreenState extends State<DeliveredScreen> {

  ScrollController _scrollController = ScrollController();

  DeliveredBloc _deliveredBloc;
  int _page = 2;
  bool isLoading = false;
  List<Order> orders = [];

  _loadMoreOrders(int page) {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });

      Map<String, dynamic> params = {'page': page, 'type': '2'};
      _deliveredBloc.inDoneOrdersSink.add(LoadDeliveredCommand(params));

      setState(() {
        isLoading = false;
      });
    }
  }

  @override
  void initState() {
    _deliveredBloc = BlocProvider.of<DeliveredBloc>(context);
    _loadMoreOrders(1);

    super.initState();

    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        _loadMoreOrders(_page);
        _page++;
        print("page >> ${_page}");
      }
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: StreamBuilder(
        stream: _deliveredBloc.outDoneOrders,
        builder: (context, AsyncSnapshot<List<Order>> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting)
            return Center(
              child: CircularProgressIndicator(),
            );
          else if (snapshot.connectionState == ConnectionState.none) {
            return Center(
              child: Text(
                'No data',
                style: TextStyle(fontSize: 16.0),
              ),
            );
          } else {
              print("orders >>>${snapshot.data.length}");
              orders.addAll(snapshot.data);
            if (orders.length > 0) {
              return ListView.builder(
                itemCount: isLoading==true ? orders.length+1:orders.length,
                controller: _scrollController,
                itemBuilder: (BuildContext context, int index) {
                  if (orders.length == index)
                    return _buildProgressIndicator();
                  else
                    return _orderItem(context, orders[index]);
                },
              );
            } else {
              return Center(
                child: Text(
                  'No data',
                  style: TextStyle(fontSize: 16.0),
                ),
              );
            }
          }
        },
      ),
    );
  }

  Widget _buildProgressIndicator() {
    return new Padding(
      padding: const EdgeInsets.all(8.0),
      child: new Center(
        child: new Opacity(
          opacity: isLoading ? 1.0 : 00,
          child: new CircularProgressIndicator(
            backgroundColor: Color(0xff185397),
          ),
        ),
      ),
    );
  }

  Widget _orderItem(BuildContext context, Order order) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
      child: GestureDetector(
          onTap: () {
            //Navigator.pushNamed(context, "order-detail");
          },
          child: Card(
            elevation: 2.0,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Row(
                      mainAxisSize: MainAxisSize.max,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          '${order.customerName}',
                          style: TextStyle(
                              color: Colors.black,
                              fontSize: 16.0,
                              fontWeight: FontWeight.bold),
                        ),
                        Text(
                          '${formatDate(order.orderDate)}',
                          style: TextStyle(
                              fontSize: 16.0,
                              fontWeight: FontWeight.bold,
                              color: Colors.black54),
                        ),
                      ],
                    )),
                Padding(
                    padding: EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        Text('Order #${order.orderId}',
                            style: TextStyle(
                                fontSize: 14.0,
                                fontWeight: FontWeight.normal,
                                color: Colors.black54)),
                        SizedBox(height: 8),
                        Text('Total \$${order.totalAmount}',
                            style: TextStyle(
                                fontSize: 14.0,
                                fontWeight: FontWeight.normal,
                                color: Colors.black87)),
                      ],
                    )),
                ButtonTheme.bar(
                  // make buttons use the appropriate styles for cards
                  child: Container(
                      padding:
                          EdgeInsets.symmetric(horizontal: 16, vertical: 16),
                      color: const Color(0xffF2F2F4),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        mainAxisSize: MainAxisSize.max,
                        children: <Widget>[
                          Row(
                            mainAxisSize: MainAxisSize.min,
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: <Widget>[
                              Icon(
                                Icons.directions_car,
                                color: Colors.black54,
                              ),
                              SizedBox(
                                width: 8,
                              ),
                              Text(
                                order.deliveryStatus == '0'
                                    ? 'pending deliver'
                                    : order.deliveryStatus == '1'
                                        ? 'delivering'
                                        : 'delivered',
                                style: TextStyle(
                                    fontSize: 14,
                                    color: Colors.black54,
                                    fontWeight: FontWeight.normal),
                              )
                            ],
                          ),
                          Text(
                            order.paymentStatus == '0' ? 'unpaid' : 'paid',
                            style: TextStyle(
                                fontSize: 14,
                                color: Colors.redAccent,
                                fontWeight: FontWeight.bold),
                          )
                        ],
                      )),
                ),
              ],
            ),
          )),
    );
  }
}

...