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

Flutter实现段落中选中单词高亮功能的替代方案咨询

Flutter 实现选中文本高亮的替代方案

RichText 是静态文本组件,不支持文本选中交互及选中回调,无法动态捕获用户选中的单词并更新高亮样式。推荐以下两种可行方案:

方案一:使用 SelectableText.rich 实现

利用 SelectableText.rich 支持富文本和选中回调的特性,动态更新选中区域的样式:

class HighlightSelectedText extends StatefulWidget {
  final String text;
  const HighlightSelectedText({super.key, required this.text});

  @override
  State<HighlightSelectedText> createState() => _HighlightSelectedTextState();
}

class _HighlightSelectedTextState extends State<HighlightSelectedText> {
  TextSelection? _selectedRange;

  @override
  Widget build(BuildContext context) {
    return SelectableText.rich(
      TextSpan(
        children: _buildHighlightedTextSpans(),
        style: const TextStyle(color: Colors.black),
      ),
      onSelectionChanged: (selection, cause) {
        setState(() {
          // 仅当选中有效文本时更新
          _selectedRange = selection.isValid ? selection : null;
        });
      },
    );
  }

  List<TextSpan> _buildHighlightedTextSpans() {
    final spans = <TextSpan>[];
    final text = widget.text;
    if (_selectedRange == null || !_selectedRange!.isValid) {
      spans.add(TextSpan(text: text));
      return spans;
    }

    // 拆分文本为未选中-选中-未选中三部分
    final start = _selectedRange!.start;
    final end = _selectedRange!.end;

    if (start > 0) {
      spans.add(TextSpan(text: text.substring(0, start)));
    }

    spans.add(TextSpan(
      text: text.substring(start, end),
      style: const TextStyle(
        backgroundColor: Colors.yellow,
        fontWeight: FontWeight.bold,
      ),
    ));

    if (end < text.length) {
      spans.add(TextSpan(text: text.substring(end)));
    }

    return spans;
  }
}

使用方式:

HighlightSelectedText(
  text: "这是一段用于测试选中文本高亮的示例段落,选中任意单词即可看到高亮效果。",
)

方案二:使用 EditableText(只读模式)

EditableText 是 TextField 的底层组件,支持更灵活的文本选中控制,设置为只读后可模拟静态文本的交互:

class EditableHighlightText extends StatefulWidget {
  final String text;
  const EditableHighlightText({super.key, required this.text});

  @override
  State<EditableHighlightText> createState() => _EditableHighlightTextState();
}

class _EditableHighlightTextState extends State<EditableHighlightText> {
  final TextEditingController _controller = TextEditingController();
  TextSelection? _selectedRange;

  @override
  void initState() {
    super.initState();
    _controller.text = widget.text;
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return EditableText(
      controller: _controller,
      readOnly: true,
      focusNode: FocusNode(),
      style: const TextStyle(color: Colors.black, fontSize: 16),
      cursorColor: Colors.transparent, // 隐藏光标
      backgroundCursorColor: Colors.transparent,
      onSelectionChanged: (selection, cause) {
        setState(() {
          _selectedRange = selection.isValid ? selection : null;
        });
      },
      // 自定义文本样式,高亮选中区域
      textSpan: TextSpan(
        children: _buildHighlightedSpans(),
        style: const TextStyle(color: Colors.black),
      ),
    );
  }

  List<TextSpan> _buildHighlightedSpans() {
    final text = _controller.text;
    if (_selectedRange == null || !_selectedRange!.isValid) {
      return [TextSpan(text: text)];
    }

    final start = _selectedRange!.start;
    final end = _selectedRange!.end;
    final spans = <TextSpan>[];

    if (start > 0) {
      spans.add(TextSpan(text: text.substring(0, start)));
    }

    spans.add(TextSpan(
      text: text.substring(start, end),
      style: const TextStyle(
        backgroundColor: Colors.lightBlueAccent,
        color: Colors.white,
      ),
    ));

    if (end < text.length) {
      spans.add(TextSpan(text: text.substring(end)));
    }

    return spans;
  }
}

方案对比

  • SelectableText.rich:更轻量,适合简单的文本选中高亮场景,无需额外控制器。
  • EditableText:支持更复杂的文本编辑特性(如自定义光标、文本样式),适合需要扩展交互的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 02:40:18