You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何从ListView.builder外部删除列表项

Flutter:从ListView.builder外部删除列表项的方法

我需要从ListView.builder外部删除指定的列表项,已知目标项的名称和索引。尝试通过ListView.removeAt(itemIndex)实现,但该方法无效。

页面包含两个FloatingActionButton:fab1和fab2。点击fab2时会调用removeItem(itemName)函数从数据库删除数据(此功能正常),数据删除后需要同步从ListView中移除对应项,但我不知道如何引用ListView来完成此操作。请问这种情况下如何从ListView中删除项?

原完整代码

Future<List<PostListDetails>> postsFuture = getPosts();
bool showButton = false;
String itemName ="";
int itemIndex = 0;


static Future<List<PostListDetails>> getPosts() async {

  SharedPreferences prefs = await SharedPreferences.getInstance();
  final token = await prefs.getString('token');
  final listID = await prefs.getString('listID');
  final lista = await prefs.getString('lista');

  Response response = await post(Uri.parse('someURL'),
    headers: <String, String>{
      'Accept': 'application/json',
      'Authorization': 'Bearer $token',
    },
    body: <String, String>{
                'listID': '$listID',
    },
  );

  if(response.statusCode != 200){
    print('Błąd połączenia z bazą danych...  status[${response.statusCode}]');
  }

  final List body = json.decode(response.body);
  return body.map((e) => PostListDetails.fromJson(e)).toList();
}


void removeItem(String nazwa) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  final token = await prefs.getString('token');
  final listID = await prefs.getString('listID');

  try{
    Response response = await post(Uri.parse('SomeURL'),
      headers: <String, String>{
        'Accept': 'application/json',
        'Authorization': 'Bearer $token',
      },
      body: <String, String>{
        'listID': '$listID',
        'nazwa': nazwa,
      },
    );

    if(response.statusCode == 200) {
      //ListView.removeAt(itemIndex);  <--- 不知道该怎么写这部分代码
      
    }else{
      print('Błąd połączenia z bazą danych...  status[${response.statusCode}]');
    }
  }catch(e){
    print(e.toString());
  }
}



@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.grey[100],
    floatingActionButton: Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        FloatingActionButton.extended(
          heroTag: "fab1",
          onPressed: () {
            print('---&gt; addList()');
            // addList();
          },
          icon: const Icon(Icons.add_circle_outline),
          label: const Text('Dodaj'),
        ),
        if (showButton)
          FloatingActionButton.extended(
            heroTag: "fab2",
            onPressed: () {
              print('---&gt; removing $itemName');
              removeItem(itemName);  // 此函数负责从数据库删除数据
              setState(() => showButton = false);
            },
            icon: const Icon(Icons.delete),
            label: const Text('Usuń'),
          ),
      ],
    ),
    appBar: AppBar(
      backgroundColor: Colors.grey[900],
      title: const Text('Lista zakupowa'),
      actions: [
        IconButton(
          onPressed: signUserOut,
          icon: const Icon(Icons.logout),
        ),
      ],
    ),
    body: Center(
      child: FutureBuilder<List<PostListDetails>>(
        future: postsFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const CircularProgressIndicator();
          } else if (snapshot.hasData) {
            return buildPosts(snapshot.data!);
          } else {
            return const Text("Brak danych...");
          }
        },
      ),
    ),
  );
}

@override
Widget buildPosts(List<PostListDetails> posts) {
  return ListView.builder(
    itemCount: posts.length,
    itemBuilder: (context, index) {
      final post = posts[index];
      int customCompare(PostListDetails a, PostListDetails b) {
        if (a.status != b.status) {
          return a.status!.toInt() - b.status!.toInt();
        }
        final int categoryCompare = a.kategoria.toString().compareTo(b.kategoria.toString());
        if (categoryCompare != 0) {
          return categoryCompare;
        }
        return a.nazwa.toString().compareTo(b.nazwa.toString());
      }
      return GestureDetector(
        onLongPress: () {
          itemName = post.nazwa!;
          itemIndex = index;
          setState(() => showButton = true);
        },
        child: Container(
          color: post.status! % 2 == 1 ? Colors.grey[100] : Colors.white,
          margin: const EdgeInsets.symmetric(vertical: 0.5, horizontal: 0),
          padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15),
          height: 50,
          width: double.maxFinite,
          child: Row(
            children: [
              Expanded(
                flex: 8,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      post.nazwa!,
                      textAlign: TextAlign.left,
                      style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15, color: Colors.black),
                    ),
                    Text(
                      '${post.waga!.toString()} g.',
                      textAlign: TextAlign.left,
                      style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.grey),
                    ),
                  ],
                ),
              ),
              Expanded(
                flex: 2,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Expanded(
                      flex: 0,
                      child: Row(),
                    ),
                    Expanded(
                      flex: 10,
                      child: Row(
                        children: [
                          CatIcon(imagePath: (Cat2Ico(post.kategoria!.toString()))),
                          Checkbox(
                            value: Int2Bool(post.status!.toInt()),
                            onChanged: (value) {
                              setState(() {
                                post.status = Bool2Int(value!);
                              });
                              saveStatus(post.nazwa!, post.status!, index);
                              posts.sort(customCompare);
                            },
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      );
    },
  );
}

更新1:我已更新源代码,将ListView.remove相关代码移至removeItem函数中。


更新2:以下是修改后的最终代码:

@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.grey[100],
    floatingActionButton: Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        FloatingActionButton.extended(
          heroTag: "fab1",
          onPressed: () {
            print('---&gt; addList()');
            // addList();
          },
          icon: const Icon(Icons.add_circle_outline),
          label: const Text('Dodaj'),
        ),
        if (showButton)
          FloatingActionButton.extended(
            heroTag: "fab2",
            onPressed: () {
              removeItem(itemName).then((value){
                setState((){
                  itemToRemove = true;
                });
              });
              setState(() => showButton = false);
            },
            icon: const Icon(Icons.delete),
            label: const Text('Usuń'),
          ),
      ],
    ),
    appBar: AppBar(
      backgroundColor: Colors.grey[900],
      title: const Text('Lista zakupowa'),
      actions: [
        IconButton(
          onPressed: signUserOut,
          icon: const Icon(Icons.logout),
        ),
      ],
    ),
    body: Center(
      child: FutureBuilder<List<PostListDetails>>(
        future: postsFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const CircularProgressIndicator();
          } else if (snapshot.hasData) {
            return buildPosts(snapshot.data!);
          } else {
            return const Text("Brak danych...");
          }
        },
      ),
    ),
  );
}

@override
Widget buildPosts(List<PostListDetails> posts) {
  if (itemToRemove) {
    posts.removeWhere((element) => element.nazwa == itemName);
    itemToRemove=false;
  }
  return ListView.builder(
    itemCount: posts.length,
    itemBuilder: (context, index) {
      final post = posts[index];
      int customCompare(PostListDetails a, PostListDetails b) {
        if (a.status != b.status) {
          return a.status!.toInt() - b.status!.toInt();
        }
        final int categoryCompare = a.kategoria.toString().compareTo(b.kategoria.toString());
        if (categoryCompare != 0) {
          return categoryCompare;
        }
        return a.nazwa.toString().compareTo(b.nazwa.toString());
      }
      return GestureDetector(
        onLongPress: () {
          itemName = post.nazwa!;
          itemIndex = index;
          setState(() => showButton = true);
        },
        child: Container(
          color: post.status! % 2 == 1 ? Colors.grey[100] : Colors.white,
          margin: const EdgeInsets.symmetric(vertical: 0.5, horizontal: 0),
          padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15),
          height: 50,
          width: double.maxFinite,
          child: Row(
            children: [
              Expanded(
                flex: 8,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      post.nazwa!,
                      textAlign: TextAlign.left,
                      style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15, color: Colors.black),
                    ),
                    Text(
                      '${post.waga!.toString()} g.',
                      textAlign: TextAlign.left,
                      style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.grey),
                    ),
                  ],
                ),
              ),
              Expanded(
                flex: 2,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Expanded(
                      flex: 0,
                      child: Row(),
                    ),
                    Expanded(
                      flex: 10,
                      child: Row(
                        children: [
                          CatIcon(imagePath: (Cat2Ico(post.kategoria!.toString()))),
                          Checkbox(
                            value: Int2Bool(post.status!.toInt()),
                            onChanged: (value) {
                              setState(() {
                                post.status = Bool2Int(value!);
                              });
                              saveStatus(post.nazwa!, post.status!, index);
                              posts.sort(customCompare);
                            },
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      );
    },
  );
}

内容的提问来源于stack exchange,提问作者bzc0fq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 13:49:52