| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- import 'package:flutter/cupertino.dart';
- import 'package:flutter/material.dart';
- class HighlightSearchText extends StatefulWidget {
- final String text; // 原始文本
- final String searchKeyword; // 搜索关键字
- final int? defaultHighlightIndex; // 默认高亮的索引位置
- final TextStyle normalTextStyle; // 普通文本样式
- final TextStyle highlightTextStyle; // 高亮文本样式
- final TextStyle activeHighlightTextStyle; // 定位高亮文本样式
- final ValueChanged<Map<String, int>>? onHighlightChanged; // 高亮变化时的回调
- const HighlightSearchText({
- super.key,
- required this.text,
- required this.searchKeyword,
- this.defaultHighlightIndex,
- this.onHighlightChanged,
- this.normalTextStyle = const TextStyle(color: Colors.black, fontSize: 16),
- this.highlightTextStyle = const TextStyle(
- color: Colors.white, backgroundColor: Colors.orange, fontSize: 16),
- this.activeHighlightTextStyle = const TextStyle(
- color: Colors.white, backgroundColor: Colors.red, fontSize: 16),
- });
- @override
- State<HighlightSearchText> createState() => _HighlightSearchTextState();
- static int getHighlightTotal(String targetTxt, String searchKeyword) {
- if (searchKeyword.isEmpty || targetTxt.isEmpty) {
- return 0;
- }
- int count = 0;
- int start = 0;
- while (true) {
- int index = targetTxt.indexOf(searchKeyword, start);
- if (index < 0) break;
- count++;
- start = index + searchKeyword.length;
- }
- return count;
- }
- }
- class _HighlightSearchTextState extends State<HighlightSearchText> {
- List<int> matchIndices = []; // 记录所有匹配的位置
- int currentHighlightIndex = -1; // 当前高亮的索引
- @override
- void initState() {
- super.initState();
- currentHighlightIndex = widget.defaultHighlightIndex ?? -1;
- _updateMatchIndices();
- }
- @override
- Widget build(BuildContext context) {
- return RichText(
- text: _buildHighlightedText(),
- );
- }
- @override
- void didUpdateWidget(covariant HighlightSearchText oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (widget.text != oldWidget.text ||
- widget.searchKeyword != oldWidget.searchKeyword ||
- widget.defaultHighlightIndex != oldWidget.defaultHighlightIndex) {
- currentHighlightIndex = widget.defaultHighlightIndex ?? -1;
- // debugPrint(
- // 'HighlightSearchText currentHighlightIndex:$currentHighlightIndex '
- // 'defaultHighlightIndex:${widget.defaultHighlightIndex} '
- // 'matchIndices:${matchIndices.length} '
- // 'text:${widget.text} '
- // ' searchKeyword:${widget.searchKeyword}');
- _updateMatchIndices();
- _notifyHighlightChanged();
- }
- }
- void _notifyHighlightChanged() {
- if (widget.onHighlightChanged != null) {
- widget.onHighlightChanged!({
- 'current': currentHighlightIndex + 1, // 当前高亮位置,1-based
- 'total': matchIndices.length, // 总匹配数量
- });
- }
- }
- void _updateMatchIndices() {
- matchIndices.clear();
- if (widget.searchKeyword.isEmpty) return;
- String textLower = widget.text.toLowerCase(); // 将原文本转换为小写
- String keywordLower = widget.searchKeyword.toLowerCase(); // 将搜索关键字转换为小写
- int start = 0;
- while (true) {
- int index = textLower.indexOf(keywordLower, start); // 在小写文本中进行匹配
- if (index < 0) break;
- matchIndices.add(index);
- start = index + widget.searchKeyword.length;
- }
- }
- TextSpan _buildHighlightedText() {
- if (widget.searchKeyword.isEmpty) {
- // 如果没有搜索关键词,返回原始文本
- return TextSpan(
- text: widget.text,
- style: widget.normalTextStyle,
- );
- }
- List<TextSpan> spans = [];
- int start = 0;
- for (int i = 0; i < matchIndices.length; i++) {
- int index = matchIndices[i];
- // 添加普通文本部分
- if (index > start) {
- spans.add(TextSpan(
- text: widget.text.substring(start, index),
- style: widget.normalTextStyle,
- ));
- }
- // 添加高亮文本部分
- spans.add(TextSpan(
- text: widget.text.substring(index, index + widget.searchKeyword.length),
- style: i == currentHighlightIndex
- ? widget.activeHighlightTextStyle // 当前定位的高亮颜色
- : widget.highlightTextStyle, // 普通高亮颜色
- ));
- start = index + widget.searchKeyword.length;
- }
- // 添加剩余普通文本部分
- if (start < widget.text.length) {
- spans.add(TextSpan(
- text: widget.text.substring(start),
- style: widget.normalTextStyle,
- ));
- }
- return TextSpan(children: spans);
- }
- }
|