import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; class StatusChip extends StatefulWidget { final String text; final Color color; final IconData? icon; final String? svgPath; final Color? svgColor; final bool breathing; final VoidCallback? onTap; const StatusChip({ super.key, required this.text, required this.color, this.icon, this.svgPath, this.svgColor, this.breathing = false, this.onTap, }) : assert(icon != null || svgPath != null, '必须提供 icon 或 svgPath 其中之一'); @override State createState() => _StatusChipState(); } class _StatusChipState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _opacityAnimation; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 1000), ); if (widget.breathing) _controller.repeat(reverse: true); // 动画区间从 0.3 到 1.0 _opacityAnimation = Tween( begin: 0.3, end: 1.0, ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut)); } @override void didUpdateWidget(StatusChip oldWidget) { super.didUpdateWidget(oldWidget); if (widget.breathing != oldWidget.breathing) { widget.breathing ? _controller.repeat(reverse: true) : _controller.stop(); } } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // 【关键】获取颜色传入时的透明度(比如你传了 0.6,baseOpacity 就是 0.6) final double baseOpacity = widget.color.opacity; return AnimatedBuilder( animation: _opacityAnimation, builder: (context, child) { // 【关键】如果不呼吸,直接用 baseOpacity,不再强制给 1.0 final currentAlpha = widget.breathing ? _opacityAnimation.value * baseOpacity : baseOpacity; return GestureDetector( onTap: widget.onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( // 这里应用计算后的透明度 color: widget.color.withOpacity(currentAlpha), borderRadius: BorderRadius.circular(12), border: Border.all( color: Colors.white.withOpacity(0.15), width: 0.5, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ if (widget.svgPath != null) SvgPicture.asset( widget.svgPath!, width: 14, height: 14, colorFilter: ColorFilter.mode( widget.svgColor ?? Colors.white, BlendMode.srcIn, ), ) else Icon( widget.icon, color: widget.svgColor ?? Colors.white, size: 14, ), const SizedBox(width: 5), Text( widget.text, style: const TextStyle( color: Colors.white, fontSize: 13, fontWeight: FontWeight.w600, ), ), ], ), ), ); }, ); } }