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

Flutter启动页心跳水平线条动画实现问题咨询

解决方案:实现心跳式水平线条启动页动画

我明白你想要的是那种从屏幕左侧中心开始向右延伸的心跳式水平线条动画,并且在应用初始数据加载完成前持续循环播放。你的现有代码是实现圆形脉冲效果的,和需求不匹配,我来帮你调整代码实现这个效果:

完整实现代码

import 'package:flutter/material.dart';

class HeartbeatLinePainter extends CustomPainter {
  final Animation<double> _animation;
  final Color _lineColor;
  final double _lineThickness;

  HeartbeatLinePainter(
    this._animation, {
    Color lineColor = const Color.fromRGBO(0, 117, 194, 1.0),
    double lineThickness = 4.0,
  })  : _lineColor = lineColor,
        _lineThickness = lineThickness,
        super(repaint: _animation);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = _lineColor
      ..strokeWidth = _lineThickness
      ..strokeCap = StrokeCap.round; // 让线条两端圆润,更美观

    // 线条起始点:屏幕左侧垂直中心
    final startPoint = Offset(0, size.height / 2);
    // 线条结束点:根据动画值动态计算水平位置
    final endX = size.width * _animation.value;
    final endPoint = Offset(endX, size.height / 2);

    canvas.drawLine(startPoint, endPoint, paint);
  }

  @override
  bool shouldRepaint(HeartbeatLinePainter oldDelegate) {
    return _animation != oldDelegate._animation ||
        _lineColor != oldDelegate._lineColor ||
        _lineThickness != oldDelegate._lineThickness;
  }
}

class SplashScreen extends StatefulWidget {
  // 模拟数据加载完成的回调,实际项目中替换为真实的加载逻辑
  final VoidCallback onLoadComplete;

  const SplashScreen({super.key, required this.onLoadComplete});

  @override
  SplashScreenState createState() => SplashScreenState();
}

class SplashScreenState extends State<SplashScreen>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  late final Animation<double> _heartbeatAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1600), // 调整动画周期
    );

    // 构建心跳式动画序列:延伸→轻微收缩→恢复,循环播放
    _heartbeatAnimation = TweenSequence([
      TweenSequenceItem(
        tween: Tween<double>(begin: 0, end: 1).chain(CurveTween(curve: Curves.easeInOut)),
        weight: 0.7, // 70%时间用于线条从左到右延伸
      ),
      TweenSequenceItem(
        tween: Tween<double>(begin: 1, end: 0.92).chain(CurveTween(curve: Curves.easeOut)),
        weight: 0.15, // 15%时间轻微收缩线条
      ),
      TweenSequenceItem(
        tween: Tween<double>(begin: 0.92, end: 1).chain(CurveTween(curve: Curves.easeIn)),
        weight: 0.15, // 15%时间恢复到完整长度
      ),
    ]).animate(_controller);

    // 启动循环动画
    _controller.repeat();

    // 模拟数据加载,实际项目替换为真实的API请求/本地数据读取
    Future.delayed(const Duration(seconds: 3), () {
      _controller.stop(); // 加载完成后停止动画
      widget.onLoadComplete(); // 跳转到主页
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white, // 启动页背景色,可根据需求修改
      body: Center(
        child: SizedBox(
          width: MediaQuery.of(context).size.width * 0.8, // 线条宽度占屏幕80%,可调整
          height: 20, // 容器高度,只要能容纳线条即可
          child: CustomPaint(
            painter: HeartbeatLinePainter(_heartbeatAnimation),
          ),
        ),
      ),
    );
  }
}

// 主函数示例
void main() {
  runApp(const MaterialApp(
    home: SplashScreen(
      onLoadComplete: () {
        // 这里替换为跳转到主页的逻辑
        print("数据加载完成,跳转到主页");
      },
    ),
  ));
}

关键实现说明

  • 自定义画笔HeartbeatLinePainter:专门负责绘制水平线条,线条从屏幕左侧垂直中心出发,根据动画值动态调整右端点位置,同时使用StrokeCap.round让线条两端更圆润美观。
  • 心跳动画序列:通过TweenSequence实现了"延伸→收缩→恢复"的循环节奏,模拟心跳的波动感。你可以通过调整各阶段的weight值和动画时长来控制心跳的快慢和幅度。
  • 加载状态控制:动画默认循环播放,当数据加载完成后调用_controller.stop()停止动画,并触发页面跳转逻辑。
  • 可定制化:你可以修改线条颜色、粗细、动画周期、线条占屏幕宽度的比例等参数,适配你的应用设计风格。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 18:58:15