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

gk7wooem  于 2023-02-25  发布在  Flutter
关注(0)|答案(4)|浏览(95)

我突出显示了这个词,但不是正确的词。
在我的BuilderSuggection中,我添加了这样的代码,

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))
          ])),
lokaqttq

lokaqttq1#

我编写了一个快速函数,它返回TextSpan的List。
函数将查询字符串与源字符串进行匹配,逐一枚举匹配项,将源字符串切割为多个片段:匹配前、匹配后和匹配本身-使其加粗。
它旨在用于RichText小工具。

List<TextSpan> highlightOccurrences(String source, String query) {
  if (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),
  ),
),

如果有帮助就告诉我。

kx1ctssn

kx1ctssn2#

根据@乔治的答案,有一个类似的功能,唯一的区别是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;
}

其用法与@乔治's answer的用法相同:

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

zzwlnbp83#

很抱歉我很晚才回答,但我也想对这种“问题”给予支持。
我想找到一种不同的方法,而且我没有使用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),
          );
yizd12fk

yizd12fk4#

//hight light occurrentces
    List<TextSpan> _highlightOccurrences(String text, String query) {
      final List<TextSpan> spans = [];
      final String lowercaseText = text.toLowerCase();
      final String lowercaseQuery = query.toLowerCase();
    
      int lastIndex = 0;
      int index = lowercaseText.indexOf(lowercaseQuery);
    
      while (index != -1) {
        spans.add(TextSpan(text: text.substring(lastIndex, index)));
        spans.add(TextSpan(text: text.substring(index, index + query.length), style: const TextStyle(fontWeight: FontWeight.bold)));
        lastIndex = index + query.length;
        index = lowercaseText.indexOf(lowercaseQuery, lastIndex);
      }
    
      spans.add(TextSpan(text: text.substring(lastIndex, text.length)));
    
      return spans;
    }


using:

    @override
      Widget buildSuggestions(BuildContext context) {
        final suggestions = lstString.where((name) {
          return name.toLowerCase().contains(query.toLowerCase());
        }).toList();
    
        //limit suggest
        const int limitSuggest = 5;
        if (suggestions.length > limitSuggest) {
          suggestions.removeRange(limitSuggest, suggestions.length);
        }
    
        return ListView.builder(
          itemCount: suggestions.length,
          itemBuilder: (BuildContext context, int index) {
            return ListTile(
              title: query.isEmpty
                  ? Text(
                      suggestions.elementAt(index),
                    )
                  : RichText(
                      text: TextSpan(
                          children: _highlightOccurrences(suggestions[index], query), style: TextStyle(color: Theme.of(context).colorScheme.onSurface)),
                    ),
              onTap: () => query = suggestions.elementAt(index),
            );
          },
        );

  }

相关问题