如何在searchDelegate上突出显示正确的单词?

时间:2019-06-12 09:20:27

标签: flutter dart

我突出显示了该词,但未突出显示正确的词。

在我的BuilderSuggection中,我像这样添加了代码,

check my searchDelegate

 title: RichText(
          text: TextSpan(
              text: suggestList[index].d.substring(0, query.length),
              style: TextStyle(
                  color: Colors.black, fontWeight: FontWeight.bold),
              children: [
            TextSpan(
                text: suggestList[index].d.substring(query.length),
                style: TextStyle(color: Colors.grey))
          ])),

3 个答案:

答案 0 :(得分:1)

我编写了一个快速函数,该函数返回TextSpan的列表。

函数将查询字符串与源字符串进行匹配,逐一枚举匹配项,将源字符串切成小块:在匹配之前,在匹配之后以及匹配本身-使其加粗。

它打算在RichText小部件中使用。

List<TextSpan> highlightOccurrences(String source, String query) {
  if (query == null || query.isEmpty || !source.toLowerCase().contains(query.toLowerCase())) {
    return [ TextSpan(text: source) ];
  }
  final matches = query.toLowerCase().allMatches(source.toLowerCase());

  int lastMatchEnd = 0;

  final List<TextSpan> children = [];
  for (var i = 0; i < matches.length; i++) {
    final match = matches.elementAt(i);

    if (match.start != lastMatchEnd) {
      children.add(TextSpan(
        text: source.substring(lastMatchEnd, match.start),
      ));
    }

    children.add(TextSpan(
      text: source.substring(match.start, match.end),
      style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
    ));

    if (i == matches.length - 1 && match.end != source.length) {
      children.add(TextSpan(
        text: source.substring(match.end, source.length),
      ));
    }

    lastMatchEnd = match.end;
  }
  return children;
}

基于您的代码的示例:

RichText(
  text: TextSpan(
    children: highlightOccurrences(suggestList[index].d, query),
    style: TextStyle(color: Colors.grey),
  ),
),

让我知道这是否有帮助。

答案 1 :(得分:1)

基于@George的答案,有一个类似的函数,唯一的区别是query首先被空格分开,然后每个单独的单词被高亮显示。我花了一段时间才能使其正常工作,所以为什么不分享:

List<TextSpan> highlightOccurrences(String source, String query) {
  if (query == null || query.isEmpty) {
    return [TextSpan(text: source)];
  }

  var matches = <Match>[];
  for (final token in query.trim().toLowerCase().split(' ')) {
    matches.addAll(token.allMatches(source.toLowerCase()));
  }

  if (matches.isEmpty) {
    return [TextSpan(text: source)];
  }
  matches.sort((a, b) => a.start.compareTo(b.start));

  int lastMatchEnd = 0;
  final List<TextSpan> children = [];
  for (final match in matches) {
    if (match.end <= lastMatchEnd) {
      // already matched -> ignore
    } else if (match.start <= lastMatchEnd) {
      children.add(TextSpan(
        text: source.substring(lastMatchEnd, match.end),
        style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
      ));
    } else if (match.start > lastMatchEnd) {
      children.add(TextSpan(
        text: source.substring(lastMatchEnd, match.start),
      ));

      children.add(TextSpan(
        text: source.substring(match.start, match.end),
        style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
      ));
    }

    if (lastMatchEnd < match.end) {
      lastMatchEnd = match.end;
    }
  }

  if (lastMatchEnd < source.length) {
    children.add(TextSpan(
      text: source.substring(lastMatchEnd, source.length),
    ));
  }

  return children;
}

用法与@George的答案相同:

RichText(
  text: TextSpan(
    children: highlightOccurrences(suggestList[index].d, query),
    style: TextStyle(color: Colors.grey),
  ),
),

答案 2 :(得分:0)

很抱歉,我的回答很晚,但是我也想支持这种“问题”。

我想找到一种不同的方法,并且在不使用if语句的情况下找到了解决方法,这看起来很不错,甚至可能更易于管理。 我认为“建议字符串”在最坏的情况下分为3个子字符串:侧面2个字符串,中间1个字符串。您可以想象,中心的是“大胆”的一个。而已! 如果没有对应关系,则建议框中显然不会显示任何结果。 我直接复制并粘贴了我使用的相同代码。

return ListView.builder(
        itemCount: _posts.length,
        itemBuilder: (context, index) {
          int startIndex = _posts[index].title.toLowerCase().indexOf(query.toLowerCase());
          return ListTile(
            title: query.isEmpty
                ? Text(_posts[index].title)
                : RichText(
                    text: TextSpan(
                    text: _posts[index].title.substring(0, startIndex),
                    style: TextStyle(color: Colors.grey),
                    children: [
                      TextSpan(
                        text: _posts[index]
                            .title
                            .substring(startIndex, startIndex + query.length),
                        style: TextStyle(
                            fontWeight: FontWeight.bold, color: Colors.black),
                      ),
                      TextSpan(
                        text: _posts[index]
                            .title
                            .substring(startIndex + query.length),
                        style: TextStyle(color: Colors.grey),
                      )
                    ],
                  )),
            subtitle: Text(_posts[index].date),
          );