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

如何在Flutter中实现文字内嵌图片的效果?

Flutter实现图片填充文字效果的方案

方法一:使用ShaderMask组件(推荐)

这是实现图片填充文字最简洁高效的方式,无需额外PNG资源,直接通过着色器将图片纹理映射到文字上。

示例代码:

import 'dart:ui' as ui;
import 'package:flutter/material.dart';

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

  @override
  State<ImageFillText> createState() => _ImageFillTextState();
}

class _ImageFillTextState extends State<ImageFillText> {
  ui.Image? _image;

  @override
  void initState() {
    super.initState();
    _loadImage();
  }

  Future<void> _loadImage() async {
    final bytes = await DefaultAssetBundle.of(context).load('assets/palm_tree.jpg');
    _image = await decodeImageFromList(bytes.buffer.asUint8List());
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _image == null
            ? const CircularProgressIndicator()
            : ShaderMask(
                blendMode: BlendMode.srcIn,
                shaderCallback: (bounds) => ImageShader(
                  _image!,
                  TileMode.repeated,
                  TileMode.repeated,
                  Matrix4.identity().storage,
                ),
                child: const Text(
                  'Hawaii',
                  style: TextStyle(
                    fontSize: 120,
                    fontWeight: FontWeight.bold,
                    color: Colors.white, // 该颜色会被Shader覆盖,可随意设置
                  ),
                ),
              ),
      ),
    );
  }
}

代码说明:

  • BlendMode.srcIn会保留子组件(文字)的形状,用指定Shader填充内容
  • ImageShader将加载的图片作为纹理,TileMode.repeated可让图片在文字内部重复填充,也可改用TileMode.clamp只显示一次
  • 需异步加载图片,避免阻塞UI

方法二:使用CustomPaint自定义绘制

如果需要更复杂的自定义逻辑(比如调整图片在文字中的位置、缩放比例),可以用CustomPaint手动实现:

示例代码:

import 'dart:ui' as ui;
import 'package:flutter/material.dart';

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

  @override
  State<CustomImageFillText> createState() => _CustomImageFillTextState();
}

class _CustomImageFillTextState extends State<CustomImageFillText> {
  ui.Image? _image;
  final TextPainter _textPainter = TextPainter(
    text: const TextSpan(
      text: 'Hawaii',
      style: TextStyle(
        fontSize: 120,
        fontWeight: FontWeight.bold,
      ),
    ),
    textDirection: TextDirection.ltr,
  );

  @override
  void initState() {
    super.initState();
    _loadImage();
    _textPainter.layout();
  }

  Future<void> _loadImage() async {
    final bytes = await DefaultAssetBundle.of(context).load('assets/palm_tree.jpg');
    _image = await decodeImageFromList(bytes.buffer.asUint8List());
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _image == null
            ? const CircularProgressIndicator()
            : CustomPaint(
                size: _textPainter.size,
                painter: _ImageTextPainter(
                  image: _image!,
                  textPainter: _textPainter,
                ),
              ),
      ),
    );
  }
}

class _ImageTextPainter extends CustomPainter {
  final ui.Image image;
  final TextPainter textPainter;

  _ImageTextPainter({required this.image, required this.textPainter});

  @override
  void paint(Canvas canvas, Size size) {
    // 获取文字路径作为裁剪区域
    final path = Path();
    textPainter.text.getPathForRange(0, textPainter.text.length, Offset.zero, path);

    // 保存画布状态,裁剪到文字路径
    canvas.save();
    canvas.clipPath(path);

    // 在裁剪区域内绘制图片
    final paint = Paint();
    canvas.drawImageRect(
      image,
      Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
      Rect.fromLTWH(0, 0, size.width, size.height),
      paint,
    );

    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant _ImageTextPainter oldDelegate) {
    return image != oldDelegate.image || textPainter != oldDelegate.textPainter;
  }
}

说明:

  • 先通过TextPainter获取文字路径,再用clipPath裁剪画布,最后在裁剪区域内绘制图片
  • 灵活性更高,但代码量比ShaderMask方案多

对比Stack叠PNG方案的不足

你之前用Stack叠加透明PNG的方式存在明显缺陷:

  • 需要额外制作带透明通道的文字图片,维护成本高
  • 修改文字大小、样式时需重新生成图片
  • 无法动态调整图片在文字内的填充方式(重复、拉伸等)

上面两种纯代码实现的方案,支持动态修改文字内容、大小、样式,图片也可随时替换,是更优的实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 07:31:14