Files
feature-next-arch/lib/features/remote_control/presentation/widgets/status_chip.dart
2026-01-21 13:27:55 +08:00

125 lines
3.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<StatusChip> createState() => _StatusChipState();
}
class _StatusChipState extends State<StatusChip>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _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<double>(
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,
),
),
],
),
),
);
},
);
}
}