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

Flutter GetX列表筛选问题:退格后已过滤项无法恢复

Flutter GetX 实时筛选列表问题

我正在开发首个Flutter应用,尝试用GetX结合TextFormField对从API获取的TreeTypes列表进行实时筛选。目前功能仅部分生效:不符合搜索字符串的项能被正确过滤,但退格删除搜索字符时,已被过滤的项无法重新回到列表中。我明白需要基于原始列表而非已过滤后的列表进行筛选,但尝试多种方法后仍未解决问题。

以下是我的TreeTypeController和视图代码:


TreeTypeController 代码

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:bonsai_care_app/services/tree_type_service.dart';
import 'package:bonsai_care_app/models/tree_type.dart';

class TreeTypeController extends GetxController {
  dynamic arguments = Get.arguments;
  var treeTypeList = <TreeType>[].obs;
  var isLoaded = true.obs;

  @override
  void onInit() {
    super.onInit();
    fetchAndSetTreeTypeList(arguments);
  }

  void filterTreeTypes(searchString) {
    var filteredTreeTypeList = [];
    filteredTreeTypeList = treeTypeList
        .where((element) =>
            element.name.toLowerCase().contains(searchString.toLowerCase()))
        .toList();
    print(filteredTreeTypeList.length);
    treeTypeList(filteredTreeTypeList);
  }

  Future<void> fetchAndSetTreeTypeList(arguments) async {
    debugPrint('TreeTypesController fetchTreeTypes()');
    try {
      isLoaded(false);
      var tree_types = await TreeTypeService().fetchTreeTypes(arguments);
      if (tree_types != null) {
        treeTypeList(tree_types);
      }
    } catch (error) {
      debugPrint(error);
      throw (error);
    } finally {
      isLoaded(true);
    }
  }
}

视图代码

import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:bonsai_care_app/controllers/tree_type_controller.dart';
import 'package:bonsai_care_app/views/select_tree_type_details_screen.dart';

class SelectTreeTypeResultsScreen extends StatelessWidget {
  final TreeTypeController treeTypeController = Get.put(TreeTypeController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('select_tree_type_results__heading'.tr),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Obx(
            () {
              return Column(
                children: [
                  Container(
                    child: TextFormField(
                      onChanged: (query) {
                        treeTypeController.filterTreeTypes(query);
                      },
                      decoration: InputDecoration(
                        labelText:
                            'select_tree_type_results__search_input_label'.tr,
                        border: const OutlineInputBorder(),
                      ),
                    ),
                  ),
                  Container(
                    height: 500,
                    width: 200,
                    child: Visibility(
                      visible: treeTypeController.isLoaded.value,
                      replacement: Center(
                        child: CircularProgressIndicator(),
                      ),
                      child: treeTypeController.treeTypeList.length == 0
                          ? Center(
                              child: Text('no_results'.tr),
                            )
                          : ListView.builder(
                              itemCount: treeTypeController.treeTypeList.length,
                              itemBuilder: (context, index) {
                                return ListTile(
                                  title: Text(treeTypeController
                                      .treeTypeList[index].name),
                                  onTap: () {
                                    Get.to(() => SelectTreeTypeDetailsScreen(),
                                        arguments: treeTypeController
                                            .treeTypeList[index]);
                                  },
                                );
                              },
                            ),
                    ),
                  ),
                ],
              );
            },
          ),
        ],
      ),
    );
  }
}

问题根源

当前treeTypeList既承担原始数据存储,又作为过滤后数据的展示载体。每次筛选时,过滤结果直接覆盖了原始数据,导致退格时无法找回之前被过滤的项。

修复方案

在控制器中新增变量存储原始数据,筛选仅基于原始数据处理,更新用于展示的列表即可:

修改后的TreeTypeController

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:bonsai_care_app/services/tree_type_service.dart';
import 'package:bonsai_care_app/models/tree_type.dart';

class TreeTypeController extends GetxController {
  dynamic arguments = Get.arguments;
  // 存储API获取的原始数据,仅初始化时赋值
  final _originalTreeTypeList = <TreeType>[].obs;
  // 用于UI展示的过滤后列表
  var treeTypeList = <TreeType>[].obs;
  var isLoaded = true.obs;

  @override
  void onInit() {
    super.onInit();
    fetchAndSetTreeTypeList(arguments);
  }

  void filterTreeTypes(String searchString) {
    if (searchString.isEmpty) {
      // 搜索为空时还原为原始列表
      treeTypeList.assignAll(_originalTreeTypeList);
      return;
    }
    var filteredTreeTypeList = _originalTreeTypeList
        .where((element) =>
            element.name.toLowerCase().contains(searchString.toLowerCase()))
        .toList();
    print(filteredTreeTypeList.length);
    treeTypeList.assignAll(filteredTreeTypeList);
  }

  Future<void> fetchAndSetTreeTypeList(arguments) async {
    debugPrint('TreeTypesController fetchTreeTypes()');
    try {
      isLoaded(false);
      var tree_types = await TreeTypeService().fetchTreeTypes(arguments);
      if (tree_types != null) {
        _originalTreeTypeList.assignAll(tree_types);
        // 初始化时展示列表与原始列表一致
        treeTypeList.assignAll(tree_types);
      }
    } catch (error) {
      debugPrint(error.toString());
      throw error;
    } finally {
      isLoaded(true);
    }
  }
}

关键修改点

  • 新增_originalTreeTypeList存储原始数据,后续不修改
  • 筛选逻辑基于原始数据执行,结果赋值给treeTypeList用于展示
  • 搜索字符串为空时,直接将原始列表赋值给展示列表实现还原
  • 使用assignAll方法更新Observable列表,确保GetX能正确监听数据变化

视图代码无需修改,保持原有逻辑即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 17:56:06