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

如何在Flutter中实现图片的动态颜色填充效果?

Flutter实现图片空白区域流畅颜色填充效果的方案

针对你想要的图片空白区域颜色流畅填充效果,这里提供几种实用的实现思路:

一、自定义绘制实现扩散填充动画

适合需要从指定点开始扩散填充的场景,核心用CustomPaint结合动画控制器实现:

  1. 核心逻辑:

    • 先绘制原始图片
    • 通过AnimationController控制填充进度,逐帧绘制填充区域,利用混合模式只填充图片的空白(透明)部分
  2. 示例代码:

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

class FillAnimationWidget extends StatefulWidget {
  final String imageAsset;
  final Color fillColor;
  final Offset startFillPoint;

  const FillAnimationWidget({
    super.key,
    required this.imageAsset,
    required this.fillColor,
    required this.startFillPoint,
  });

  @override
  State<FillAnimationWidget> createState() => _FillAnimationWidgetState();
}

class _FillAnimationWidgetState extends State<FillAnimationWidget> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late ui.Image _image;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this,
    )..forward();
    _loadImage();
  }

  Future<void> _loadImage() async {
    final bytes = await DefaultAssetBundle.of(context).load(widget.imageAsset);
    _image = await ui.decodeImageFromList(bytes.buffer.asUint8List());
    setState(() {});
  }

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

  @override
  Widget build(BuildContext context) {
    if (_image == null) return const SizedBox.shrink();
    return CustomPaint(
      size: Size(_image.width.toDouble(), _image.height.toDouble()),
      painter: _FillPainter(
        animation: _controller,
        image: _image,
        fillColor: widget.fillColor,
        startPoint: widget.startFillPoint,
      ),
    );
  }
}

class _FillPainter extends CustomPainter {
  final Animation<double> animation;
  final ui.Image image;
  final Color fillColor;
  final Offset startPoint;

  _FillPainter({
    required this.animation,
    required this.image,
    required this.fillColor,
    required this.startPoint,
  }) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    // 绘制原始图片
    canvas.drawImage(image, Offset.zero, Paint());

    // 计算填充半径,随动画进度扩大
    final fillRadius = animation.value * size.longestSide;

    // 创建填充画笔,只填充图片透明区域
    final fillPaint = Paint()
      ..color = fillColor.withOpacity(0.9)
      ..blendMode = BlendMode.dstOut;

    // 绘制填充的圆形区域,可根据需求修改为其他形状/路径
    canvas.drawCircle(startPoint, fillRadius, fillPaint);
  }

  @override
  bool shouldRepaint(_FillPainter oldDelegate) {
    return animation.value != oldDelegate.animation.value;
  }
}
  1. 使用方式:
    将组件嵌入页面,传入对应参数即可:
FillAnimationWidget(
  imageAsset: 'assets/your_empty_image.png',
  fillColor: Colors.blue,
  startFillPoint: const Offset(50, 50),
)

二、SVG图片填充动画(更简便)

如果你的图片是SVG格式,用flutter_svg库可快速实现路径填充动画:

  1. 添加依赖:
    在pubspec.yaml中加入:
dependencies:
  flutter_svg: ^2.0.7
  1. 示例代码:
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

class SvgFillAnimation extends StatefulWidget {
  final String svgPath;
  final Color fillColor;

  const SvgFillAnimation({super.key, required this.svgPath, required this.fillColor});

  @override
  State<SvgFillAnimation> createState() => _SvgFillAnimationState();
}

class _SvgFillAnimationState extends State<SvgFillAnimation> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return SvgPicture.asset(
      widget.svgPath,
      colorFilter: ColorFilter.mode(widget.fillColor, BlendMode.srcIn),
      fit: BoxFit.contain,
    ).animate(
      const Duration(seconds: 2),
      curve: Curves.easeInOut,
    ).stretch(
      alignment: Alignment.centerLeft,
      value: Tween<double>(begin: 0, end: 1).animate(_controller),
    );
  }
}

三、蒙版过渡填充

如果是整体渐变填充效果,可通过Stack结合AnimatedContainer和蒙版实现:

  • 将图片作为底层,上层放置AnimatedContainer,用ClipPath裁剪出图片的空白区域,通过动画改变容器的颜色透明度或宽度,实现填充效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 14:40:26