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

如何制作条纹背景动画?求Flutter按钮点击动画实现方案

一、条纹背景动画实现

可以通过CustomPainter结合AnimationController实现流动/滚动的条纹背景,以下是完整可运行示例:

import 'package:flutter/material.dart';

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

  @override
  State<StripedBackground> createState() => _StripedBackgroundState();
}

class _StripedBackgroundState extends State<StripedBackground> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _offsetAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this,
    )..repeat();
    _offsetAnimation = Tween<double>(begin: 0, end: 1).animate(_controller);
  }

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

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _offsetAnimation,
      builder: (context, child) {
        return CustomPaint(
          painter: StripedPainter(offset: _offsetAnimation.value),
          child: child,
        );
      },
      child: const Center(child: Text("条纹背景动画")),
    );
  }
}

class StripedPainter extends CustomPainter {
  final double offset;

  StripedPainter({required this.offset});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..style = PaintingStyle.fill
      ..shader = LinearGradient(
        colors: [Colors.grey.shade200, Colors.white, Colors.grey.shade200],
        stops: const [0.3, 0.5, 0.7],
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
        transform: GradientRotation(offset * 3.1415),
      ).createShader(Rect.fromLTWH(0, 0, size.width, size.height));

    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
  }

  @override
  bool shouldRepaint(covariant StripedPainter oldDelegate) {
    return oldDelegate.offset != offset;
  }
}

如果需要横向滚动的条纹,可修改渐变的transform为水平偏移,调整Tween范围即可。

二、按钮点击动画实现

你需要的点击扩散条纹波纹效果,无需第三方插件,用GestureDetector+Stack+AnimationController就能实现,示例如下:

import 'package:flutter/material.dart';

class StripedButton extends StatefulWidget {
  final String text;
  final VoidCallback onTap;

  const StripedButton({super.key, required this.text, required this.onTap});

  @override
  State<StripedButton> createState() => _StripedButtonState();
}

class _StripedButtonState extends State<StripedButton> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _scaleAnimation;
  late Animation<double> _opacityAnimation;
  Offset? _tapPosition;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 600),
      vsync: this,
    );
    _scaleAnimation = Tween<double>(begin: 0, end: 2).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeOut),
    );
    _opacityAnimation = Tween<double>(begin: 0.5, end: 0).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeOut),
    );
  }

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

  void _handleTapDown(TapDownDetails details) {
    setState(() {
      _tapPosition = details.localPosition;
    });
    _controller.reset();
    _controller.forward();
    widget.onTap();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: _handleTapDown,
      child: Stack(
        alignment: Alignment.center,
        children: [
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
            decoration: BoxDecoration(
              color: Colors.blue.shade500,
              borderRadius: BorderRadius.circular(8),
            ),
            child: Text(
              widget.text,
              style: const TextStyle(color: Colors.white, fontSize: 16),
            ),
          ),
          if (_tapPosition != null)
            AnimatedBuilder(
              animation: _controller,
              builder: (context, child) {
                return CustomPaint(
                  painter: RippleStripedPainter(
                    center: _tapPosition!,
                    radius: _scaleAnimation.value * MediaQuery.of(context).size.shortestSide,
                    opacity: _opacityAnimation.value,
                  ),
                );
              },
            ),
        ],
      ),
    );
  }
}

class RippleStripedPainter extends CustomPainter {
  final Offset center;
  final double radius;
  final double opacity;

  RippleStripedPainter({required this.center, required this.radius, required this.opacity});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2
      ..shader = LinearGradient(
        colors: [
          Colors.white.withOpacity(opacity),
          Colors.white.withOpacity(0),
        ],
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
      ).createShader(Rect.fromCircle(center: center, radius: radius));

    // 绘制8条交叉条纹波纹
    for (int i = 0; i < 8; i++) {
      final angle = (i * 45) * 3.1415 / 180;
      final startX = center.dx + radius * cos(angle);
      final startY = center.dy + radius * sin(angle);
      final endX = center.dx - radius * cos(angle);
      final endY = center.dy - radius * sin(angle);
      canvas.drawLine(Offset(startX, startY), Offset(endX, endY), paint);
    }
  }

  @override
  bool shouldRepaint(covariant RippleStripedPainter oldDelegate) {
    return oldDelegate.radius != radius || oldDelegate.opacity != opacity;
  }
}

使用该按钮的示例代码:

StripedButton(
  text: "点击测试",
  onTap: () {
    // 自定义点击逻辑
  },
)

你可以根据需求调整颜色、动画时长、条纹数量、波纹大小等参数,所有实现均基于Flutter原生API,无需额外插件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 22:15:29