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

基于Flutter TextField构建支持语法高亮与行号的可编辑代码编辑器技术求助

实现带行号的可编辑代码TextField方案

我之前在做Flutter代码编辑器需求时也遇到过类似问题,给你分享几个经过验证的可行方案:


方案一:Row嵌套行号列表与TextField,同步滚动

这是最灵活的自定义实现方式,完全可控:

  • 核心思路:把行号展示区域和TextField放在同一个Row中,共享同一个ScrollController来实现滚动同步,同时监听文本变化实时更新行号数量。
  • 具体步骤:
    1. 初始化两个控制器:TextEditingController用于管理输入文本,ScrollController用于同步行号和代码区域的滚动。
    2. 行号区域用ListView.builder构建,根据当前文本的实际行数动态生成行号(注意要处理自动换行的情况,不能只靠换行符分割)。
    3. 监听TextEditingController的文本变化,用TextPainter计算实际渲染的行数(因为TextField中长文本会自动换行,行数不等于换行符数量)。
    4. 将行号列表和TextField都放在Row中,设置crossAxisAlignment: CrossAxisAlignment.stretch保证两者高度一致。

示例代码片段:

class CodeEditor extends StatefulWidget {
  @override
  _CodeEditorState createState() => _CodeEditorState();
}

class _CodeEditorState extends State<CodeEditor> {
  final TextEditingController _textController = TextEditingController();
  final ScrollController _scrollController = ScrollController();
  int _lineCount = 1;

  @override
  void initState() {
    super.initState();
    _textController.addListener(_updateLineCount);
    _updateLineCount();
  }

  void _updateLineCount() {
    final text = _textController.text;
    final textPainter = TextPainter(
      text: TextSpan(text: text, style: TextStyle(fontSize: 14)),
      maxLines: null,
      textDirection: TextDirection.ltr,
    )..layout(maxWidth: MediaQuery.of(context).size.width - 60); // 减去行号区域宽度
    setState(() {
      _lineCount = textPainter.lineCount;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        // 行号区域
        Container(
          width: 50,
          color: Colors.grey[100],
          child: ListView.builder(
            controller: _scrollController,
            itemCount: _lineCount,
            itemBuilder: (context, index) {
              return Padding(
                padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                child: Text(
                  '${index + 1}',
                  style: TextStyle(color: Colors.grey[600], fontSize: 14),
                ),
              );
            },
          ),
        ),
        // 代码输入区域
        Expanded(
          child: TextField(
            controller: _textController,
            scrollController: _scrollController,
            maxLines: null,
            expands: true,
            decoration: InputDecoration(
              border: InputBorder.none,
              contentPadding: EdgeInsets.all(8),
            ),
            style: TextStyle(fontSize: 14, fontFamily: 'Monospace'),
          ),
        ),
      ],
    );
  }
}

方案二:自定义TextField装饰,绘制行号

如果不想额外嵌套Widget,可以通过自定义InputDecoration或者直接用CustomPaint在TextField左侧绘制行号:

  • 核心思路:利用TextField的decoration属性,通过prefix或者自定义背景绘制行号,监听文本变化更新行号。
  • 优势:布局更紧凑,不需要额外的ListView,适合简单场景。
  • 注意点:需要精确计算行号的位置,确保和每一行代码对齐,同时要给TextField设置足够的左侧padding,避免文字覆盖行号。

方案三:使用支持编辑的代码编辑器库

如果不想重复造轮子,可以直接用现成的支持编辑和行号的库:

  • 比如flutter_code_editor,它内置了行号显示、语法高亮、代码折叠等功能,而且支持实时编辑,完美替代只能展示的flutter_syntax_view。
  • 使用方式也很简单,只需要配置控制器和基础参数就能开启行号功能,节省大量自定义开发时间。

额外注意事项

  • 计算行数时,一定要用TextPainter来计算实际渲染行数,而不是单纯按换行符分割,否则会忽略自动换行的情况。
  • 行号区域建议用浅色背景和灰色文字,和代码区域形成视觉区分,提升可读性。
  • 同步滚动时,确保行号列表和TextField的滚动行为完全一致,避免出现滚动偏移。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:32:52