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

Flutter中如何在TextField的文本中间插入图片?

Flutter TextField 插入图文混排的实现方案

原生 TextField 仅支持纯文本输入,要实现图文混排效果,可通过以下两种方案实现:

一、使用第三方富文本编辑库(推荐:flutter_quill)

第三方库已封装好图文混排逻辑,上手快、功能完善,适合大多数场景。

步骤:

  1. 添加依赖到 pubspec.yaml:
dependencies:
  flutter_quill: ^latest_version # 替换为当前最新版本
  1. 实现示例代码:
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';

class RichTextEditor extends StatefulWidget {
  const RichTextEditor({super.key});

  @override
  State<RichTextEditor> createState() => _RichTextEditorState();
}

class _RichTextEditorState extends State<RichTextEditor> {
  final QuillController _controller = QuillController.basic();

  // 插入图片方法
  void insertImage() {
    // 替换为你的图片路径(本地资源/网络链接均可)
    const imageUrl = 'assets/images/demo.png';
    final delta = _controller.document.toDelta()..insert('\n', {'image': imageUrl});
    _controller.update(delta, ChangeSource.local);
    // 将光标移至图片后方
    _controller.moveCursorToPosition(_controller.selection.baseOffset + 1);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 自定义工具栏,添加插入图片按钮
        QuillToolbar.basic(
          controller: _controller,
          customButtons: [
            IconButton(
              icon: const Icon(Icons.image),
              onPressed: insertImage,
            ),
          ],
        ),
        // 富文本编辑区域
        Expanded(
          child: QuillEditor.basic(
            controller: _controller,
            readOnly: false,
            padding: const EdgeInsets.all(8),
          ),
        ),
      ],
    );
  }
}

二、自定义实现(基于 TextEditingController + RichText)

若不想依赖第三方库,可通过自定义逻辑实现:用特殊标记占位图片,再通过 RichText 渲染为图片组件。

核心思路:

  • 用特殊标记(如 [img:唯一标识])代表文本中的图片位置
  • 自定义 TextEditingController 管理文本,实现插入标记的方法
  • 通过 RichText 将标记替换为图片 Widget 渲染

示例代码:

import 'package:flutter/material.dart';

class ImageTextField extends StatefulWidget {
  const ImageTextField({super.key});

  @override
  State<ImageTextField> createState() => _ImageTextFieldState();
}

class _ImageTextFieldState extends State<ImageTextField> {
  final TextEditingController _controller = TextEditingController();
  final Map<String, String> _imageMap = {}; // 标记与图片路径的映射

  // 生成唯一图片标记
  String _createImageTag(String imageUrl) {
    final tag = '[img:${DateTime.now().microsecondsSinceEpoch}]';
    _imageMap[tag] = imageUrl;
    return tag;
  }

  // 在光标位置插入图片
  void insertImage(String imageUrl) {
    final tag = _createImageTag(imageUrl);
    final cursorPos = _controller.selection.baseOffset;
    final text = _controller.text;
    _controller.text = '${text.substring(0, cursorPos)}$tag${text.substring(cursorPos)}';
    // 移动光标到标记后方
    _controller.selection = TextSelection.fromPosition(
      TextPosition(offset: cursorPos + tag.length),
    );
  }

  // 将文本转换为带图片的 RichText
  Widget _buildRichContent() {
    final text = _controller.text;
    final spans = <TextSpan>[];
    int currentIndex = 0;

    while (currentIndex < text.length) {
      final imgStart = text.indexOf('[img:', currentIndex);
      if (imgStart == -1) {
        spans.add(TextSpan(text: text.substring(currentIndex)));
        break;
      }
      // 添加标记前的普通文本
      if (imgStart > currentIndex) {
        spans.add(TextSpan(text: text.substring(currentIndex, imgStart)));
      }
      // 找到标记结束位置
      final imgEnd = text.indexOf(']', imgStart);
      if (imgEnd == -1) {
        spans.add(TextSpan(text: text.substring(imgStart)));
        break;
      }
      final tag = text.substring(imgStart, imgEnd + 1);
      final imageUrl = _imageMap[tag];
      if (imageUrl != null) {
        // 渲染图片
        spans.add(WidgetSpan(
          child: SizedBox(
            width: 100,
            height: 100,
            child: Image.asset(imageUrl, fit: BoxFit.cover),
          ),
        ));
      } else {
        spans.add(TextSpan(text: tag));
      }
      currentIndex = imgEnd + 1;
    }

    return RichText(
      text: TextSpan(
        style: const TextStyle(color: Colors.black, fontSize: 16),
        children: spans,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: () => insertImage('assets/images/demo.png'),
          child: const Text('插入图片'),
        ),
        // 堆叠布局:用透明 TextField 处理输入焦点,RichText 显示图文内容
        Stack(
          children: [
            Padding(
              padding: const EdgeInsets.all(8),
              child: _buildRichContent(),
            ),
            TextField(
              controller: _controller,
              style: const TextStyle(color: Colors.transparent),
              decoration: const InputDecoration(
                border: InputBorder.none,
                hintStyle: TextStyle(color: Colors.transparent),
              ),
              cursorColor: Colors.black,
            ),
          ],
        ),
      ],
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 16:04:09