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

如何在Flutter中实现示例动图所示的星光闪烁动画效果?

Flutter 星光闪烁动画实现方案

星光闪烁动画示例

这个效果由多个随机位置、随机大小、随机闪烁周期的发光光点组成,每个光点独立执行「淡入-淡出+轻微缩放」的循环动画,整体叠加后就形成了自然的星光闪烁效果,不需要引入第三方依赖,用Flutter自带的动画和绘制能力即可实现。


1. 定义星光属性模型

首先创建数据类存储单个星光的配置参数,所有参数初始化时随机生成,保证每个星光的运动规律不同:

class Star {
  // 星光在画布上的坐标
  double x;
  double y;
  // 星光基础大小
  double size;
  // 单次闪烁动画的周期(毫秒)
  int duration;
  // 动画延迟启动时间(毫秒,避免所有星光同步闪烁)
  int delay;
  // 当前动画的透明度值
  double opacity = 0;
  // 当前动画的缩放比例
  double scale = 1.0;

  Star({
    required this.x,
    required this.y,
    required this.size,
    required this.duration,
    required this.delay,
  });
}

2. 初始化动画控制器与星光列表

在State类中混入SingleTickerProviderStateMixin,初始化时生成随机的星光列表,启动循环动画:

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

class TwinkleStars extends StatefulWidget {
  // 星光数量
  final int starCount;
  // 画布大小
  final Size size;

  const TwinkleStars({
    super.key,
    this.starCount = 30,
    required this.size,
  });

  @override
  State<TwinkleStars> createState() => _TwinkleStarsState();
}

class _TwinkleStarsState extends State<TwinkleStars> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  final List<Star> _stars = [];
  final Random _random = Random();

  @override
  void initState() {
    super.initState();
    // 初始化动画控制器,16ms刷新一次匹配屏幕帧率
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 16),
    )..repeat();

    // 生成随机星光数据
    for (int i = 0; i < widget.starCount; i++) {
      _stars.add(Star(
        x: _random.nextDouble() * widget.size.width,
        y: _random.nextDouble() * widget.size.height,
        size: 2 + _random.nextDouble() * 6,
        duration: 800 + _random.nextInt(1200),
        delay: _random.nextInt(1000),
      ));
    }

    // 动画每帧更新星光的透明度和缩放值
    _controller.addListener(() {
      final now = DateTime.now().millisecondsSinceEpoch;
      for (var star in _stars) {
        // 计算当前动画进度,循环播放
        double progress = ((now + star.delay) % star.duration) / star.duration;
        // 用easeInOut曲线让淡入淡出更自然
        if (progress < 0.5) {
          star.opacity = Curves.easeIn.transform(progress * 2);
          star.scale = 1 + progress * 0.3;
        } else {
          star.opacity = Curves.easeOut.transform((1 - progress) * 2);
          star.scale = 1 + (1 - progress) * 0.3;
        }
      }
      setState(() {});
    });
  }

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

3. 自定义Painter绘制星光

用CustomPainter绘制所有星光,此处实现四芒星形匹配示例效果,也可简化为带模糊的圆形光点:

@override
  Widget build(BuildContext context) {
    return CustomPaint(
      size: widget.size,
      painter: StarPainter(stars: _stars),
    );
  }
}

class StarPainter extends CustomPainter {
  final List<Star> stars;
  // 星光画笔,加模糊效果模拟发光
  final Paint _starPaint = Paint()
    ..imageFilter = ImageFilter.blur(sigmaX: 1.2, sigmaY: 1.2)
    ..color = Colors.white;

  StarPainter({required this.stars});

  @override
  void paint(Canvas canvas, Size size) {
    for (var star in stars) {
      _starPaint.color = Colors.white.withOpacity(star.opacity);
      // 绘制四芒星光
      Path starPath = Path();
      double halfSize = star.size * star.scale / 2;
      // 上下左右四个顶点
      starPath.moveTo(star.x, star.y - halfSize);
      starPath.lineTo(star.x + halfSize * 0.3, star.y - halfSize * 0.3);
      starPath.lineTo(star.x + halfSize, star.y);
      starPath.lineTo(star.x + halfSize * 0.3, star.y + halfSize * 0.3);
      starPath.lineTo(star.x, star.y + halfSize);
      starPath.lineTo(star.x - halfSize * 0.3, star.y + halfSize * 0.3);
      starPath.lineTo(star.x - halfSize, star.y);
      starPath.lineTo(star.x - halfSize * 0.3, star.y - halfSize * 0.3);
      starPath.close();
      canvas.drawPath(starPath, _starPaint);
    }
  }

  @override
  bool shouldRepaint(covariant StarPainter oldDelegate) => true;
}

使用方法

直接在页面中放置TwinkleStars组件,作为背景层放在Stack里即可实现示例效果:

Stack(
  children: [
    // 深色背景层
    Container(color: const Color(0xFF1A1A2E)),
    // 星光层
    const TwinkleStars(size: Size(375, 812)),
    // 其他上层业务内容
  ]
)

可选优化项

  • 星光数量多的时候可以给CustomPaint包裹RepaintBoundary,避免和页面其他组件一起重绘,提升性能
  • 可以随机给星光设置淡白、淡黄、淡蓝等低饱和度颜色,效果更有层次感
  • 给星光增加极慢的横向/纵向位移,模拟星光缓慢飘动的效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 20:36:03