在多个字符串中进行颤振搜索

时间:2021-06-03 05:47:02

标签: flutter

我有过滤我的列表的搜索字段,它工作正常,我只想对其进行一些小的更改:

逻辑

  1. 当用户清除搜索字段时返回完整列表
  2. 搜索也包含在ListTile->subtitle中,目前只搜索title

代码 search function is commented for better understanding

List<World> locations = [...]


Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
            children: [
                buildSearch(),
                Expanded(
                    child: ListView.builder(
                        itemCount: locations.length,
                        itemBuilder: (context, index) {
                            return Card(
                                child: ListTile(
                                    onTap: () {},
                                    title: Text(locations[index].location),
                                    subtitle: Text(locations[index].country),
                                ),
                            ),
                        },
                    ),
                ),
            ],
        ),
    ),
}

Widget buildSearch() => SearchWidget(
    text: query,
    hintText: 'Search for location',
    onChanged: searchLocation,
);

void searchLocation(String query) async {
    // currently only search in titles (need to add subtitle as well)
    final newLocations = locations.where((location) {
        final nameLower = location.location.toLowerCase();
        final searchLower = query.toLowerCase();
        return nameLower.contains(searchLower);
    }).toList();

    // when user clear search or remove letters list wont back to it's default
    setState(() {
        this.query = query;
        this.locations = newLocations;
    });
}

有什么建议吗?

更新

这是我的 SearchWidget 文件(以防万一)

class SearchWidget extends StatefulWidget {
  final String text;
  final ValueChanged<String> onChanged;
  final String hintText;

  const SearchWidget({
    Key key,
    this.text,
    this.onChanged,
    this.hintText,
  }) : super(key: key);

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

class _SearchWidgetState extends State<SearchWidget> {
  final controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final styleActive = TextStyle(color: Colors.black);
    final styleHint = TextStyle(color: Colors.black54);
    final style = widget.text.isEmpty ? styleHint : styleActive;

    return Container(
      height: 42,
      margin: const EdgeInsets.fromLTRB(16, 16, 16, 16),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(12),
        color: Colors.white,
        border: Border.all(color: Colors.black26),
      ),
      padding: const EdgeInsets.symmetric(horizontal: 8),
      child: TextField(
        controller: controller,
        decoration: InputDecoration(
          icon: Icon(Icons.search, color: style.color),
          suffixIcon: widget.text.isNotEmpty
              ? GestureDetector(
            child: Icon(Icons.close, color: style.color),
            onTap: () {
              controller.clear();
              widget.onChanged('');
              FocusScope.of(context).requestFocus(FocusNode());
            },
          )
              : null,
          hintText: widget.hintText,
          hintStyle: style,
          border: InputBorder.none,
        ),
        style: style,
        onChanged: widget.onChanged,
      ),
    );
  }
}

更新 2

我已经设法在我的逻辑中修复了 #2 并通过以下代码获得了包含搜索结果的字幕(清晰的搜索问题仍然存在)

void searchLocation(String query) async {
    final newLocations = locations.where((location) {
      final nameLower = location.location.toLowerCase();
      final countryLower = location.country.toLowerCase(); // added
      final searchLower = query.toLowerCase();
      return nameLower.contains(searchLower) || countryLower.contains(searchLower); //changed
    }).toList();

    setState(() {
      this.query = query;
      this.locations = newLocations;
    });
  }

注意:

我已接受 Yair Chen 答案,但我需要澄清一些问题以解决此问题:

根据 Yair Chen 答案,我必须创建新列表 List<World> filteredLocations = [];

然后在我的 ListView.builder 中,我更改了 itemCountchild,如下所示:

ListView.builder(
  itemCount: filteredLocations.isNotEmpty ? filteredLocations.length : locations.length,
  //...
  child: filteredLocations.isNotEmpty ? card(... //filteredLocations[index].location//...) : Card(... //locations[index].location// ...),

通过这种方式解决了过滤结果的索引问题,卡片数据将获取有关它们返回的列表的数据。

1 个答案:

答案 0 :(得分:0)

您可以添加另一个名为 filtersLocations 的列表,然后将新列表保存到过滤位置。函数 .where() 也会更改您不想要的原始列表。您可以浅复制(使用扩展运算符)列表,然后创建一个与查询匹配的新列表,如下所示:

void searchLocation(String query) async {
    // currently only search in titles (need to add subtitle as well)
    // [...locations] copies the list to not change original list
    final newLocations = [...locations].where((location) {
        final nameLower = location.location.toLowerCase();
        final searchLower = query.toLowerCase();

        // Also adding subtitle check (whether the name contains it or the subtitle does
        return nameLower.contains(searchLower) || location.subtitle.toLowerCase().contains(searchLower);
    }).toList();

    // when user clear search or remove letters list wont back to it's default
    setState(() {
        this.query = query;
        this.filteredLocations = newLocations;
    });
}

这样原始列表永远不会改变,只有filteredList会被更新。它还将解决当字符串为空时您希望所有项目都出现的问题。

祝您好运,如果您需要其他任何东西,请告诉我:)