How to rebuild all grid items in flutter?

谁都会走 提交于 2021-01-01 08:01:02

问题


I have a dashboard, represented by grid, that supposed to delete item on long press event (using flutter_bloc), but it deletes last item instead of selected. All debug prints show, that needed element actually removed from list, but view layer still keeps it.

My build function code:

  Widget build(BuildContext context) {
    double pyxelRatio = MediaQuery.of(context).devicePixelRatio;
    double width = MediaQuery.of(context).size.width * pyxelRatio;

    return BlocProvider(
      bloc: _bloc,
        child: BlocBuilder<Request, DataState>(
        bloc: _bloc,
        builder: (context, state) {
          if (state is EmptyDataState) {
            print("Uninit");
            return Center(
              child: CircularProgressIndicator(),
            );
          }
          if (state is ErrorDataState) {
            print("Error");
            return Center(
              child: Text('Something went wrong..'),
            );
          }
          if (state is LoadedDataState) {
            print("empty: ${state.contracts.isEmpty}");
            if (state.contracts.isEmpty) {
              return Center(
                child: Text('Nothing here!'),
              );
            } else{
              print("items count: ${state.contracts.length}");              
              print("-------");
              for(int i = 0; i < state.contracts.length; i++){
                if(state.contracts[i].isFavorite)print("fut:${state.contracts[i].name} id:${state.contracts[i].id}");
              }
              print("--------");  

              List<Widget> testList = new List<Widget>();
              for(int i = 0; i < state.contracts.length; i++){
                if(state.contracts[i].isFavorite) testList.add(
                  InkResponse(
                  enableFeedback: true,
                  onLongPress: (){
                    showShortToast();
                    DashBLOC dashBloc = BlocProvider.of<DashBLOC>(context);
                    dashBloc.dispatch(new UnfavRequest(state.contracts[i].id));
                  },
                  onTap: onTap,
                  child:DashboardCardWidget(state.contracts[i])
                  )
              );
              }
              return GridView.count(
                  crossAxisCount: width >= 900 ? 2 : 1,
                  padding: const EdgeInsets.all(2.0),
                  children: testList
              );
            }
          }
      })
    );
  }

full class code and dashboard bloc

Looks like grid rebuilds itself, but don't rebuild its tiles. How can I completely update grid widget with all its subwidgets?

p.s i've spent two days fixing it, pls help


回答1:


I think you should use a GridView.builderconstructor to specify a build function which will update upon changes in the list of items, so when any update occur in your data the BlocBuilder will trigger the build function inside yourGridView.

I hope this example makes it more clear.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Test(),
    );
  }
}

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  List<int> testList = List<int>();

  @override
  void initState() {
    for (int i = 0; i < 20; i++) {
      testList.add(i);
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      floatingActionButton: FloatingActionButton(
        //Here we can remove an item from the list and using setState
        //or BlocBuilder will rebuild the grid with the new list data
        onPressed: () => setState(() {testList.removeLast();})
      ),
      body: GridView.builder(
        // You must specify the items count of your grid
        itemCount: testList.length,
        // You must use the GridDelegate to specify row item count
        // and spacing between items
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 5,
          childAspectRatio: 1.0,
          crossAxisSpacing: 1.0,
          mainAxisSpacing: 1.0,
        ),
        // Here you can build your desired widget which will rebuild
        // upon changes using setState or BlocBuilder
        itemBuilder: (BuildContext context, int index) {
          return Text(
            testList[index].toString(),
            textScaleFactor: 1.3,
          );
        },
      ),
    );
  }
}



回答2:


Your code is always sending the last value of int i.

So instead of

for(int i = 0; i < state.contracts.length; i++){
            if(state.contracts[i].isFavorite) testList.add(
              InkResponse(
              enableFeedback: true,
              onLongPress: (){
                showShortToast();
                DashBLOC dashBloc = BlocProvider.of<DashBLOC>(context);
                dashBloc.dispatch(new UnfavRequest(state.contracts[i].id));
              },
              onTap: onTap,
              child:DashboardCardWidget(state.contracts[i])
              )
          );

Do

          List<Widget> testList = new List<Widget>();

          state.contracts.forEach((contract){
            if(contract.isFavorite) testList.add(
              InkResponse(
              enableFeedback: true,
              onLongPress: (){
                showShortToast();
                DashBLOC dashBloc = BlocProvider.of<DashBLOC>(context);
                dashBloc.dispatch(new UnfavRequest(contract.id));
              },
              onTap: onTap,
              child:DashboardCardWidget(contract)
              )
          ));



回答3:


Is it actually rebuilds? I'm just don't understand why you use the State with BLoC. Even if you use the State you should call the setState() method to update the widget with new data. On my opinion the best solution to you will be to try to inherit your widget from StatelessWidget and call the dispatch(new UpdateRequest()); in the DashBLOC constructor.

Also always keep in mind this link about the bloc, there are lots of examples: https://felangel.github.io/bloc/#/




回答4:


just give children a key

 return  GridView.builder(
                itemCount: children.length,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(3),
                itemBuilder: (context, index) {
                  return Container(
                    key: ValueKey(children.length+index),                       
                  );
                });


来源:https://stackoverflow.com/questions/55539044/how-to-rebuild-all-grid-items-in-flutter

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!